写C语言程序时,经常会遇到数组大小不确定的情况。比如你正在开发一个小型数据库工具,用户可能一次性导入几百条数据,也可能导入几万条。如果用固定大小的数组,要么浪费内存,要么不够用。这时候就得靠“堆”来解决。
什么是堆?
程序运行时,内存大致分为栈和堆两块区域。局部变量存在栈里,由系统自动管理。而堆不一样,它是一块可以手动申请和释放的内存空间。C语言里通过 malloc、calloc、realloc 和 free 这几个函数来操作堆内存。
怎么在堆上分配内存?
最常用的函数是 malloc。比如你要处理一个用户动态输入长度的整数数组,可以这样写:
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
printf("请输入元素个数:");
scanf("%d", &n);
// 在堆上分配 n 个整数的空间
int *arr = (int*)malloc(n * sizeof(int));
if (arr == NULL) {
printf("内存分配失败!\n");
return 1;
}
// 使用这块内存
for (int i = 0; i < n; i++) {
arr[i] = i * i;
}
// 用完后记得释放
free(arr);
arr = NULL; // 避免野指针
return 0;
}
malloc 和 calloc 有啥区别?
malloc 分配内存但不初始化,里面可能是乱码。而 calloc 会自动把内存清零,适合需要干净初始值的场景。比如构建一个计数用的数组:
int *count = (int*)calloc(256, sizeof(int));
// 所有元素初始为0,适合统计字符频次这类任务
数据变多了怎么办?
有时候一开始估不准需要多少内存。比如你在往数据库缓存中加载记录,边读边扩展空间。这时可以用 realloc 动态调整大小:
int *data = malloc(10 * sizeof(int));
// 假设已经用了10个
// 现在要扩展到20个
data = (int*)realloc(data, 20 * sizeof(int));
if (data == NULL) {
printf("重新分配失败\n");
return 1;
}
别忘了释放,不然会出问题
堆上的内存不会自动回收。如果你在循环里反复申请内存却不释放,程序跑着跑着就会变慢甚至崩溃。这就像租房不退房,房东迟早没房可租。所以每次 malloc 或 calloc 后,一定要配对使用 free。
尤其是在处理数据库连接、批量数据导入导出这类长期运行的任务时,漏掉 free 可能让系统内存被一点点吃光。
实际应用场景举例
假设你写了个程序读取 CSV 文件导入到内存中做分析。文件行数未知,你可以先分配一小块堆空间存放指针数组,每读一行就用 malloc 给该行数据开空间,最后统一释放。这种方式灵活又高效。
堆用好了,程序就变得“能屈能伸”。但也要小心使用,避免内存泄漏、重复释放或访问已释放的内存。