Nếu bạn đã từng code C một thời gian (hoặc mới hôm qua 😅), có thể bạn đã gặp một tình huống… "tình là tình nhiều khi không mà có, tình là tình nhiều lúc có như không":
Code nhìn hoàn toàn hợp lý, rất hợp lý, rất ổn!
Nếu chỉ chạy Compile sẽ thấy không lỗi. Rõ ràng là không có vấn đề gì!
Nhưng nếu bấm Run…
👉 Và… đùng! bạn gặp lỗi segmentation fault
Bạn ngồi nhìn màn hình, tự hỏi:
"Ủa mình sai ở đâu vậy trời???"...Bám Run lại...Vũ Như Cẩn, vẫn gặp lỗi!
👉 90% khả năng: bạn vừa hội ngộ với một "em" tên là "con trỏ NULL".
Con trỏ NULL là gì?
Nói đơn giản, dễ hiểu, không màu mè:
Con trỏ NULL là con trỏ không trỏ đến đâu cả
Trong C:
int *p = NULL;
👉 Nghĩa là:
p tồn tại
Nhưng nó không trỏ tới bất kỳ vùng nhớ hợp lệ nào
Ví dụ đời thường (cho dễ nhớ)
Bạn tưởng tượng:
Con trỏ = địa chỉ nhà
NULL = “không có địa chỉ”
👉 Bạn đang cầm một tờ giấy ghi:
“Nhà của tôi ở… (để trống)”
Và bạn vẫn cố:
gửi thư
giao hàng
đến thăm
👉 Kết quả: ...chẳng có kết quả nào cả!
Lỗi kinh điển (ai cũng từng dính)
int *p = NULL;
*p = 10; // 💥 crash
👉 Bạn đang ghi dữ liệu vào… “hư không”
Hệ điều hành nhìn thấy và nói:
“Không được phép!”
→ crash ngay lập tức
Vì sao con trỏ NULL nguy hiểm?
Vì nó trông có vẻ hợp lệ, và nó gật gù cho qua nếu bạn dịch code.
Code compile OK
Không warning
Nhìn bằng mắt thường cũng thấy “có vẻ đúng”
👉 Nhưng runtime thì… 💀
Code nhìn hoàn toàn hợp lý, rất hợp lý, rất ổn!
Nếu chỉ chạy Compile sẽ thấy không lỗi. Rõ ràng là không có vấn đề gì!
Nhưng nếu bấm Run…
👉 Và… đùng! bạn gặp lỗi segmentation fault
Bạn ngồi nhìn màn hình, tự hỏi:
"Ủa mình sai ở đâu vậy trời???"...Bám Run lại...Vũ Như Cẩn, vẫn gặp lỗi!
👉 90% khả năng: bạn vừa hội ngộ với một "em" tên là "con trỏ NULL".
Con trỏ NULL là gì?
Nói đơn giản, dễ hiểu, không màu mè:
Con trỏ NULL là con trỏ không trỏ đến đâu cả
Trong C:
int *p = NULL;
👉 Nghĩa là:
p tồn tại
Nhưng nó không trỏ tới bất kỳ vùng nhớ hợp lệ nào
Ví dụ đời thường (cho dễ nhớ)
Bạn tưởng tượng:
Con trỏ = địa chỉ nhà
NULL = “không có địa chỉ”
👉 Bạn đang cầm một tờ giấy ghi:
“Nhà của tôi ở… (để trống)”
Và bạn vẫn cố:
gửi thư
giao hàng
đến thăm
👉 Kết quả: ...chẳng có kết quả nào cả!
Lỗi kinh điển (ai cũng từng dính)
int *p = NULL;
*p = 10; // 💥 crash
👉 Bạn đang ghi dữ liệu vào… “hư không”
Hệ điều hành nhìn thấy và nói:
“Không được phép!”
→ crash ngay lập tức
Vì sao con trỏ NULL nguy hiểm?
Vì nó trông có vẻ hợp lệ, và nó gật gù cho qua nếu bạn dịch code.
Code compile OK
Không warning
Nhìn bằng mắt thường cũng thấy “có vẻ đúng”
👉 Nhưng runtime thì… 💀
5 tình huống phổ biến gây ra NULL pointer
❌ 1. Quên cấp phát bộ nhớ
int *p;
*p = 5; // crash
👉 p chưa trỏ tới đâu cả
❌ 2. malloc thất bại (ít gặp nhưng rất nguy hiểm)
int *p = malloc(sizeof(int));
if (p == NULL) {
// hết bộ nhớ
}
👉 Nếu bạn không check → rất dễ crash
❌ 3. Hàm trả về NULL nhưng không kiểm tra
int *getData() {
return NULL;
}
int *p = getData();
*p = 10; // crash
👉 Tin tưởng mù quáng là một cái giá đắt 😅
❌ 4. Sau khi free mà quên set NULL
int *p = malloc(sizeof(int));
free(p);
*p = 10; // 💥
👉 Đây gọi là “dangling pointer” (không hẳn NULL nhưng nguy hiểm tương tự)
👉 Best practice:
free(p);
p = NULL;
❌ 5. Truyền pointer sai giữa các hàm
👉 Đây là kiểu lỗi “cao cấp hơn một chút” nhưng rất hay gặp khi code lớn
Cách tránh NULL pointer (đơn giản nhưng hiệu quả)
✅ 1. Luôn kiểm tra trước khi dùng
if (p != NULL) {
*p = 10;
}
✅ 2. Sau khi free → set NULL
free(p);
p = NULL;
👉 Tránh “xài lại đồ cũ”
✅ 3. Khi dùng malloc → luôn check
int *p = malloc(sizeof(int));
if (p == NULL) {
printf("Hết bộ nhớ rồi!\n");
}
Để hiểu rõ hơn, bạn nên thử chạy code và "mục sở thị"
Bạn copy đoạn này vào:
👉 Online C Compiler
#include <stdio.h>
int main() {
int *p = NULL;
printf("Trước khi crash\n");
*p = 10; // crash
printf("Sau khi crash\n");
return 0;
}
👉 Kết quả:
Chỉ in ra đoạn Text: “Trước khi crash”
Và tiếp theo là Program finished with exit code 139
Điều đó có nghĩa là đoạn code "*p = 10; " đã "có vấn đề"
Sửa lại đoạn code như sau:
#include <stdio.h>
int main() {
int *p = NULL;
printf("Trước khi crash\n");
printf("p = %p\n", p);
*p = 10; // crash
printf("Sau khi crash\n");
return 0;
}
👉 Nếu thấy:
p = (nil)
👉 Bingo — Bạn đã tìn ra lỗi NULL pointer
Một sự thật hơi “đắng”
👉 Rất nhiều bug khó chịu trong C đến từ:
pointer
NULL
memory
👉 Nếu bạn thấy rối:
Bạn không cô đơn 😅
Tổng kết
Con trỏ NULL không phải là “lỗi khó”
👉 Nó chỉ là một cái bẫy rất dễ dính
Chỉ cần nhớ:
NULL = không trỏ đi đâu
Dùng NULL = crash
Luôn kiểm tra trước khi dùng
❓ NULL pointer có luôn gây segmentation fault không?
→ Gần như luôn luôn nếu bạn dereference (*p)
❓ Làm sao biết pointer có NULL không?
→ In ra hoặc check if (p == NULL)
❓ Có nên tránh dùng pointer không?
→ Không. Nhưng phải dùng cẩn thận 😅
👉 Bạn có thể cũng đang gặp:
Segmentation fault trong C là gì?
Memory leak nguy hiểm thế nào?
Stack vs Heap khác nhau ra sao?
(👉 sẽ có trong các bài tiếp theo)
Không có nhận xét nào:
Đăng nhận xét