malloc 是 C 语言动态内存分配的核心函数之一,它允许程序员在程序运行时(而不是编译时)申请一块指定大小的内存空间,这对于处理不确定大小的数据(如用户输入、文件内容等)至关重要。

malloc 是什么?
malloc 的全称是 memory allocation(内存分配),它定义在头文件 <stdlib.h> 中。
它的作用是:在 堆 上分配一块连续的内存空间,并返回一个指向这块内存起始地址的 void* 类型的指针。
关键点:
- 堆内存:与栈内存不同,堆内存由程序员手动管理,生命周期从
malloc调用开始,直到free调用或程序结束。 - *`void
指针**:malloc` 返回的是一个通用指针,它可以指向任何类型的数据,在使用时,我们通常需要将其强制转换为我们需要的具体类型的指针。
函数原型
void *malloc(size_t size);
- 参数:
size_t size: 你想要分配的内存空间的大小,以 字节 为单位。
- 返回值:
- 成功时: 返回一个指向分配好的内存块起始地址的
void*指针。 - 失败时: 如果堆空间不足,无法满足分配请求,
malloc会返回NULL指针,这是一个非常重要的返回值,必须进行检查!
- 成功时: 返回一个指向分配好的内存块起始地址的
基本用法步骤(四步曲)
使用 malloc 的标准流程如下:
第 1 步:包含头文件
必须包含 <stdlib.h>,因为 malloc 和 free 等函数都在这个头文件中声明。
#include <stdlib.h> // 或者 #include <malloc.h> 在某些系统中也可以
第 2 步:声明指针
声明一个与你想要存储的数据类型相匹配的指针。
int *ptr; // 声明一个指向整型的指针
第 3 步:调用 malloc 并检查返回值
使用 sizeof 运算符来计算所需内存的大小,并将返回的 void* 指针强制转换为你需要的类型。务必检查返回值是否为 NULL。
// 申请 sizeof(int) 字节的内存,并强制转换为 int*
ptr = (int *)malloc(sizeof(int));
// 检查内存是否分配成功
if (ptr == NULL) {
printf("内存分配失败!\n");
// 在这里可以采取错误处理措施,比如退出程序
return 1; // 或 exit(1);
}
第 4 步:使用内存
你可以像使用普通数组或变量一样,通过指针来访问和使用这块内存。
*ptr = 100; // 将 100 存入 ptr 指向的内存中
printf("ptr 指向的值是: %d\n", *ptr);
第 5 步:释放内存
当你不再需要这块内存时,必须 使用 free 函数将其释放,否则,就会造成 内存泄漏。
free(ptr); // 释放 ptr 指向的内存 ptr = NULL; // 这是一个好习惯,将指针置为 NULL,防止成为“野指针”
完整示例代码
示例 1:分配单个变量
#include <stdio.h>
#include <stdlib.h>
int main() {
// 1. 声明指针
int *number_ptr;
// 2. 分配内存
number_ptr = (int *)malloc(sizeof(int));
// 3. 检查是否分配成功
if (number_ptr == NULL) {
fprintf(stderr, "错误:内存分配失败,\n");
return 1;
}
// 4. 使用内存
*number_ptr = 42;
printf("分配的整数值是: %d\n", *number_ptr);
// 5. 释放内存
free(number_ptr);
number_ptr = NULL; // 推荐做法
return 0;
}
示例 2:分配一个数组
这是 malloc 最常见的用法之一,用于创建动态数组。
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
int *array_ptr;
printf("请输入数组的大小: ");
scanf("%d", &n);
// 1. 分配 n 个整型的内存空间
array_ptr = (int *)malloc(n * sizeof(int));
// 2. 检查是否分配成功
if (array_ptr == NULL) {
fprintf(stderr, "错误:内存分配失败,\n");
return 1;
}
// 3. 使用内存(像普通数组一样)
printf("请输入 %d 个整数:\n", n);
for (int i = 0; i < n; i++) {
scanf("%d", &array_ptr[i]);
}
printf("你输入的数组是:\n");
for (int i = 0; i < n; i++) {
printf("%d ", array_ptr[i]);
}
printf("\n");
// 4. 释放内存
free(array_ptr);
array_ptr = NULL;
return 0;
}
重要注意事项和常见错误
错误 1:忘记检查 NULL 返回值
这是最常见也是最危险的错误。malloc 失败而你没有检查,后续使用 NULL 指针会导致程序崩溃(段错误)。
// 错误示例 int *p = (int *)malloc(1000000000 * sizeof(int)); // 尝试分配过大内存 *p = 10; // p 是 NULL,这里会直接导致程序崩溃
错误 2:内存泄漏
分配了内存但没有 free,或者 free 的逻辑有误,导致这块内存永远无法被回收,直到程序结束,在长时间运行的程序(如服务器、游戏)中,内存泄漏是致命的。
// 错误示例
void leaky_function() {
int *p = (int *)malloc(sizeof(int));
*p = 5;
// 函数结束,p 被销毁,但分配的内存没有释放!
// 这块内存就泄漏了。
}
错误 3:重复释放
对同一块内存调用两次 free 会导致 未定义行为,通常会使程序崩溃。
// 错误示例 int *p = (int *)malloc(sizeof(int)); free(p); free(p); // 第二次 free 是错误的!
错误 4:释放后继续使用(野指针)
释放内存后,指针变量本身并没有被销毁,它仍然保存着那块已释放内存的地址,继续使用这个指针就是访问非法内存。
// 错误示例 int *p = (int *)malloc(sizeof(int)); *p = 10; free(p); // 内存已释放 *p = 20; // 错误!访问了已释放的内存,可能导致程序崩溃或数据污染
最佳实践:释放内存后,立即将指针置为 NULL。
free(p); p = NULL; // p 是 NULL,访问 *p 会在编译时或运行时被检查出来
错误 5:计算 sizeof 时的错误
在分配数组时,常见的错误是写成 malloc(n),这只会分配 n 个字节,而不是 n 个元素,正确的做法是 n * sizeof(数据类型)。
// 错误示例 int *p = (int *)malloc(10); // 只分配了 10 字节,只能存下 2 或 3 个 int // 正确示例 int *p = (int *)malloc(10 * sizeof(int)); // 分配了 10 个 int 的空间
malloc 与 calloc 的区别
malloc 和 calloc 都是动态内存分配函数,但 calloc 有两个主要区别:
- 参数不同:
calloc接受两个参数:元素个数 (num) 和每个元素的大小 (size)。void *calloc(size_t num, size_t size);
- 初始化:
calloc会将分配的内存块中的所有位都初始化为 零,而malloc不会进行初始化,内存中是随机的“垃圾值”。
示例:
// 使用 malloc,内存未初始化 int *p_malloc = (int *)malloc(5 * sizeof(int)); // p_malloc[0] 的值是随机的 // 使用 calloc,内存被初始化为 0 int *p_calloc = (int *)calloc(5, sizeof(int)); // p_calloc[0] 的值是 0
| 特性 | malloc |
|---|---|
| 头文件 | #include <stdlib.h> |
| 功能 | 在堆上分配指定字节数的内存 |
| 参数 | size_t size (总字节数) |
| 返回值 | 成功返回 void*,失败返回 NULL |
| 内存初始化 | 不确定 |
| 配套函数 | free() 用于释放内存 |
| 核心原则 | 谁分配,谁释放,每次 malloc 都必须对应一次 free。 |
掌握 malloc 是学习 C 语言高级特性的关键一步,请务必牢记其用法和注意事项,养成良好的内存管理习惯。
