在C语言中,内存管理是一个核心概念,因为C让程序员直接控制内存的分配和释放。以下是 malloc、calloc 和 free 的详细说明:
1. malloc - 内存分配
功能:
分配指定字节数的内存块,不初始化内存内容。
语法:
cpp
void* malloc(size_t size);
示例:
cpp
#include <stdio.h>
#include <stdlib.h>
int main() {
// 分配一个整数的内存
int *ptr = (int*)malloc(sizeof(int));
if (ptr == NULL) {
printf("内存分配失败\n");
return 1;
}
*ptr = 100;
printf("值: %d\n", *ptr);
free(ptr); // 释放内存
return 0;
}
2. calloc - 分配并初始化内存
功能:
分配指定数量和大小的内存块,并将所有位初始化为0。
语法:
cpp
void* calloc(size_t num, size_t size);
示例:
cpp
#include <stdio.h>
#include <stdlib.h>
int main() {
// 分配5个整数的数组,全部初始化为0
int *arr = (int*)calloc(5, sizeof(int));
if (arr == NULL) {
printf("内存分配失败\n");
return 1;
}
for(int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]); // 全部为0
}
free(arr);
return 0;
}
3. free - 释放内存
功能:
释放之前分配的内存块。
语法
cpp
void free(void* ptr);
重要规则:
-
只能释放通过
malloc、calloc或realloc分配的内存 -
不能重复释放同一块内存
-
释放后应将指针设为NULL
综合示例
cpp
#include <stdio.h>
#include <stdlib.h>
int main() {
int n, i;
printf("输入数组大小: ");
scanf("%d", &n);
// 使用malloc分配内存
int *arr1 = (int*)malloc(n * sizeof(int));
if(arr1 == NULL) {
printf("内存分配失败!\n");
return 1;
}
printf("malloc分配的内容(未初始化):\n");
for(i = 0; i < n; i++) {
printf("%d ", arr1[i]); // 可能是随机值
}
printf("\n");
// 使用calloc分配内存
int *arr2 = (int*)calloc(n, sizeof(int));
if(arr2 == NULL) {
printf("内存分配失败!\n");
free(arr1);
return 1;
}
printf("calloc分配的内容(初始化为0):\n");
for(i = 0; i < n; i++) {
printf("%d ", arr2[i]); // 全部为0
}
printf("\n");
// 重新分配内存 (realloc)
int *arr3 = (int*)realloc(arr2, 2 * n * sizeof(int));
if(arr3 == NULL) {
printf("内存重新分配失败!\n");
free(arr1);
free(arr2);
return 1;
}
printf("重新分配后的数组:\n");
for(i = 0; i < 2 * n; i++) {
printf("%d ", arr3[i]);
}
printf("\n");
// 释放所有内存
free(arr1);
free(arr3);
// 将指针设为NULL避免悬空指针
arr1 = NULL;
arr3 = NULL;
return 0;
}
最佳实践和注意事项
1. 总是检查返回值
cpp
int *ptr = (int*)malloc(sizeof(int));
if (ptr == NULL) {
// 处理分配失败的情况
}
2. 避免内存泄漏
cpp
// 错误示例
void leak_memory() {
int *ptr = (int*)malloc(100 * sizeof(int));
// 忘记调用 free(ptr)
}
// 正确示例
void no_leak() {
int *ptr = (int*)malloc(100 * sizeof(int));
if (ptr != NULL) {
// 使用内存
// ...
free(ptr); // 及时释放
ptr = NULL; // 避免悬空指针
}
}
3. 不要重复释放
cpp
int *ptr = (int*)malloc(sizeof(int));
free(ptr);
// free(ptr); // 错误!重复释放
4. 动态数组示例
cpp
#include <stdio.h>
#include <stdlib.h>
int main() {
int size;
printf("输入数组大小: ");
scanf("%d", &size);
// 动态分配数组
double *scores = (double*)malloc(size * sizeof(double));
if (scores == NULL) {
printf("内存分配失败\n");
return 1;
}
// 输入数据
for (int i = 0; i < size; i++) {
printf("输入分数 %d: ", i + 1);
scanf("%lf", &scores[i]);
}
// 计算平均值
double sum = 0;
for (int i = 0; i < size; i++) {
sum += scores[i];
}
printf("平均分: %.2f\n", sum / size);
free(scores);
return 0;
}
alloc vs calloc 对比
| 特性 | malloc | calloc |
|---|---|---|
| 初始化 | 不初始化 | 初始化为0 |
| 参数 | 一个参数(总字节数) | 两个参数(元素个数, 元素大小) |
| 性能 | 稍快 | 稍慢(因为要初始化) |
| 使用场景 | 需要手动初始化时 | 需要零初始化时 |
掌握这些内存管理函数对于编写高效、稳定的C程序至关重要。