Explore all courses in this category.
Explore all courses in this category.
Nguyễn Đình Cường
0 comment
09 Nov, 2026
Con trỏ là chủ đề khiến nhiều người mới học C phát hoảng, nhưng khái niệm cốt lõi rất đơn giản: con trỏ là một biến lưu địa chỉ của biến khác. Hiểu nó giúp bạn nắm được bộ nhớ hoạt động ra sao.
Hãy hình dung bộ nhớ như một dãy dài các ô, mỗi ô có số thứ tự gọi là địa chỉ. Khi bạn khai báo int x = 5;, máy cấp một vài ô để chứa giá trị 5 và biến x là tên gắn với vùng đó. Có hai thứ liên quan đến x: giá trị (5) và địa chỉ (ô nằm ở đâu).
&x: lấy địa chỉ của biến x.*p: truy cập giá trị tại địa chỉ mà con trỏ p đang giữ (gọi là giải tham chiếu).#include <stdio.h>
int main(void) {
int x = 5;
int *p = &x; // p lưu địa chỉ của x
printf("x = %d\n", x);
printf("*p = %d\n", *p); // 5
*p = 10; // sửa x thông qua p
printf("x sau khi sua = %d\n", x); // 10
return 0;
}Dấu * xuất hiện ở hai ngữ cảnh: khi khai báo (int *p) nghĩa là "p là con trỏ tới int", còn khi dùng (*p) nghĩa là "giá trị tại địa chỉ p trỏ tới".
C truyền tham số theo giá trị, tức hàm nhận một bản sao. Muốn hàm thay đổi biến gốc, ta truyền địa chỉ của nó:
#include <stdio.h>
void hoan_doi(int *a, int *b) {
int tam = *a;
*a = *b;
*b = tam;
}
int main(void) {
int x = 1, y = 2;
hoan_doi(&x, &y);
printf("%d %d\n", x, y); // 2 1
return 0;
}Tên mảng gần như là con trỏ đến phần tử đầu tiên. Do đó a[i] tương đương *(a + i):
int a[3] = {10, 20, 30};
int *p = a;
printf("%d\n", *(p + 1)); // 20
printf("%d\n", p[2]); // 30Cộng một số vào con trỏ nghĩa là nhảy đúng bấy nhiêu phần tử của kiểu đó, chứ không phải bấy nhiêu byte.
Khi chưa biết trước cần bao nhiêu phần tử, ta xin bộ nhớ lúc chương trình chạy bằng malloc và phải trả lại bằng free:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n = 3;
int *ds = malloc(n * sizeof(int));
if (ds == NULL) {
return 1; // xin bộ nhớ thất bại
}
for (int i = 0; i < n; i++) {
ds[i] = (i + 1) * 10;
}
printf("%d\n", ds[2]); // 30
free(ds);
return 0;
}NULL nếu chưa có địa chỉ.*p khi p là NULL làm chương trình sập.malloc mà quên free.free.Các công cụ như trình gỡ lỗi và các bộ kiểm tra bộ nhớ giúp phát hiện những lỗi này khi bạn thực hành.
printf("%p", (void*)&x) để quan sát.Hãy làm theo thứ tự tăng dần độ khó, vừa làm vừa vẽ sơ đồ bộ nhớ:
void tang_doi(int *x) nhân đôi giá trị của biến được truyền vào.malloc, nhập n số, tính tổng, rồi giải phóng.#include <stdio.h>
void dao_mang(int *dau, int n) {
int *cuoi = dau + n - 1;
while (dau < cuoi) {
int tam = *dau;
*dau = *cuoi;
*cuoi = tam;
dau++;
cuoi--;
}
}
int main(void) {
int a[5] = {1, 2, 3, 4, 5};
dao_mang(a, 5);
for (int i = 0; i < 5; i++) printf("%d ", a[i]); // 5 4 3 2 1
printf("
");
return 0;
}Bài đảo mảng cho thấy hai con trỏ cùng thuộc một mảng có thể so sánh với nhau và di chuyển bằng ++, --. Khi đã thạo, bạn chuyển sang danh sách liên kết, nơi con trỏ là trung tâm của mọi thứ.
Con trỏ là biến chứa địa chỉ, & lấy địa chỉ, * lấy giá trị tại địa chỉ. Nắm vững ba ý này cùng nguyên tắc "xin bộ nhớ thì phải trả", bạn đã vượt qua phần khó nhất của C và sẵn sàng viết các cấu trúc dữ liệu như danh sách liên kết hay cây.
Nếu cần một lộ trình rõ ràng thay vì tự mò mẫm, codebem.com có nhiều khóa học phù hợp cho người mới.
Nguyễn Đình Cường
0 comment