- 1 1. Giới thiệu
- 2 2. malloc là gì?
- 3 3. Cách sử dụng cơ bản của malloc
- 4 4. Tầm quan trọng của việc giải phóng bộ nhớ với free()
- 5 5. Tầm quan trọng của việc kiểm tra NULL
- 6 6. Sự khác biệt giữa malloc và calloc
- 7 7. Ví dụ thực tế: Cấp phát bộ nhớ động cho chuỗi bằng malloc
- 8 8. Sử dụng malloc với cấu trúc (struct)
- 9 9. Những lỗi thường gặp khi sử dụng malloc
- 10 10. Tổng kết
1. Giới thiệu
Khi bạn bắt đầu lập trình với ngôn ngữ C, bạn thường sẽ sử dụng mảng để thao tác với bộ nhớ. Tuy nhiên, khi chương trình trở nên phức tạp hơn, sẽ có những lúc bạn muốn quản lý bộ nhớ một cách linh hoạt hơn. Trong những tình huống như vậy, “cấp phát bộ nhớ động” sẽ trở nên rất hữu ích. malloc
là một trong những hàm tiêu biểu cho mục đích này, cho phép bạn cấp phát bộ nhớ cần thiết trong quá trình thực thi chương trình.
Ví dụ, bạn có thể tưởng tượng malloc
giống như “một món ăn được chuẩn bị sau khi gọi món”. Trong khi đó, bộ nhớ đã xác định trước như mảng có thể ví như “món ăn buffet”. Bạn chỉ cần “gọi món” đúng lượng mình cần thông qua malloc
, và sau khi dùng xong thì “dọn đĩa” bằng cách giải phóng bộ nhớ với hàm free
. Trong bài viết này, chúng ta sẽ cùng tìm hiểu chi tiết về malloc
.

2. malloc
là gì?
malloc
là viết tắt của “memory allocation” (phân bổ bộ nhớ), và là một hàm trong ngôn ngữ C dùng để cấp phát bộ nhớ động. Trong quá trình thực thi chương trình, nó sẽ cấp phát một vùng nhớ với kích thước được chỉ định và trả về địa chỉ đầu tiên của vùng nhớ đó. Nhờ đó, bạn có thể sử dụng lượng bộ nhớ cần thiết trong quá trình chương trình chạy, cho phép quản lý bộ nhớ linh hoạt hơn so với việc sử dụng mảng với kích thước cố định.
Trong mã nguồn thực tế, bạn có thể sử dụng malloc
như sau:
int *array = (int*)malloc(10 * sizeof(int));
Trong ví dụ này, bộ nhớ đủ để chứa 10 phần tử kiểu số nguyên được cấp phát. Một điểm quan trọng là malloc
trả về địa chỉ đầu tiên của vùng nhớ vừa cấp phát, và kiểu dữ liệu mặc định là void*
, vì vậy thường cần phải ép kiểu về đúng loại con trỏ cần dùng. Trong trường hợp trên, chúng ta ép kiểu về con trỏ số nguyên bằng cách dùng (int*)
.
3. Cách sử dụng cơ bản của malloc
Vậy thì, hãy cùng tìm hiểu chi tiết hơn về cách sử dụng malloc
. Cú pháp cơ bản của malloc
như sau:
void* malloc(size_t size);
Hàm malloc
nhận một đối số là kích thước bộ nhớ cần cấp phát (tính bằng byte). Sau đó, nó sẽ cấp phát một vùng nhớ với kích thước tương ứng và nếu thành công, sẽ trả về địa chỉ đầu tiên của vùng nhớ đó. Giá trị trả về có kiểu void*
, nghĩa là con trỏ tổng quát có thể ép kiểu thành bất kỳ kiểu dữ liệu nào. Ví dụ như sau:
int *array = (int*)malloc(10 * sizeof(int));
Ở đây, sizeof(int)
được dùng để tính kích thước chính xác của một phần tử kiểu số nguyên. Bằng cách này, bạn có thể đảm bảo cấp phát đúng kích thước bộ nhớ phù hợp với môi trường cụ thể. Sau khi sử dụng xong vùng nhớ đã cấp phát, điều quan trọng là phải giải phóng nó bằng hàm free
. Nếu không giải phóng, chương trình sẽ gặp vấn đề gọi là rò rỉ bộ nhớ (memory leak).

