C语言动态内存分配完全指南:malloc、calloc、realloc 与 free
C语言动态内存分配完全指南
本指南通过清晰示例和最佳实践,讲解使用标准库函数 malloc()、calloc()、realloc() 和 free() 进行动态内存分配。
为何使用动态分配?
静态数组在编译时固定大小,可能导致空间浪费或运行时容量不足。动态分配允许程序运行时按需申请内存。
四个函数均定义在 <stdlib.h> 中,提供受控的堆内存管理方式。
malloc() – 分配字节块
malloc 代表 "memory allocation"。它预留指定字节数的连续内存块,返回 void * 类型指针,可转换为任意指针类型。
语法
ptr = malloc(size_in_bytes); // 按需转换类型
示例
float *ptr = malloc(100 * sizeof(float)); // 大多数系统上 400 字节
ptr 指向 400 字节块的首字节。请求失败时 malloc 返回 NULL。建议在 C 中避免不必要的强制转换;赋值给类型指针时编译器可推断类型。
calloc() – 分配并零初始化
calloc 即 "contiguous allocation"。与 malloc 不同,它将分配块每位初始化为零,适合数值类型和指针。
语法
ptr = calloc(num_elements, size_of_each_element);
示例
float *ptr = calloc(25, sizeof(float)); // 25 个零初始化的 float 元素
分配失败时返回 NULL。
free() – 释放已分配内存
用 malloc 或 calloc 获得的内存持久存在,直到显式释放。free() 释放块并将内存返还堆供复用。
语法
free(ptr);
对 NULL 指针调用 free 是安全的,无操作。
示例 1:使用 malloc() 和 free()
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n, i, *ptr, sum = 0;
printf("输入元素个数: ");
scanf("%d", &n);
ptr = malloc(n * sizeof(int));
if (!ptr) {
fprintf(stderr, "错误: 内存分配失败。\n");
return EXIT_FAILURE;
}
printf("输入元素: ");
for (i = 0; i < n; ++i) {
scanf("%d", ptr + i);
sum += *(ptr + i);
}
printf("Sum = %d\n", sum);
free(ptr);
return EXIT_SUCCESS;
}
输出
输入元素个数: 3
输入元素: 100 20 36
Sum = 156
示例 2:使用 calloc() 和 free()
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n, i, *ptr, sum = 0;
printf("输入元素个数: ");
scanf("%d", &n);
ptr = calloc(n, sizeof(int));
if (!ptr) {
fprintf(stderr, "错误: 内存分配失败。\n");
return EXIT_FAILURE;
}
printf("输入元素: ");
for (i = 0; i < n; ++i) {
scanf("%d", ptr + i);
sum += *(ptr + i);
}
printf("Sum = %d\n", sum);
free(ptr);
return EXIT_SUCCESS;
}
输出
输入元素个数: 3
输入元素: 100 20 36
Sum = 156
realloc() – 调整现有分配大小
若发现当前分配过小或过大,realloc() 可在保留现有数据(不超过新大小)的前提下调整大小。
语法
ptr = realloc(ptr, new_size_in_bytes);
返回重分配块的指针,失败返回 NULL。为防内存泄漏,先用临时指针保存结果。
示例 3:使用 realloc()
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *ptr, i, n1, n2;
printf("输入初始大小: ");
scanf("%d", &n1);
ptr = malloc(n1 * sizeof(int));
if (!ptr) {
fprintf(stderr, "分配失败。\n");
return EXIT_FAILURE;
}
printf("重分配前地址:\n");
for (i = 0; i < n1; ++i) printf("%p\n", ptr + i);
printf("\n输入新大小: ");
scanf("%d", &n2);
int *tmp = realloc(ptr, n2 * sizeof(int));
if (!tmp) {
fprintf(stderr, "重分配失败。\n");
free(ptr);
return EXIT_FAILURE;
}
ptr = tmp;
printf("重分配后地址:\n");
for (i = 0; i < n2; ++i) printf("%p\n", ptr + i);
free(ptr);
return EXIT_SUCCESS;
}
典型输出
输入初始大小: 2
重分配前地址:
0x7ffc12345670
0x7ffc12345674
输入新大小: 4
重分配后地址:
0x7ffc12345670
0x7ffc12345674
0x7ffc12345678
0x7ffc1234567c
掌握这四个函数并应用适当的错误处理,即可在任何 C 应用中安全高效地管理堆内存。
C语言
- 理解 ROM、PROM、EPROM 与 EEPROM:设计、编程与识别
- 微处理器:存储程序计算的演进
- 动态定价回归传统零售:为何势在必行
- Cervoz推出DDR4-2666工业级内存 助力AI与物联网解决方案
- G.AL® C330 Dynamic:精密应用用高强度铝合金
- C++ 动态内存管理:new 与 delete 专家级实战指南
- C++ 动态数组分配实战指南:new/delete、初始化、扩容与内存管理
- C 语言 calloc() 详解:零初始化动态分配原理与实战案例
- C 语言 realloc() 完全指南:语法、最佳实践与实战案例
- C 语言动态内存管理:calloc、malloc 与 free 完全解析
- C++动态内存管理精要:栈与堆、new/delete、数组与对象分配实战
- Java 10 堆分配增强:支持 NV-DIMM 等替代内存设备