C 内存分配
保留内存的过程称为分配。分配内存的方式取决于内存的类型。
C 语言有两种内存类型:静态内存和动态内存。
静态内存
静态内存是在程序运行**前**为变量保留的内存。静态内存分配也称为*编译时*内存分配。
当程序编译时,C 语言会自动为每个变量分配内存。
例如,如果您创建一个包含 20 名学生(例如用于暑期学期)的整数数组,C 语言将为 20 个元素保留空间,通常是 80 字节的内存(20 * 4)。
但是当学期开始时,发现只有 12 名学生入学。那么您就浪费了 8 个未使用元素的空间。
由于您无法更改数组的大小,因此您将留下不必要的保留内存。
请注意,程序仍将运行,并且不会以任何方式损坏。但是,如果您的程序包含大量此类代码,它可能比最佳状态运行得慢。
如果您希望更好地控制已分配的内存,请查看下面的动态内存。
动态内存
动态内存是在程序开始运行**后**分配的内存。动态内存分配也可以称为*运行时*内存分配。
与静态内存不同,您可以完全控制在任何时候使用了多少内存。您可以编写代码来确定您需要多少内存并进行分配。
动态内存不属于变量,它只能通过指针访问。
要分配动态内存,可以使用 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 个 float
值保留空间,sizeof
运算符将返回 4,这是一个 float
值所需的字节数。
让我们使用动态内存来改进上面的学生示例。
如前所述,我们不能使用 sizeof
来测量分配了多少内存,我们必须通过将项目数量乘以数据类型的大小来计算。
示例
int *students;
int numStudents = 12;
students = calloc(numStudents, sizeof(*students));
printf("%d", numStudents * sizeof(*students)); // 48 字节
自己动手试一试 »
注意
在使用动态内存分配时,您还应该**检查错误**并在程序结束时**释放内存**。您将在下一章中了解更多信息。
栈内存
为了完整起见,值得一提的是栈内存。栈内存是一种动态内存,它为函数内部声明的变量保留。在函数内部声明的变量使用栈内存而不是静态内存。
当函数被调用时,会为函数中的变量分配栈内存。当函数返回时,栈内存被释放。
了解栈内存对于处理嵌套函数调用和递归的内存使用很有帮助。重复次数过多的递归可能会占用过多的栈内存。当这种情况发生时,称为**栈溢出**。