搜索
C 教程 / 分配内存

分配内存

静态内存

静态内存是指在程序运行之前为变量预留的内存。静态内存的分配也称为编译时内存分配(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 字节
运行实例 »

点击 "运行实例" 按钮查看在线实例

注意事项

在处理动态内存分配时,你还应该检查错误并在程序结束时释放内存。你将在接下来的章节中了解更多关于此内容的信息。

栈内存

为了完整性,值得一提的是栈内存。栈内存是一种为函数内部声明的变量预留的动态内存。函数内部声明的变量使用栈内存而不是静态内存。

当调用函数时,会为函数中的变量分配栈内存。当函数返回时,栈内存会被释放。

了解栈内存对于处理嵌套函数调用和递归的内存使用情况很有用。递归次数过多可能会占用太多的栈内存。当这种情况发生时,它被称为栈溢出