Chương 07
CON TRỎ
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
1
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 tốn
Con trỏ và mảng
Cấp phát bộ nhớ động
Trần Quang
© 2016
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
Chương 06: Con trỏ
Kỹ thuật lập trình
2
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
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
3
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
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
4
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 tồn cục
Biến tĩnh (static)
Hằng chuỗi
(Nguồn: />Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
5
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: /> />Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
6
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
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
7
Ứ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í
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ỏ
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
8
Ứ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:
Trần Quang
© 2016
Sử dụng danh sách liên kết dùng con trỏ
Chương 06: Con trỏ
Kỹ thuật lập trình
9
Mơ hình của con trỏ
Biến a có địa chỉ là
0x1234 FFFF
0x1234 FFFF
Biến p là con trỏ
chứa địa chỉ của biến a
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
10
Tố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);
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
11
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);
In ra địa chỉ của p1
printf("%p\n", &p1);
In ra giá trị của p1.x
printf("%p\n", &p1.x);
In ra địa chỉ của p1.y
printf("%p\n", &p1.y);
In ra địa chỉ của p1.z
printf("%p\n", &p1.z);
}
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
12
Khai báo con trỏ
<Tên kiểu> *<tên biến>;
<Tên kiểu> *<tên biến> = 0;
//NULL
<Tên kiểu> *<tên biến> = &<tên biến b>;
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
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
13
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);
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
14
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: ==, !=
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
15
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);
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
16
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
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
17
Con trỏ và mảng
Ví dụ:
Gán mảng vào con trỏ
a và p giữ cùng địa chỉ là địa
int a[5];
chỉ phần tử đầu tiên của mảng
int *p = a;
printf ("a =%p\n", a);
printf ("p =%p\n", p);
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
18
Con trỏ và mảng
Con trỏ và mảng có cùng cách truy cập các ơ nhớ
Dùng tốn tử [ ]
Dùng tốn tử * và +
int a[5];
int *p = a;
int id = 2;
a[id] = 100;
p[id] = 100;
Giống nhau
*(a + id) = 100;
*(p + id) = 100;
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
19
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
Trần Quang
© 2016
Chương 06: Con trỏ
Kỹ thuật lập trình
20