分配内存
静态内存
静态内存是指在程序运行之前为变量预留的内存。静态内存的分配也称为编译时内存分配(compile time memory allocation)。
在程序编译时,C 语言会自动为每个变量分配内存。
例如,如果你创建一个包含 20 个学生的整数数组,C 语言将为 20 个元素预留空间,这通常是 80 字节的内存(20 * 4):
实例
int students[20]; printf("%lu", sizeof(students)); // 80 字节运行实例 »
点击 "运行实例" 按钮查看在线实例
但是,当学期开始时,发现只有 12 名学生参加。那么,你就浪费了 8 个未使用元素的空间。
由于你无法更改数组的大小,因此你会留下不必要的预留内存。
请注意,程序仍然会运行,并且不会受到任何损坏。但是,如果你的程序中包含大量此类代码,它可能无法以最佳速度运行。
如果你想要更好地控制分配的内存,请查看下面的动态内存。
动态内存
动态内存是指在程序开始运行之后分配的内存。动态内存的分配也可以称为运行时内存分配(runtime memory allocation)。
与静态内存不同,你可以完全控制任何时候使用的内存量。你可以编写代码来确定你需要多少内存并进行分配。
动态内存不属于变量,只能通过指针访问。
要分配动态内存,你可以使用 malloc()
或 calloc()
函数。需要使用 <stdlib.h>
头文件才能使用它们。malloc()
和 calloc()
函数分配一些内存,并返回一个指向其地址的指针。
int *ptr1 = malloc(size); int *ptr2 = calloc(amount, size);
malloc()
函数有一个 size 参数,它指定要分配多少内存,以字节为单位。
calloc()
函数有两个参数:
- amount:指定要分配的项数
- size:指定每个项的大小,以字节为单位
注意:malloc()
分配的内存中的数据是不可预测的。为了避免意外的值,请确保在读取之前向内存中写入某些内容。
与 malloc()
不同,calloc()
函数会将分配的所有内存写入零。但是,这会使 calloc()
的效率略低。
为数据类型分配正确内存量的最佳方法是使用 sizeof
运算符:
int *ptr1, *ptr2; ptr1 = malloc(sizeof(*ptr1)); ptr2 = calloc(1, sizeof(*ptr2));
请注意:sizeof(ptr1)
告诉 C 语言测量地址处的数据大小。如果你忘记使用并写入 sizeof(ptr1)
,它将测量指针本身的大小,这通常是存储内存地址所需的 8 个字节。
注意:sizeof
运算符无法测量分配了多少动态内存。在测量动态内存时,它只会告诉你内存的数据类型的大小。例如,如果你为5个浮点值预留空间,sizeof
运算符将返回 4,这是单个浮点值所需的字节数。
让我们使用动态内存来改进上面的学生示例。
如前所述,我们无法使用 sizeof
来测量分配了多少内存,我们必须通过将项数乘以数据类型的大小来计算:
实例
int *students; int numStudents = 12; students = calloc(numStudents, sizeof(*students)); printf("%d", numStudents * sizeof(*students)); // 48 字节运行实例 »
点击 "运行实例" 按钮查看在线实例
注意事项
在处理动态内存分配时,你还应该检查错误并在程序结束时释放内存。你将在接下来的章节中了解更多关于此内容的信息。
栈内存
为了完整性,值得一提的是栈内存。栈内存是一种为函数内部声明的变量预留的动态内存。函数内部声明的变量使用栈内存而不是静态内存。
当调用函数时,会为函数中的变量分配栈内存。当函数返回时,栈内存会被释放。
了解栈内存对于处理嵌套函数调用和递归的内存使用情况很有用。递归次数过多可能会占用太多的栈内存。当这种情况发生时,它被称为栈溢出。