1. 4/14/2017 Cấp phát bộ nhớ động
https://www.laptrinh101.com/lap-trinh-c/cap-phat-bo-nho-dong/ 1/11
Cấp phát bộ nhớ động
Trong bài này, bạn sẽ học được cách cấp phát bộ nhớ động trong lập trình C
sử dụng các hàm của thư viện chuẩn <stdlib.h>.
Con trỏ là một công cụ hữu dụng, mạnh mẽ và linh hoạt mà bạn sẽ dùng
nhiều và rất nhiều lần để giải quyết các bài toán trong lập trình. Cũng
tương tự như vậy, cấp phát bộ nhớ động sẽ không thể khả thi nếu không
có sự hỗ trợ của con trỏ.
Hàm malloc()
malloc() (memory allocation) là hàm đơn giản nhất được sử dụng để cấp
phát bộ nhớ ở thời điểm runtime. Khi bạn sử dụng hàm malloc() để cấp
phát bộ nhớ, bạn cần phải xác định rõ số byte của bộ nhớ cần cấp phát
trong đối số của hàm. Hàm này sẽ trả về địa chỉ byte đầu tiên của vùng bộ
nhớ được cấp phát nếu cấp phát thành công, hoặc trả về NULL nếu cấp
phát thất bại. Ví dụ sau mô tả cách cấp phát động 100 byte bộ nhớ với kiểu
int:
int *pointer = (int *) malloc(100);
Nếu được cấp phát thành công, 100 byte bộ nhớ này sẽ nằm trên vùng
heap. Vùng nhớ mới được cấp phát này có thể lưu trữ được tối đa 100/4 =
25 số nguyên (kiểu int 4 byte) hoặc tối đa 100/2 = 50 số nguyên (kiểu int
2. 4/14/2017 Cấp phát bộ nhớ động
https://www.laptrinh101.com/lap-trinh-c/cap-phat-bo-nho-dong/ 2/11
2 byte). Để tránh khác biệt về kích thước kiểu dữ liệu (ví dụ, kiểu int có thể
là 2 hoặc 4 byte tùy thuộc vào kiến trúc và OS), bạn có thể sử dụng cách
sau:
int *pointer = (int *) malloc(25 * sizeof(int));
Vì hàm malloc() sẽ trả về một con trỏ có kiểu void. Con trỏ có kiểu void
có thể ép được sang bất kỳ kiểu dữ liệu nào. Do đó, (int *) trong ví dụ
trên được dùng để ép sang kiểu int. Mặc dù, hiện tại có nhiều trình biên
dịch sẽ tự động ép con trỏ kiểu void trả về bởi hàm malloc() sang một
kiểu thích hợp. Tuy nhiên, bạn nên ép sang một kiểu cố định cho chắc chắn.
Hàm calloc()
Cũng như hàm malloc(), hàm calloc (contiguous allocation) được dùng
để cấp phát bộ nhớ động. Tuy nhiên, vùng nhớ được cấp phát bởi hàm
calloc() sẽ được set về 0 toàn bộ. Thông thường, hàm calloc() sẽ
chậm hơn hàm malloc().
Khi gọi hàm calloc(), bạn cần cung cấp 2 đối số; một là, số phần tử trong
mảng; hai là, kích thước của mỗi phần tử. Ví dụ bạn cấp phát bộ nhớ cho
một mảng số nguyên gồm 25 phần tử:
int *pointer = (int *) calloc(25, sizeof(int));
Kết quả trả về tương tự hàm malloc().
Hàm free()
3. 4/14/2017 Cấp phát bộ nhớ động
https://www.laptrinh101.com/lap-trinh-c/cap-phat-bo-nho-dong/ 3/11
Khác với các biến cục bộ và đối số của một hàm nằm trên vùng nhớ stack
(sẽ được tự động giải phóng ngay sau khi ra khỏi phạm vi của hàm đó),
vùng nhớ được cấp phát động nằm trên vùng heap sẽ không được giải
phóng. Bạn phải tự chịu trách nhiệm cho vùng nhớ mà mình đã cấp phát.
Nếu không giải phóng, chương trình của bạn có thể bị memory leak (tạm
dịch, rò rĩ bộ nhớ). Bạn có thể dùng Valgrind để kiểm tra lỗi này.
Để giải phóng vùng nhớ được cấp phát bởi malloc() và calloc(), bạn chỉ
cần gọi hàm free() với đối số là con trỏ đến phần tử đầu tiên trong vùng
nhớ mà bạn đã cấp phát. Nếu bạn gọi hàm free() không có đối số, hàm
này sẽ không làm gì cả. Ví dụ, để xóa vùng nhớ đã cấp phát, bạn chỉ cần
gọi:
free(pointer);
Chú ý: bạn không được xóa một vùng nhớ đã cấp phát 2 lần.
Hàm realloc()
Hàm realloc() (re-allocation) cho phép bạn sử dụng lại vùng nhớ mà bạn
đã cấp phát trước đó bởi hàm malloc() và calloc(). Hàm realloc()
nhận 2 đối số; một là, con trỏ trả về bởi malloc() hoặc calloc(); hai là,
số byte cần cấp phát lại. Thông thường, bạn sẽ sử dụng hàm realloc() để
cấp phát lại trên chính vùng nhớ đã cấp phát trước đó do vùng nhớ cấp
phát trước đó không đủ hoặc quá lớn. Ví dụ cấp phát lại vùng nhớ chứa tối
đa 20 số nguyên:
pointer = (int *) realloc(pointer, 25 * sizeof (int));
4. 4/14/2017 Cấp phát bộ nhớ động
https://www.laptrinh101.com/lap-trinh-c/cap-phat-bo-nho-dong/ 4/11
Chương trình ví dụ minh họa
Chương trình #1
Xuất ra các phần tử số nguyên đã nhập từ bàn phím, cấp phát động sử
dụng hàm malloc():
5. 4/14/2017 Cấp phát bộ nhớ động
https://www.laptrinh101.com/lap-trinh-c/cap-phat-bo-nho-dong/ 5/11
#include <stdio.h>
#include <stdlib.h>
int main()
{
int elems = 0;
int *pointer = NULL;
printf("Enter number of elements: ");
scanf("%d", &elems);
// cap phat bo nho
pointer = (int *) malloc(elems * sizeof(int));
// kiem tra cap phat thanh cong
if (!pointer)
{
printf("Error!");
exit(1);
}
for (int i = 0; i < elems; i++)
{
printf("Enter element %d: ", i + 1);
scanf("%d", pointer + i);
}
printf("Entered array: [");
for (int i = 0; i < elems; i++)
{
printf((i == elems - 1) ? "%d]n" : "%d ", *(pointer + i))
6. 4/14/2017 Cấp phát bộ nhớ động
https://www.laptrinh101.com/lap-trinh-c/cap-phat-bo-nho-dong/ 6/11
}
free(pointer); // giai phong bo nho
return 0;
}
Khi biên dịch và chạy, bạn có thể nhận được kết quả tương tự như sau:
Enter number of elements: 5
Enter element 1: 1
Enter element 2: 2
Enter element 3: 6
Enter element 4: 7
Enter element 5: 4
Entered array: [1 2 6 7 4]
Chương trình #2
Giống hoàn toàn chương trình trên, ngoại trừ cấp phát động sử dụng hàm
calloc():
7. 4/14/2017 Cấp phát bộ nhớ động
https://www.laptrinh101.com/lap-trinh-c/cap-phat-bo-nho-dong/ 7/11
#include <stdio.h>
#include <stdlib.h>
int main()
{
int elems = 0;
int *pointer = NULL;
printf("Enter number of elements: ");
scanf("%d", &elems);
// cap phat bo nho
pointer = (int *) calloc(elems, sizeof(int));
// kiem tra cap phat thanh cong
if (!pointer)
{
printf("Error!");
exit(1);
}
for (int i = 0; i < elems; i++)
{
printf("Enter element %d: ", i + 1);
scanf("%d", pointer + i);
}
printf("Entered array: [");
for (int i = 0; i < elems; i++)
{
printf((i == elems - 1) ? "%d]n" : "%d ", *(pointer + i))
8. 4/14/2017 Cấp phát bộ nhớ động
https://www.laptrinh101.com/lap-trinh-c/cap-phat-bo-nho-dong/ 8/11
}
free(pointer); // giai phong bo nho
return 0;
}
Kết quả xuất ra giống với chương trình #1.
Chương trình #3
Chương trình minh họa cách sử dụng hàm realloc():
9. 4/14/2017 Cấp phát bộ nhớ động
https://www.laptrinh101.com/lap-trinh-c/cap-phat-bo-nho-dong/ 9/11
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *str;
// cap phat bo nho
if (!(str = (char *) calloc(10, sizeof(char))))
{
printf("Error while allocating memory!n");
exit(1);
}
strcpy(str, "laptrinh");
printf("Old string: %sn", str);
// tai cap phat bo nho
if (!(str = (char *) realloc(str, 15)))
{
printf("Error while re-allocating memory!n");
exit(1);
}
strcat(str, "101");
printf("New string: %sn", str);
free(str);
return(0);
}
10. 4/14/2017 Cấp phát bộ nhớ động
https://www.laptrinh101.com/lap-trinh-c/cap-phat-bo-nho-dong/ 10/11
Bài trước (https://www.laptrinh101.com/lap-trinh-c/con-tro-pointer/)
Bài sau (https://www.laptrinh101.com/lap-trinh-c/ham/)
Sau khi biên dịch và chạy, sẽ được kết quả sau:
Old string: laptrinh
New string: laptrinh101
Danh sách bài học (https://www.laptrinh101.com/lap-trinh-c/)
Cập nhật lần cuối vào 14-04-2017 16:21.
11. 4/14/2017 Cấp phát bộ nhớ động
https://www.laptrinh101.com/lap-trinh-c/cap-phat-bo-nho-dong/ 11/11