C 语言动态内存分鱁全解:malloc、calloc、realloc、free 实战指南
深入动态内存分配前,先理解 C 语言内存管理机制。
C 语言内存管理原理
基本类型变量声明时,编译器自动在 栈 上分配空间。例如 float 通常占 4 字节(平台相关)。可用 sizeof 验证:
#include <stdio.h>
int main() {
float x;
printf("The size of float is %d bytes", sizeof(x));
return 0;
}
输出:
The size of float is 4 bytes
指定大小的数组也在栈上连续分配,每元素占其类型大小:
#include <stdio.h>
int main() {
float arr[10];
printf("The size of the float array with 10 elements is %d", sizeof(arr));
return 0;
}
结果:
The size of the float array with 10 elements is 40
栈分配虽自动,但许多程序需要运行时才知大小的内存。这由 动态内存分配 解决,使用 堆 而非栈。
C 语言动态内存分配
动态分配手动请求/释放内存,用指针追踪堆上分配块。标准库提供四大函数:
- malloc() – 分配指定字节连续块,返回首字节指针
- calloc() – 分配元素数组、全零初始化、返回首元素指针
- realloc() – 调整已分配块大小,保留原内容
- free() – 释放已分配块归还堆
逐一详解。
malloc() 函数
malloc() 全称“memory allocation”。保留指定字节块并返回指针,通常强转为目标类型:
ptr = (cast_type *) malloc(byte_size);
示例:
#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* 15 个整数 */
if (ptr != NULL) {
*(ptr + 5) = 480; /* 第 6 个元素 */
printf("Value of the 6th integer is %d", *(ptr + 5));
}
}
输出:
Value of the 6th integer is 480
要点:
- 用
sizeof(*ptr)使代码对类型变更健壮 - 检查
NULL返回值以捕获分配失败 - 分配内存连续,可视为数组用指针算术访问
动态分配不限基本类型,结构体、字符数组均适用。
free() 函数
malloc()、calloc()、realloc() 分配的内存必须显式释放防泄漏。free() 完成此任务:
#include <stdio.h>
int main() {
int* ptr = malloc(10 * sizeof(*ptr));
if (ptr != NULL){
*(ptr + 2) = 50;
printf("Value of the 2nd integer is %d", *(ptr + 2));
}
free(ptr);
}
输出:
Value of the 2nd integer is 50
calloc() 函数
calloc() 分配多个等大块并将每字节置零,适合需零初始化的数组/结构体:
ptr = (cast_type *) calloc(n, size);
示例 – 等差数列求和:
#include <stdio.h>
int main() {
int i, *ptr, sum = 0;
ptr = calloc(10, sizeof(int));
if (ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
for (i = 0; i < 10; ++i) {
*(ptr + i) = i;
sum += *(ptr + i);
}
printf("Sum = %d", sum);
free(ptr);
return 0;
}
结果:
Sum = 45
calloc() vs malloc()
关键差异:
- 初始化:
calloc()零初始化;malloc()不初始化(垃圾值) - 用途:需零值数组/结构体选
calloc();无初始化需求选malloc()更简洁 - 性能:两者相近,但
calloc()因置零略慢
realloc() 函数
realloc() 调整现有分配大小并保留内容:
ptr = realloc(ptr, newsize);
示例 – 扩展字符串缓冲区:
#include <stdio.h>
int main () {
char *ptr = malloc(10);
strcpy(ptr, "Programming");
ptr = realloc(ptr, 20); // 扩容
strcat(ptr, " In 'C'");
printf("%s, Address = %u", ptr, ptr);
free(ptr);
return 0;
}
重分配失败时 realloc() 返回 NULL 且原块保持有效。
动态数组
动态数组允许元素数量运行时增长,算法与数据结构常用模式:
#include <stdio.h>
int main() {
int *arr_dynamic = NULL;
int elements = 2, i;
arr_dynamic = calloc(elements, sizeof(int));
for (i = 0; i < elements; i++) arr_dynamic[i] = i;
for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
elements = 4;
arr_dynamic = realloc(arr_dynamic, elements * sizeof(int));
printf("After realloc\n");
for (i = 2; i < elements; i++) arr_dynamic[i] = i;
for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
free(arr_dynamic);
}
结果:
arr_dynamic[0]=0 arr_dynamic[1]=1 After realloc arr_dynamic[0]=0 arr_dynamic[1]=1 arr_dynamic[2]=2 arr_dynamic[3]=3
总结
- 动态内存让你在运行时分配/释放堆空间
- 单块用
malloc(),零初始化数组用calloc() - 始终检查
NULL捕获分配失败 - 用
free()释放防泄漏 - 需更多空间时用
realloc()调整 - 动态数组是灵活数据结构的强大模式
C语言
- 理解 ROM、PROM、EPROM 与 EEPROM:设计、编程与识别
- C# 基础:输入输出核心技巧完全指南
- 掌握 C# using 指令:命名空间导入、别名与静态导入全解析
- C++ 动态内存管理:new 与 delete 专家级实战指南
- C 语言用户自定义函数四大模式对比:参数与返回值的设计权衡
- C语言动态内存分配完全指南:malloc、calloc、realloc 与 free
- 精通C标准库函数:实战指南
- C++ 动态数组分配实战指南:new/delete、初始化、扩容与内存管理
- C++ 函数详解:从声明到调用的实战指南
- C 语言函数详解:定义、声明、调用与参数传递
- C 语言动态内存管理:calloc、malloc 与 free 完全解析
- C++动态内存管理精要:栈与堆、new/delete、数组与对象分配实战