Ví dụ về quản lý bộ nhớ C
Ví dụ về quản lý bộ nhớ thực tế
Để minh họa một ví dụ thực tế về bộ nhớ động , chúng tôi đã tạo một chương trình có thể tạo một danh sách có độ dài bất kỳ.
Các mảng thông thường trong C có độ dài cố định và không thể thay đổi, nhưng với bộ nhớ động chúng ta có thể tạo danh sách bao lâu tùy thích:
Ví dụ
struct list {
int *data; // Points to the memory where the list items are
stored
int numItems; // Indicates how many items are currently in the list
int size; // Indicates how many items fit in the allocated memory
};
void addToList(struct list *myList, int item);
int main() {
struct list myList;
int amount;
// Create a list and start with
enough space for 10 items
myList.numItems = 0;
myList.size = 10;
myList.data = malloc(myList.size * sizeof(int));
// Find out if
memory allocation was successful
if (myList.data == NULL) {
printf("Memory allocation failed");
return 1; // Exit
the program with an error code
}
// Add any number of
items to the list specified by the amount variable
amount = 44;
for (int i = 0; i < amount; i++) {
addToList(&myList, i + 1);
}
//
Display the contents of the list
for (int j = 0; j < myList.numItems; j++) {
printf("%d ", myList.data[j]);
}
// Free the memory when it is no
longer needed
free(myList.data);
myList.data = NULL;
return 0;
}
// This function adds an item to a list
void addToList(struct list
*myList, int item) {
// If the list is full then resize the memory to
fit 10 more items
if (myList->numItems == myList->size) {
myList->size +=
10;
myList->data = realloc( myList->data, myList->size * sizeof(int) );
}
// Add the item to the end of the list
myList->data[myList->numItems] = item;
myList->numItems++;
}
Hãy tự mình thử » Con trỏ tới cấu trúc: Ví dụ này có một con trỏ tới cấu trúc myList
. Vì chúng ta đang sử dụng một con trỏ tới cấu trúc thay vì chính cấu trúc đó nên chúng ta sử dụng cú pháp mũi tên ( ->
) để truy cập các thành viên của cấu trúc.
Ví dụ giải thích
Ví dụ này có ba phần:
- Cấu trúc
myList
chứa dữ liệu của danh sách - Hàm
main()
có chương trình trong đó. - Hàm
addToList()
để thêm một mục vào danh sách
Cấu trúc myList
Cấu trúc myList
chứa tất cả thông tin về danh sách, bao gồm cả nội dung của nó. Nó có ba thành viên:
-
data
- Một con trỏ tới bộ nhớ động chứa nội dung của danh sách -
numItems
- Cho biết số lượng mục mà danh sách có -
size
- Cho biết có bao nhiêu mục có thể vừa trong bộ nhớ được phân bổ
Chúng tôi sử dụng một cấu trúc để có thể dễ dàng chuyển tất cả thông tin này vào một hàm.
Hàm main()
Hàm main()
bắt đầu bằng cách khởi tạo danh sách có khoảng trống cho 10 mục:
// Create a list and start with enough space for 10 items
myList.numItems =
0;
myList.size = 10;
myList.data = malloc(myList.size * sizeof(int));
myList.numItems
được đặt thành 0 vì danh sách bắt đầu trống.
myList.size
theo dõi lượng bộ nhớ được dành riêng. Chúng tôi đặt nó thành 10 vì chúng tôi sẽ dành đủ bộ nhớ cho 10 mục.
Sau đó, chúng tôi phân bổ bộ nhớ và lưu trữ một con trỏ tới nó trong myList.data
.
Sau đó, chúng tôi bao gồm việc kiểm tra lỗi để tìm hiểu xem việc cấp phát bộ nhớ có thành công hay không:
// Find out if memory allocation was successful
if (myList.data == NULL) {
printf("Memory allocation failed");
return 1; // Exit the program with an error code
}
Nếu mọi thứ đều ổn, một vòng lặp sẽ thêm 44 mục vào danh sách bằng hàm addToList()
:
// Add any number of items to the list specified by the amount variable
amount = 44;
for (int i = 0; i < amount; i++) {
addToList(&myList, i + 1);
}
Trong đoạn mã trên, &myList
là một con trỏ tới danh sách và i + 1
là số mà chúng ta muốn thêm vào danh sách. Chúng tôi đã chọn i + 1
để danh sách bắt đầu từ 1 thay vì 0. Bạn có thể chọn bất kỳ số nào để thêm vào danh sách.
Sau khi tất cả các mục đã được thêm vào danh sách, vòng lặp tiếp theo sẽ in nội dung của danh sách.
// Display the contents of the list
for (int j = 0; j < myList.numItems;
j++) {
printf("%d ", myList.data[j]);
}
Khi in xong danh sách, chúng tôi sẽ giải phóng bộ nhớ để tránh rò rỉ bộ nhớ.
// Free the memory when it is no longer needed
free(myList.data);
myList.data = NULL;
Hàm addToList()
Hàm addToList()
của chúng ta thêm một mục vào danh sách. Phải mất hai tham số:
void addToList(struct list *myList, int item)
- Một con trỏ tới danh sách.
- Giá trị được thêm vào danh sách.
Trước tiên, hàm này sẽ kiểm tra xem danh sách đã đầy hay chưa bằng cách so sánh số mục trong danh sách với kích thước của danh sách. Nếu danh sách đầy thì nó sẽ phân bổ lại bộ nhớ để chứa thêm 10 mục:
// If the list is full then resize the memory to fit 10 more items
if (myList->numItems == myList->size) {
myList->size += 10;
myList->data = realloc( myList->data, myList->size * sizeof(int) );
}
Cuối cùng, hàm thêm mục vào cuối danh sách. Chỉ mục tại myList->numItems
luôn ở cuối danh sách vì nó tăng thêm 1 mỗi khi có một mục mới được thêm vào.
// Add the item to the end of the list
myList->data[myList->numItems] =
item;
myList->numItems++;
Tại sao chúng tôi đặt trước 10 mặt hàng cùng một lúc?
Tối ưu hóa là hành động cân bằng giữa bộ nhớ và hiệu suất. Mặc dù chúng ta có thể đang cấp phát một số bộ nhớ mà chúng ta không sử dụng nhưng việc tái cấp phát bộ nhớ quá thường xuyên có thể không hiệu quả. Có sự cân bằng giữa việc cấp phát quá nhiều bộ nhớ và cấp phát bộ nhớ quá thường xuyên.
Chúng tôi đã chọn số 10 cho ví dụ này nhưng nó phụ thuộc vào lượng dữ liệu bạn mong đợi và tần suất thay đổi. Ví dụ: nếu chúng ta biết trước rằng chúng ta sẽ có chính xác 44 mục thì chúng ta có thể cấp phát bộ nhớ cho chính xác 44 mục và chỉ cấp phát một lần.