Con trỏ (tiếp)

Con trỏ và hằng số

Khai báo từ khóa const trước kiểu dữ liệu cho biết đó là khai báo con trỏ được trỏ đến giá trị không đổi.

1
2
const int* p = &x;
(*p) = y; // lỗi khi thay đổi dữ liệu con trỏ được trỏ tới

Khai báo từ khóa const sau kiểu dữ liệu và dấu * là khai báo con trỏ chỉ trỏ đến một địa chỉ duy nhất.

1
2
int* const p = &x;
p = &y; // lỗi khi thay đổi địa chỉ mà con trỏ p trỏ tới

Với khai báo con trỏ vừa không thay đổi giá trị nó trỏ tới và không thay đổi địa chỉ nó trỏ tới thì dùng tới hai từ khóa const.

1
2
3
const int* const p = &x;
(*p) = y; // lỗi
p = &y; // lỗi

Các lỗi với hằng số này được thông báo ngay lúc biên dịch chương trình.

Con trỏ NULL

Con trỏ NULL để khai báo con trỏ trỏ về giá trị NULL. Lý do phải khai báo như vậy là vì vấn đề an toàn của dữ liệu, con trỏ trong C có thể trỏ đến bất kỳ đâu trong chương trình. Ngoài ra nhiều hàm trong thư viện C (ví dụ như hàm strstr) trả về giá trị con trỏ NULL khi không tìm ra dữ liệu mong muốn.

1
2
3
int* p1; // khai báo con trỏ chưa được gán giá trị nào
int* p2 = NULL; // khai báo con trỏ trỏ đến giá trị null
int* p3 = (void*) 0; // khai báo con trỏ p3 trỏ đến giá trị null

Con trỏ void

Con trỏ void là con trỏ đặt biệt khi mà chúng ta không cần biết kiểu dữ liệu mà nó trỏ tới.
Vì không biết kiểu dữ liệu của con trỏ nên phải ép kiểu về dạng con trỏ được trỏ tới một kiểu dữ liệu nào đó mới có thể thao tác với dữ liệu được.

1
2
3
4
5
6
int a = 10;
void* p_void = &a; // khai báo con trỏ void
int* p_int;
p_int = (int*) p_void; // ép kiểu void* về int* rồi gán vào p_int
(*p_int)++; // tăng dữ liệu của con trỏ p_int lên 1
printf("%d\n", a); // -> 11

Con trỏ hàm

Con trỏ hàm là con trỏ trỏ tới một hàm số. Với con trỏ hàm, cần khai báo kiểu giá trị trả về và kiểu các tham số của hàm. Khi gán một hàm cho con trỏ hàm thì có thể sử dụng hoặc không sử dụng dấu &.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int add(int a, int b) {
  return a + b;
}
int main() {
  // khai báo và gán con trỏ hàm
  // có thể sử dụng &add thay cho add
  int (*func_pointer)(int, int) = add; 
  
  int sum_1_and_2 = func_pointer(1, 2);
  printf("%d", sum_1_and_2); // -> 3
}

Con trỏ hàm rất hay được sử dụng khi cần truyền hàm như một tham số vào hàm khác.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int add(int a, int b) {
  return a + b;
}
// khai báo hàm có tham số là con trỏ hàm
int operation (int x, int y, int (*functocall)(int, int)) {
  return (*functocall)(x, y);
}
int main() {
  int sum_1_and_2 = operation(1, 2, add);
  printf("%d", sum_1_and_2); // -> 3
}