Lưu ý quan trọng
C không có "Reference" (tham chiếu) như C++. Bài viết gốc nhầm lẫn khái niệm. Trong C chỉ có Con trỏ (Pointer) và Truyền tham chiếu bằng con trỏ.
Con trỏ (Pointer) trong C
Con trỏ là biến lưu trữ địa chỉ bộ nhớ của biến khác.
Khai báo
int *p; // Con trỏ tới int
float *fp; // Con trỏ tới float
char *cp; // Con trỏ tới char
Toán tử quan trọng
| Toán tử | Tên | Chức năng |
|---|---|---|
& | Address-of | Lấy địa chỉ biến |
* | Dereference | Truy cập giá trị tại địa chỉ |
Chương trình minh họa
#include <stdio.h>
int main() {
int a = 10, b = 20;
int *p; // Khai báo con trỏ int
printf("Dia chi a: %p\n", (void*)&a);
printf("Dia chi b: %p\n", (void*)&b);
// p trỏ đến a
p = &a;
printf("\np tro den a:\n");
printf("Gia tri a: %d\n", a);
printf("Gia tri *p: %d\n", *p); // Giá trị tại địa chỉ p
printf("Dia chi p (gia tri cua p): %p\n", (void*)p);
// p trỏ đến b
p = &b;
printf("\np tro den b:\n");
printf("Gia tri b: %d\n", b);
printf("Gia tri *p: %d\n", *p);
printf("Dia chi p: %p\n", (void*)p);
// Thay đổi giá trị qua con trỏ
*p = 99;
printf("\nSau khi *p = 99:\n");
printf("b = %d\n", b); // b đã thay thành 99
return 0;
}
Kết quả
Dia chi a: 0x7ffc1234
Dia chi b: 0x7ffc1238
p tro den a:
Gia tri a: 10
Gia tri *p: 10
Dia chi p: 0x7ffc1234
p tro den b:
Gia tri b: 20
Gia tri *p: 20
Dia chi p: 0x7ffc1238
Sau khi *p = 99:
b = 99
Truyền tham chiếu (Pass by Reference) trong C
C chỉ có Truyền giá trị (Pass by Value). Để mô phỏng truyền tham chiếu, ta truyền địa chỉ (con trỏ).
Truyền giá trị (Không thay đổi gốc)
void doiGiaTri(int x) {
x = 20; // Chỉ thay đổi bản sao
}
int main() {
int a = 10;
doiGiaTri(a);
printf("%d\n", a); // Vẫn là 10
}
Truyền địa chỉ (Thay đổi được gốc)
void doiGiaTri(int *x) {
*x = 20; // Thay đổi giá trị tại địa chỉ
}
int main() {
int a = 10;
doiGiaTri(&a); // Truyền địa chỉ
printf("%d\n", a); // Thành 20
}
So sánh Pointer vs Reference (C++)
| Đặc điểm | Pointer (C/C++) | Reference (Chỉ C++) |
|---|---|---|
| Cú pháp | int *p = &a; | int &r = a; |
| Có thể NULL | Có | Không (luôn tham chiếu hợp lệ) |
| Thay đổi đối tượng trỏ | Được (p = &b) | Không (gán một lần) |
| Truy cập giá trị | *p | r (tự động dereference) |
| Kích thước | 4/8 bytes | Cùng kích thước đối tượng |
Các loại con trỏ phổ biến
- Con trỏ NULL:
int *p = NULL;hoặcint *p = 0; - Con trỏ void:
void *vp;- trỏ đến bất kỳ kiểu nào - Con trỏ hằng:
const int *p(giá trị không đổi) vsint *const p(địa chỉ không đổi) - Con trỏ hàm:
int (*func)(int, int); - Con trỏ cấp 2:
int **pp;- trỏ đến con trỏ
Ứng dụng chính của con trỏ
- Cấp phát bộ nhớ động (
malloc,free) - Truyền mảng/hàm vào hàm
- Cấu trúc dữ liệu: linked list, tree, graph
- Thao tác chuỗi, file, phần cứng
- Tối ưu hiệu năng (tránh copy dữ liệu lớn)
Nắm vững con trỏ là chìa khóa thành thạo C. Hãy tập luyện nhiều với &, *, mảng-con trỏ, và cấp phát động.