4. Tầm quan trọng của việc giải phóng bộ nhớ với free()
Việc cấp phát bộ nhớ động rất tiện lợi, tuy nhiên cũng có một điểm cần lưu ý. Đó là: bạn phải luôn nhớ giải phóng bộ nhớ đã cấp phát. Nếu bỏ qua điều này, chương trình sẽ bị rò rỉ bộ nhớ, dẫn đến việc sử dụng tài nguyên hệ thống một cách lãng phí.
Bộ nhớ được cấp phát bằng malloc
cần được giải phóng bằng free()
như ví dụ sau:
free(array);
Bộ nhớ không được giải phóng sẽ vẫn chiếm dụng tài nguyên hệ thống cho đến khi chương trình kết thúc. Đối với các chương trình chạy trong thời gian dài, điều này có thể trở thành một vấn đề nghiêm trọng. Có thể ví việc này giống như bạn mượn đĩa bằng malloc
, nếu bạn không trả lại bằng free
, thì nhà bếp sẽ bị chất đầy đĩa bẩn!
5. Tầm quan trọng của việc kiểm tra NULL
Hàm malloc
sẽ trả về NULL
nếu việc cấp phát bộ nhớ thất bại. Ví dụ như khi bạn cố gắng cấp phát một lượng bộ nhớ quá lớn mà hệ thống không thể cung cấp. Vì vậy, khi sử dụng malloc
, bạn nên luôn kiểm tra xem kết quả có phải là NULL
hay không để đảm bảo rằng bộ nhớ đã được cấp phát thành công.
int *array = (int*)malloc(100000000 * sizeof(int));
if (array == NULL) {
// Xử lý khi cấp phát bộ nhớ thất bại
printf("Memory allocation failed.\n");
return 1;
}
Bằng cách kiểm tra như trên, bạn có thể xử lý lỗi trong trường hợp việc cấp phát bộ nhớ thất bại. Thêm một biện pháp an toàn nhỏ trong đoạn mã sẽ giúp bạn tránh được những sự cố lớn về sau.

6. Sự khác biệt giữa malloc
và calloc
Trong ngôn ngữ C, ngoài malloc
còn có một hàm khác cũng dùng để cấp phát bộ nhớ động, đó là calloc
. Hai hàm này rất giống nhau, nhưng có một vài điểm khác biệt quan trọng. malloc
chỉ đơn giản là cấp phát một vùng nhớ với kích thước được chỉ định, nhưng nội dung trong vùng nhớ đó sẽ chưa được khởi tạo. Trong khi đó, calloc
không chỉ cấp phát bộ nhớ mà còn khởi tạo tất cả các phần tử trong vùng nhớ đó về giá trị 0.
Cách sử dụng calloc
int *array = (int*)calloc(10, sizeof(int));
Đoạn mã trên sẽ cấp phát bộ nhớ cho một mảng gồm 10 phần tử kiểu số nguyên và khởi tạo tất cả các phần tử này về 0. Sự khác biệt chính giữa malloc
và calloc
là calloc
nhận hai đối số: “số lượng phần tử” và “kích thước của mỗi phần tử”. Cú pháp này đặc biệt hữu ích khi làm việc với dữ liệu dạng mảng có nhiều phần tử.
Nên sử dụng hàm nào còn tùy thuộc vào tình huống. Nếu bạn cần khởi tạo giá trị ban đầu cho bộ nhớ, calloc
là lựa chọn phù hợp. Ngược lại, nếu không cần khởi tạo hoặc muốn tối ưu hiệu suất, malloc
sẽ tốt hơn.
7. Ví dụ thực tế: Cấp phát bộ nhớ động cho chuỗi bằng malloc
Trong phần này, chúng ta sẽ xem một ví dụ thực tế về việc sử dụng malloc
để cấp phát bộ nhớ động cho chuỗi. Khi xử lý chuỗi trong ngôn ngữ C, bạn thường sử dụng mảng có kích thước cố định. Tuy nhiên, nếu độ dài của chuỗi chỉ được xác định khi chương trình chạy, hoặc khi bạn muốn thao tác với chuỗi một cách linh hoạt, thì malloc
là công cụ rất hữu ích.
char *str = (char*)malloc(50 * sizeof(char));
if (str == NULL) {
printf("Memory allocation failed.\n");
return 1;
}
sprintf(str, "Hello, World!");
printf("%s\n", str);
free(str);
Trong đoạn mã này, chúng ta cấp phát bộ nhớ đủ để chứa 50 ký tự và lưu chuỗi “Hello, World!” vào vùng nhớ đó. Sau khi sử dụng xong, đừng quên giải phóng bộ nhớ bằng hàm free
. Bằng cách sử dụng malloc
, bạn có thể quản lý bộ nhớ một cách linh hoạt hơn, điều mà mảng có kích thước cố định không thể làm được.

