6.1. Khái niệm về con trỏ và địa chỉ
- Con trỏ (Pointer) là một
kiểu dữ liệu đặc biệt dùng đê quản lý địa chỉ của các ô nhớ. Một con trỏ quản
lý các địa chỉ mà dữ liệu tại các địa chỉ này có kiểu T thì con trỏ đó được gọi
là con trỏ kiểu T.
- Con trỏ kiểu T chỉ được dùng để chứa địa chỉ của biến kiểu T. Nghĩa là con trỏ kiểu int chỉ được dùng để chứa biến kiểu int, con trỏ kiểu char chỉ được dùng chứa biến kiểu char.
Cú
pháp <tên kiểu dữ liệu> *<tên biến con trỏ>
Ví dụ 6.1:
// x là biến kiểu int, còn px là con trỏ kiểu int.
int x, *px;
px được khai báo là một con trỏ kiểu int, nó chứa
địa chỉ của biến kiểu dữ liệu số nguyên.
- Dấu * không phải là một phần của biến, int * có
nghĩa là con trỏ kiểu int.
- Đặt tên biến con trỏ giống như tên của các biến
khác.
6.3. Các thao tác trên con trỏ
6.3.1. Gán địa chỉ của biến cho con trỏ
Toán tử địa chỉ (&)
-
Biến được khai báo là a thì &a là địa chỉ của a.
-
Kết quả của phép lấy địa chỉ (&) là một con trỏ, do đó có thể dùng để gán
cho một biến pointer.
Ví dụ 6.2: Để
gán địa chỉ vào con trỏ chúng ta cần phải gán giá trị cho biến như sau:
int a =
10;
int *p;
p =
&a;// giá trị p chứa địa chỉ của biến
a
6.3.2. Nội dung của ô nhớ con trỏ chỉ tới
Toán tử nội dung (*)
Toán
tử lấy nội dung của một địa chỉ được kí hiệu là dấu * trước một pointer, dùng
để lấy giá trị của biến mà con trỏ đang trỏ đến.
Ví dụ 6.3:
int *p, a = 10 ;
p= &a ;
int k = *p + 3 ;
//giá
trị của *p (tức là a) cộng thêm 3, gán cho k. Sau câu lệnh trên k = 13
a. Cấp phát vùng nhớ cho biến con trỏ
Trước
khi sử dụng biến con trỏ, ta nên cấp phát vùng nhớ cho biến con trỏ này quản lý
địa chỉ. Việc cấp phát được thực hiện nhờ các hàm malloc(), trong
thư viện alloc.h.
Cú pháp:
void *malloc(size_t size): Cấp phát vùng nhớ có kích thước size.
void *calloc(size_t nitems, size_t size): Cấp phát vùng nhớ có kích thước là nitems*size.
Ví dụ 6.4:
Giả sử ta có khai báo:
int a, *pa, *pb;
pa =
(int*)malloc(sizeof(int)); /* Cấp phát vùng nhớ
có kích thước bằng với kích
thước của một số
nguyên */
pb= (int*)calloc(10,
sizeof(int)); /* Cấp phát vùng
nhớ có thể chứa được 10 số
nguyên*/
Hình ảnh minh họa trong bộ
nhớ như sau:
Lưu ý: Khi sử dụng hàm malloc() hay calloc(), ta phải ép kiểu
vì nguyên mẫu các hàm này trả về con trỏ kiểu void.
b. Cấp phát lại vùng nhớ cho biến con
trỏ
Trong
quá trình thao tác trên biến con trỏ, nếu ta cần cấp phát thêm vùng nhớ có kích
thước lớn hơn vùng nhớ đã cấp phát, ta sử dụng hàm realloc().
Cú pháp: void *realloc(void *block,
size_t size)
Ví dụ 6.5: Trong ví dụ trên ta có thể cấp phát lại vùng nhớ do
con trỏ pa quảnlý như sau:
int
a, *pa;
/*Cấp
phát vùng nhớ có kích thước 2 byte*/
pa=(int*)malloc(sizeof(int));
/*
Cấp phát lại vùng nhớ có kích thước 6 byte*/
pa
= realloc(pa, 6);
c. Giải phóng vùng nhớ cho biến con trỏ
Một
vùng nhớ đã cấp phát cho biến con trỏ, khi không còn sử dụng nữa, ta sẽ thu hồi
lại vùng nhớ này nhờ hàm free().
Cú pháp: void free(void *block)
Ví dụ 6.7: Xét lại ví dụ 6.4, sau khi thực hiện xong, ta giải
phóng vùng nhớ cho 2 biến con trỏ pa & pb:
free(pa);
free(pb);
Một biến pointer có thể được
cộng trừ với một số nguyên (int, long) để cho kết quả là một pointer chỉ đến
một vùng nhớ khác.
Ví dụ 6.8:
int *ptr, *p1;
int num = 10;
ptr = #
p1 = ptr + 2;
Việc cộng hoặc trừ pointer
với một số nguyên n thì pointer sẽ chỉ đến một địa chỉ mới hay nói cách khác là
chỉ đến một biến khác nằm cách biến đó n vị trí.
Sử dụng Con trỏ để
viết các chương trình sau:
Bài 1. Viết chương trình nhập vào mảng a
gồm n phần tử nhập từ bàn phím. Sau đó xuất ra màn hình mảng vừa nhập.
Bài 2. Viết chương trình sắp xếp một
mảng n phần tử theo thứ tự tăng dần.
Bài 3. Viết chương trình nhập vào một
mảng, hãy xuất ra màn hình:
- Phần tử lớn nhất của mảng.
- Phần tử nhỏ nhất của mảng.
- Tính tổng của các phần
tử trong mảng .