C 内存管理示例
真实内存管理示例
为了演示一个实际的动态内存示例,我们创建了一个可以生成任意长度列表的程序。
C 语言中的常规数组长度固定且不可更改,但使用动态内存,我们可以创建任意长度的列表。
示例
struct list {
int *data; // 指向存储列表项的内存
int numItems; // 指示列表中当前有多少项
int size; // 指示已分配的内存可以容纳多少项
};
void addToList(struct list *myList, int item);
int main() {
struct list myList;
int amount;
// 创建一个列表,初始容量为 10 项
myList.numItems = 0;
myList.size = 10;
myList.data = malloc(myList.size * sizeof(int));
// 检查内存分配是否成功
if (myList.data == NULL) {
printf("内存分配失败");
return 1; // 以错误代码退出程序
}
// 将 amount 变量指定的任意数量的项添加到列表中
amount = 44;
for (int i = 0; i < amount; i++) {
addToList(&myList, i + 1);
}
// 显示列表内容
for (int j = 0; j < myList.numItems; j++) {
printf("%d ", myList.data[j]);
}
// 在不再需要时释放内存
free(myList.data);
myList.data = NULL;
return 0;
}
// 此函数向列表中添加一项
void addToList(struct list *myList, int item) {
// 如果列表已满,则重新分配内存以容纳另外 10 项
if (myList->numItems == myList->size) {
myList->size += 10;
myList->data = realloc( myList->data, myList->size * sizeof(int) );
}
// 将项添加到列表末尾
myList->data[myList->numItems] = item;
myList->numItems++;
}
自己动手试一试 »
指向结构的指针:此示例有一个指向结构 myList
的指针。因为我们使用的是指向结构的指针而不是结构本身,所以我们使用箭头语法 (->
) 来访问结构的成员。
示例说明
此示例包含三个部分:
- 一个包含列表数据的
myList
结构 main()
函数,其中包含程序代码。- 一个
addToList()
函数,用于向列表中添加一项
myList
结构
myList
结构包含列表的所有信息,包括其内容。它有三个成员:
data
- 指向包含列表内容的动态内存的指针numItems
- 指示列表中的项数size
- 指示已分配内存可以容纳多少项
我们使用结构是为了方便地将所有这些信息传递给函数。
main()
函数
main()
函数首先初始化列表,为其分配 10 个项的空间。
// 创建一个列表,初始容量为 10 项
myList.numItems = 0;
myList.size = 10;
myList.data = malloc(myList.size * sizeof(int));
myList.numItems
设置为 0,因为列表一开始是空的。
myList.size
用于跟踪已保留多少内存。我们将其设置为 10,因为我们将为 10 个项保留足够的内存。
然后我们分配内存,并将其指针存储在 myList.data
中。
接着,我们包含错误检查,以确定内存分配是否成功。
// 检查内存分配是否成功
if (myList.data == NULL) {
printf("内存分配失败");
return 1; // 以错误代码退出程序
}
如果一切正常,一个循环将使用 addToList()
函数将 44 个项添加到列表中。
// 将 amount 变量指定的任意数量的项添加到列表中
amount = 44;
for (int i = 0; i < amount; i++) {
addToList(&myList, i + 1);
}
在上面的代码中,&myList
是列表的指针,i + 1
是我们要添加到列表中的数字。我们选择 i + 1
是为了让列表从 1 开始而不是从 0 开始。您可以选择任何数字添加到列表中。
在所有项都添加到列表后,下一个循环将打印列表的内容。
// 显示列表内容
for (int j = 0; j < myList.numItems; j++) {
printf("%d ", myList.data[j]);
}
在打印完列表后,我们释放内存以防止内存泄漏。
// 在不再需要时释放内存
free(myList.data);
myList.data = NULL;
addToList()
函数
我们的 addToList()
函数将一个项添加到列表中。它接受两个参数:
void addToList(struct list *myList, int item)
- 指向列表的指针。
- 要添加到列表的值。
该函数首先通过比较列表中项的数量和列表的大小来检查列表是否已满。如果列表已满,则重新分配内存以容纳另外 10 项。
// 如果列表已满,则重新分配内存以容纳另外 10 项
if (myList->numItems == myList->size) {
myList->size += 10;
myList->data = realloc( myList->data, myList->size * sizeof(int) );
}
最后,该函数将项添加到列表末尾。myList->numItems
处的索引始终位于列表末尾,因为它在每次添加新项时会增加 1。
// 将项添加到列表末尾
myList->data[myList->numItems] = item;
myList->numItems++;
我们为什么一次预留 10 个项目?
优化是一个在内存和性能之间取得平衡的挑战。尽管我们可能会分配一些未使用但已分配的内存,但过于频繁地重新分配内存会效率低下。需要在分配过多内存和过于频繁分配内存之间找到平衡。
我们为这个示例选择了数字 10,但这取决于您预计有多少数据以及数据更改的频率。例如,如果我们事先知道我们将有正好 44 个项,那么我们可以分配正好 44 个项的内存,并且只分配一次。
完整的 stdlib 参考
有关内存管理函数和标准库中其他函数的完整参考,请访问我们的 C <stdlib.h> 库参考。