Thứ Ba, 31 tháng 3, 2026

Con trỏ NULL trong C – kẻ giết người thầm lặng mà ai cũng từng dính

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 đẹp" 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ả. Quá xá là đơn giản phải không?!

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 

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ả! Hư không...!

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ớ:
  1. NULL = không trỏ đi đâu
  2. Dùng NULL = crash
  3. Luôn kiểm tra trước khi dùng

FAQ

❓ 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 😅