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> 库参考。