Bài 1 · Nâng cao · 24 phút· Cập nhật 11/06/2026
Con trỏ & địa chỉ
Biên soạn bởi Nguyễn Anh Tuấn
Con trỏ (pointer) trong C: mọi biến có một địa chỉ trong RAM; & lấy địa chỉ, * (dereference) truy cập giá trị - học với mô phỏng RAM trực quan.
Bộ nhớ (RAM) là một dãy ô, mỗi ô có một địa chỉ (như số nhà). Khi bạn viết int x = 5;, máy dành một ô ở một địa chỉ nào đó và đặt 5 vào. Toán tử & (address-of) cho ta địa chỉ ấy:
- ▸Mỗi biến có HAI thứ: một giá trị, và một địa chỉ nơi nó được lưu.
- ▸&x đọc là “địa chỉ của x” - một con số (thường in dạng hex 0x…).
- ▸Địa chỉ thực đổi mỗi lần chạy; điều quan trọng là KHÁI NIỆM, không phải con số cụ thể.
Trung thực: đây là mô hình dạy học
Chuẩn C của khoá: C17
Con trỏ là biến lưu địa chỉ của biến khác. int *px = &x; tạo con trỏ px và cho nó giữ địa chỉ của x - ta nói “px trỏ tới x”. Bấm Bước tiếp để xem từng câu lệnh tác động lên bộ nhớ; để ý mũi tên px → x:
- ▸Khai báo: kiểu *tên; vd int *px; (px trỏ tới một int).
- ▸px = &x; cho px giữ địa chỉ của x → mũi tên px trỏ sang x.
- ▸Giá trị của con trỏ chính là một địa chỉ (xem cột Giá trị: 0x100).
Có địa chỉ rồi, dùng *px (dereference) để đi tới ô đó và làm việc với giá trị. Đây mới là chỗ con trỏ phát huy tác dụng: *px = 99; ghi trực tiếp vào x dù ta không hề nhắc tên x:
deref.c
#include <stdio.h>
int main() {
int x = 5;
int *px = &x; // px tro toi x
printf("%d\n", *px); // doc qua con tro -> 5
*px = 99; // ghi qua con tro -> doi x
printf("%d\n", x); // x da thanh 99!
return 0;
} Kết quả khi chạy
5 99
- ▸*px ở VẾ PHẢI: đọc giá trị tại ô px trỏ tới.
- ▸*px ở VẾ TRÁI: ghi giá trị vào ô px trỏ tới.
- ▸*(&x) chính là x - & và * là hai phép ngược nhau.
Một con trỏ phải trỏ tới đâu đó hợp lệ trước khi dereference. Hai tình huống nguy hiểm: con trỏ NULL (cố ý “rỗng”) và con trỏ chưa khởi tạo (chứa địa chỉ rác):
null.c
#include <stdio.h>
int main() {
int *p = NULL; // ro rang: chua tro vao dau
if (p == NULL) {
printf("p chua tro vao dau\n");
}
// *p = 5; <- neu bo dau // se SAP (segfault)
int *q; // con tro HOANG: dia chi rac
// *q = 7; <- ghi vao vung nho bat ky -> nguy hiem
return 0;
} Kết quả khi chạy
p chua tro vao dau
Quy tắc vàng
Người mới học con trỏ hay lẫn lộn ba thứ sau - phân biệt rõ là qua được nửa chặng đường:
- ▸px ≠ *px: px là ĐỊA CHỈ (số nhà); *px là GIÁ TRỊ trong căn nhà đó.
- ▸& (lấy địa chỉ) ngược với * (truy cập giá trị) - đừng dùng nhầm.
- ▸int *px, y; → px là con trỏ, y CHỈ là int (dấu * gắn với px thôi).
- ▸Gán px = x (thiếu &) là sai kiểu: px cần một địa chỉ, không phải giá trị.
Mẹo đọc khai báo
Câu hỏi thường gặp
Là một biến đặc biệt lưu ĐỊA CHỈ của một biến khác, thay vì lưu giá trị trực tiếp. Nói “px trỏ tới x” nghĩa là px chứa địa chỉ ô nhớ của x. Từ địa chỉ đó, ta đọc/ghi được chính x.
& (address-of) lấy ĐỊA CHỈ của một biến: &x. * (dereference) đi tới địa chỉ và truy cập GIÁ TRỊ ở đó: *px. Chúng ngược nhau - *(&x) chính là x. Lưu ý * còn dùng khi KHAI BÁO con trỏ (int *px), nghĩa khác với * khi dùng (dereference).
Gắn với BIẾN. int *px, y; thì px là con trỏ-tới-int, còn y chỉ là int thường. Muốn hai con trỏ phải viết int *a, *b;. Nhiều người viết int* px cho dễ đọc, nhưng cái bẫy ở trên vẫn đúng.
Để (1) hàm sửa được biến của nơi gọi (truyền địa chỉ - bài sau); (2) cấp phát bộ nhớ động (malloc); (3) xây cấu trúc liên kết (danh sách, cây); (4) truyền dữ liệu lớn mà không sao chép. Con trỏ là cánh cửa vào phần bản chất của C.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Trong int x = 5; int *px = &x; thì giá trị lưu trong px là gì?
- 1
px có đổi không?
Dùng mô phỏng ở Bước 2, tới bước “
*px = 99;”. Giá trị lưu trongpxcó thay đổi không? Cònx?Hoàn thành khi:
pxKHÔNG đổi (vẫn giữ địa chỉ0x100củax); chỉ ôxđổi thành 99.*px = 99ghi vào ôpxtrỏ tới. - 2
Lấy giá trị qua con trỏ
Cho
int a = 7; int *pa = &a;thì*pabằng bao nhiêu?Hoàn thành khi: 7 -
*pađi tới địa chỉpalưu (=&a) và đọc giá trị ở đó, chính làa. - 3
Sửa qua con trỏ
Tiếp bài trên, chạy
*pa = 20;rồi ina.abằng bao nhiêu?Hoàn thành khi: 20 - ghi qua con trỏ đổi luôn biến gốc
a. - 4
Con trỏ rỗng
Viết khai báo một con trỏ
intchưa trỏ vào đâu một cách an toàn.Hoàn thành khi:
int *p = NULL;- rồi kiểm traif (p != NULL)trước khi dùng*p. - 5
px so với *px
Cho
int *px = &x;vớix = 42.printf("%p")chopxin ra gì, cònprintf("%d", *px)in ra gì (về ý nghĩa)?Hoàn thành khi:
pxin ra một ĐỊA CHỈ (vd0x...);*pxin ra GIÁ TRỊ tại địa chỉ đó = 42. - 6
Vì sao con trỏ 8 byte?
Con trỏ
intchiếm 8 byte (trên 64-bit) dùintchỉ 4 byte. Vì sao?Hoàn thành khi: Con trỏ lưu một ĐỊA CHỈ bộ nhớ (rộng 8 byte trên hệ 64-bit), không phụ thuộc kích thước biến nó trỏ tới. Trên các nền tảng thông dụng, mọi con trỏ dữ liệu đều cùng kích thước.