Ứng dụng của con trỏ
Mảng trong C
Phải biết trước số lượng phần tử tại thời điểm viết
chương trình
Do đó, cần phải khai báo một số lượng lớn các ô
nhớ để sẵn. Tuy nhiên, tại một thời điểm nào đó,
chương trình có thể sẽ sử dụng ít hơn rất nhiều
lãng phí
Yêu cầu: có thể nào dùng mảng với số lượng phần
tử chỉ cần biết lúc chương trình đang chạy?
=> Dùng con trỏ
28 trang |
Chia sẻ: thanhle95 | Lượt xem: 640 | Lượt tải: 1
Bạn đang xem trước 20 trang tài liệu Bài giảng Kỹ thuật lập trình - Chương 7: Con trỏ - Trần Quang, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Trần Quang
© 2016
Kỹ thuật lập trình
1
Chương 06: Con trỏ
Chương 07
CON TRỎ
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
2
Chương 06: Con trỏ
Nội dung
Tổ chức bộ nhớ
Ứng dụng của con trỏ
Mô hình của con trỏ
Toán tử &
Khai báo trỏ
Toán tử *
Các phép toán
Con trỏ và mảng
Cấp phát bộ nhớ động
Con trỏ và cấu trúc,
toán tử ->
Các chủ đề nâng cao
với con trỏ
Thứ tự đánh giá *
và ++, --
Con trỏ và const
Con trỏ đến con trỏ
Con trỏ void
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
3
Chương 06: Con trỏ
Tổ chức bộ nhớ thực thi
Tổ chức bộ nhớ
khi chương
trình nạp vào để
thực thi
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
4
Chương 06: Con trỏ
Tổ chức bộ nhớ thực thi
Vùng TEXT
Chứa mã thực thi của
chương trình
Vùng này chỉ đọc
Có thể dùng chung
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
5
Chương 06: Con trỏ
Tổ chức bộ nhớ thực thi
Vùng DATA
Dữ liệu đã được khởi
tạo (initialized)
Dữ liệu không được
khởi tạo (uninitialzed)
gồm:
Biến toàn cục
Biến tĩnh (static)
Hằng chuỗi
(Nguồn:
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
6
Chương 06: Con trỏ
Tổ chức bộ nhớ thực thi
Vùng HEAP
Chứa bộ nhớ xin
cấp phát động bởi
người lập trình
Liên quan đến kiểu
dữ liệu con trỏ trong
chương này
(Nguồn: programming.org/)
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
7
Chương 06: Con trỏ
Tổ chức bộ nhớ thực thi
Vùng STACK
Chứa các biến
khai báo trong
chương trình
Thông tin các
lần gọi hàm
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
8
Chương 06: Con trỏ
Ứng dụng của con trỏ
Mảng trong C
Phải biết trước số lượng phần tử tại thời điểm viết
chương trình
Do đó, cần phải khai báo một số lượng lớn các ô
nhớ để sẵn. Tuy nhiên, tại một thời điểm nào đó,
chương trình có thể sẽ sử dụng ít hơn rất nhiều
lãng phí
Yêu cầu: có thể nào dùng mảng với số lượng phần
tử chỉ cần biết lúc chương trình đang chạy?
=> Dùng con trỏ
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
9
Chương 06: Con trỏ
Ứng dụng của con trỏ
Mảng trong C
Khi thêm vào và xóa các phần tử trên mảng, cần
phải dịch phải và trái nhiều phần tử tốn nhiều
thời gian
Yêu cầu: Có cách tổ chức dữ liệu nào giúp các
phép quản lý phần tử nói trên nhanh chóng
Giải pháp:
Sử dụng danh sách liên kết dùng con trỏ
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
10
Chương 06: Con trỏ
Mô hình của con trỏ
0x1234 FFFF
Biến p là con trỏ
chứa địa chỉ của biến a
Biến a có địa chỉ là
0x1234 FFFF
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
11
Chương 06: Con trỏ
Toán tử &
Dùng để lấy địa chỉ của một biến
Ví dụ:
int a = 100;
printf("%d\n", a);
printf("%p\n", &a);
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
12
Chương 06: Con trỏ
Toán tử &
typedef struct sPoint3D{float x, y, z;} Point3D;
void main(){
Point3D p1 = {1.0f, 2.0f, 3.0f};
printf("%-5.1f\n", p1.x);
printf("%p\n", &p1);
printf("%p\n", &p1.x);
printf("%p\n", &p1.y);
printf("%p\n", &p1.z);
}
In ra giá trị của p1.x
In ra địa chỉ của p1
In ra địa chỉ của p1.y
In ra địa chỉ của p1.z
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
13
Chương 06: Con trỏ
Khai báo con trỏ
*;
* = 0; //NULL
* = &;
Ví dụ:
int a; // biến số nguyên
int *p1; // con trỏ đến số nguyên, giá trị chưa xác định
int *p2 = 0; // con trỏ đến số nguyên, giá trị là NULL
int *p3 = &a; // con trỏ đến số nguyên, giá trị là địa chỉ
của biến a
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
14
Chương 06: Con trỏ
Toán tử *
Toán tử * lấy giá trị (tham khảo) tại một địa chỉ
Ví dụ:
int a = 100;
int *p;
p = &a;
printf("a : %d\n", a);
printf("&a : %p\n", &a);
printf("p : %p\n", p);
printf("*p : %d\n", *p);
printf("*&a: %d\n", *&a);
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
15
Chương 06: Con trỏ
Các phép toán trên con trỏ
Tăng, giảm: ++, --
Cộng, trừ: +, -
Cộng, trừ kết hợp gán: +=, -=
So sánh: ==, !=
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
16
Chương 06: Con trỏ
Các phép toán trên con trỏ
Gọi p là con trỏ có kiểu T;
Các phép cộng, trừ: làm con trỏ p tăng hay giảm
một bội số của kích thước kiểu T
Ví dụ:
int a = 100;
int *p = &a;
printf("p : %p\n", p);
p++;
printf("p : %p\n", p);
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
17
Chương 06: Con trỏ
Con trỏ và mảng
Con trỏ và mảng có nhiều điểm giống nhau. Cả 2
đều giữ địa chỉ của ô nhớ
Con trỏ: giữ địa chỉ của một ô nhớ nào đó
Mảng: giữ địa chỉ của phần tử đầu tiên
Do đó:
Có thể gán mảng vào con trỏ
Nhưng không thể gán con trỏ vào mảng
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
18
Chương 06: Con trỏ
Con trỏ và mảng
Ví dụ:
int a[5];
int *p = a;
printf ("a =%p\n", a);
printf ("p =%p\n", p);
Gán mảng vào con trỏ
a và p giữ cùng địa chỉ là địa
chỉ phần tử đầu tiên của mảng
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
19
Chương 06: Con trỏ
Con trỏ và mảng
Con trỏ và mảng có cùng cách truy cập các ô nhớ
Dùng toán tử [ ]
Dùng toán tử * và +
int a[5];
int *p = a;
int id = 2;
a[id] = 100;
p[id] = 100;
*(a + id) = 100;
*(p + id) = 100;
Giống nhau
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
20
Chương 06: Con trỏ
Con trỏ và mảng
Con trỏ và mảng cũng có điểm khác nhau:
Mảng: các phần tử của mảng nằm trên STACK
Con trỏ: Các phần tử mảng con trỏ chỉ đến có thể
trên STACK hay HEAP
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
21
Chương 06: Con trỏ
Cấp phát bộ nhớ động
Giúp người lập trình tạo ra mảng động, không cần
xác định số lượng phần tử của mảng động tại thời
điểm biên dịch như mảng tĩnh
Mảng động sẽ được cấp phát trên HEAP
Vùng nhớ xin cấp phát không tự động giải phóng,
nên CẦN ra lệnh giải phóng vùng nhớ sau khi
dùng xong
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
22
Chương 06: Con trỏ
Cấp phát bộ nhớ động
Hàm xin cấp phát bộ nhớ
malloc
calloc
realloc
Hàm giải phóng bộ nhớ
free
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
23
Chương 06: Con trỏ
Cấp phát bộ nhớ động
p1 = (int*) malloc (num * sizeof(int));
num: số lượng phần tử xin cấp phát
sizeof(int): kích thước của mỗi phần tử.
num*sizeof(int): số bytes cần thiết để xin
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
24
Chương 06: Con trỏ
Cấp phát bộ nhớ động
int *p1;
float *p2;
int n = 100;
p1 = (int*) malloc (n * sizeof(int));
p2 = (float*) malloc (n * sizeof(float));
free(p1); free(p2);
xin cấp phát bộ nhớ
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
25
Chương 06: Con trỏ
Cấp phát bộ nhớ động
malloc
int *p1 = (int*)malloc(num*sizeof(int));
if(p1 == NULL){ ...} else { ...}
Hàm malloc trả về NULL nếu không xin được.
Lúc đó, không thể dùng bộ nhớ được!
Do đó, LUÔN LUÔN kiểm tra xem malloc có trả về NULL hay không
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
26
Chương 06: Con trỏ
Cấp phát bộ nhớ động
Hàm malloc trả về NULL nếu không cấp phát được
vùng nhớ. Do đó, nên kiểm tra bằng lệnh if trước
khi xử lý tiếp.
Ví dụ:
int n = 100;
int *p1 = (int*) malloc (n * sizeof(int));
if (p1 == NULL) {
printf ("Khong cap phat duoc!\n"); exit(1);
} else {
// Tiếp tục xử lý
free(p1);
}
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
27
Chương 06: Con trỏ
Con trỏ và cấu trúc
typedef struct{
float x, y, z;
} Point3D;
Point3D *p_ptr = (Point3D*)malloc(sizeof(Point3D));
// (4) Sử dụng
free(p_ptr);
(1) Định nghĩa kiểu cấu trúc: Point3D
(2) Khai báo con trỏ đến một mảng
(3) Xin cấp phát bộ nhớ trên HEAP,
p_ptr: giữ địa chỉ của ô nhớ đầu tiên trong
vùng được cấp(5) Giải phóng vùng nhớ
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Trần Quang
© 2016
Kỹ thuật lập trình
28
Chương 06: Con trỏ
Con trỏ và cấu trúc
(*p_ptr).x = 4.5f; (*p_ptr).y = 5.5f; (*p_ptr).z = 6.5f;
p_ptr->x = 7.5f; p_ptr->y = 8.5f; p_ptr->z = 9.5f;
Truy cập biến thành viên cấu trúc qua con trỏ
p_ptr : biến con trỏ chứa địa chỉ của một cấu trúc Point3D
(*p_ptr) : Vùng nhớ của cấu trúc Point3D
(*p_ptr).x : Vùng nhớ chứa biến x của cấu trúc Point3D
p_ptr -> x : Vùng nhớ chứa biến x của cấu trúc Point3D,
truy cập thông qua toán tử -> từ con trỏ p_ptr
CuuDuongThanCong.com https://fb.com/tailieudientucntt