8. Sử dụng malloc
với cấu trúc (struct)
Tiếp theo, chúng ta sẽ xem một ví dụ về cách sử dụng malloc
để cấp phát bộ nhớ động cho một cấu trúc (struct). Cấu trúc là kiểu dữ liệu mạnh mẽ cho phép bạn nhóm nhiều loại dữ liệu khác nhau lại với nhau, và việc quản lý bộ nhớ của chúng cũng có thể được thực hiện một cách linh hoạt bằng cách sử dụng cấp phát động.
typedef struct {
int id;
char *name;
} Person;
Person *p = (Person*)malloc(sizeof(Person));
if (p == NULL) {
printf("Memory allocation failed.\n");
return 1;
}
p->name = (char*)malloc(50 * sizeof(char));
sprintf(p->name, "John Doe");
p->id = 1;
printf("ID: %d, Name: %s\n", p->id, p->name);
free(p->name);
free(p);
Trong đoạn mã trên, chúng ta sử dụng malloc
để cấp phát bộ nhớ cho một cấu trúc có tên là Person
, và tiếp tục cấp phát bộ nhớ cho thành phần name
bên trong cấu trúc đó. Bằng cách này, bạn có thể linh hoạt quản lý bộ nhớ cho từng thành phần trong cấu trúc tùy theo nhu cầu sử dụng.
9. Những lỗi thường gặp khi sử dụng malloc
Hãy cùng đề cập đến những lỗi mà người mới học thường mắc phải khi sử dụng malloc
. Việc tránh được những lỗi này sẽ giúp bạn viết chương trình an toàn và hiệu quả hơn.
- Quên giải phóng bộ nhớ
Nếu bạn không sử dụngfree()
để giải phóng bộ nhớ đã được cấp phát động, sẽ xảy ra hiện tượng rò rỉ bộ nhớ (memory leak). Điều này đặc biệt nghiêm trọng đối với các chương trình chạy lâu dài. Hãy tạo thói quen luôn giải phóng vùng nhớ đã cấp phát, bất kể chương trình có phức tạp đến đâu. - Bỏ qua kiểm tra
NULL
Nhiều người quên rằngmalloc
có thể trả vềNULL
nếu cấp phát bộ nhớ thất bại. Sau mỗi lần sử dụngmalloc
, bạn nên kiểm traNULL
và xử lý lỗi một cách phù hợp. - Truy cập vào bộ nhớ chưa được khởi tạo
Bộ nhớ được cấp phát bởimalloc
chưa được khởi tạo. Nếu bạn sử dụng ngay mà không khởi tạo, có thể gây ra hành vi không mong muốn. Trong trường hợp cần khởi tạo giá trị ban đầu, hãy cân nhắc sử dụngcalloc
.

10. Tổng kết
malloc
là một công cụ mạnh mẽ trong ngôn ngữ lập trình C, không thể thiếu khi cần cấp phát bộ nhớ động. Tuy nhiên, để sử dụng hiệu quả, bạn cần hiểu rõ cơ chế hoạt động của nó và quản lý bộ nhớ một cách hợp lý. Từ cách sử dụng cơ bản đến các ví dụ ứng dụng với cấu trúc và chuỗi, bạn hãy vận dụng vào thực tế để nâng cao kỹ năng lập trình. Lần tới khi viết chương trình, đừng quên “gọi món” bộ nhớ bằng malloc
, và sau khi dùng xong hãy “trả lại đĩa” bằng free
nhé!
FAQ
- Phải làm gì khi
malloc
không cấp phát được bộ nhớ?
Nếumalloc
thất bại, nó sẽ trả vềNULL
. Vì vậy, bạn nên luôn kiểm traNULL
và xử lý lỗi một cách thích hợp. - Nên sử dụng
malloc
haycalloc
?
Nếu bạn không cần khởi tạo bộ nhớ, hãy dùngmalloc
. Nếu bạn muốn khởi tạo tất cả các giá trị về 0, hãy dùngcalloc
.