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 测量地址处数据的 size。如果你忘记了 *
并改为写入 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 字节
自己试一试 »
备注
在使用动态内存分配时,你还应该**检查错误**并在程序结束时**释放内存**。你将在下一章中学习更多关于此方面的知识。
堆栈内存
为了完整起见,有必要提到堆栈内存。堆栈内存是一种动态内存,它为在函数内部声明的变量保留。在函数内部声明的变量使用堆栈内存而不是静态内存。
当调用一个函数时,将为函数中的变量分配堆栈内存。当函数返回时,将释放堆栈内存。
了解堆栈内存有助于处理嵌套函数调用和递归的内存使用情况。重复次数过多的递归可能会占用过多的堆栈内存。当这种情况发生时,它被称为**堆栈溢出**。