2. malloc函数:函数原型、参数与返回值、基本用法
好,咱们正式开始聊动态内存分配。说实话,C语言里最让新手头疼的,就是这块内容。但你别怕,我带你一步步拆解。
先问个问题:为什么需要动态分配?你想想看,写程序时经常遇到这种情况——用户要输入多少数据,你事先根本不知道。比如写个学生成绩管理系统,有的班30人,有的班60人。你总不能每次都开个1000人的数组吧?太浪费了。这时候,malloc就派上用场了。
2.1 函数原型
malloc的全名是memory allocation,内存分配。它的原型长这样:
#include <stdlib.h>
void *malloc(size_t size);
嗯,这里有几个关键点,我一个个说。
2.2 参数:你要多大?
size参数,说白了就是你想要多少字节的内存。类型是size_t,通常是个无符号整数。你可能会问:那我怎么知道一个int占几个字节?用sizeof啊!
核心要点:永远不要写死数字。比如你要10个int,别写malloc(40),要写malloc(10 * sizeof(int))。为什么?因为不同平台int大小可能不一样。我当年刚入行时就吃过这个亏,代码在32位机上跑得好好的,移植到64位就崩了。
2.3 返回值:成功还是失败?
返回值类型是void *,也就是一个无类型指针。这意味着它可以指向任何类型的数据。但有个坑——
- 成功:返回指向分配内存的指针
- 失败:返回
NULL
警告:一定要检查返回值!我曾经见过一个同事,写了半天的代码,结果因为malloc返回NULL没检查,程序直接段错误。排查了一下午才发现是内存不够了。记住:malloc不是100%成功的。
2.4 基本用法:三步走
用malloc其实就三步,我总结一下:
- 调用malloc,传入你需要的字节数
- 检查返回值,确保不是NULL
- 用完之后free掉,释放内存
来看个完整的例子:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr;
int n = 5;
// 第一步:分配内存
arr = (int *)malloc(n * sizeof(int));
// 第二步:检查是否成功
if (arr == NULL) {
printf("内存分配失败!\n");
return 1;
}
// 使用这块内存
for (int i = 0; i < n; i++) {
arr[i] = i * 10;
printf("arr[%d] = %d\n", i, arr[i]);
}
// 第三步:释放内存
free(arr);
return 0;
}
小技巧:很多人纠结要不要强制类型转换。在C语言中,void *可以隐式转换为任何指针类型,所以(int *)这个转换其实可以省略。但我个人习惯加上,因为这样代码更清晰,别人一看就知道你要存什么类型的数据。
2.5 知识体系图
下面这张图,把malloc的核心逻辑串起来了。你看一遍,心里就有谱了:
2.6 常见误区
我见过太多人在malloc上栽跟头了。这里列几个最常见的:
| 误区 | 正确做法 | 为什么 |
|---|---|---|
| 不检查返回值 | 始终判断 if (ptr == NULL) |
内存可能不够,不检查就是埋雷 |
| 忘记free | 用完后立即free,并置NULL | 内存泄漏,程序跑久了就崩 |
| free后继续用 | free后把指针置NULL | 野指针,随时可能段错误 |
| 写死数字 | 用 sizeof 计算 |
跨平台兼容性,代码可读性 |
我曾经踩过的坑:有一次写网络服务器,处理大量并发连接。我图省事,每次分配内存后都不检查返回值。结果线上环境内存吃紧,malloc返回NULL,程序直接崩溃。从那以后,我写malloc必加检查,成了肌肉记忆。
2.7 小结
malloc其实不复杂。记住三点:参数传大小,返回值判空,用完要free。嗯,就这么简单。但越是简单的东西,越容易在细节上翻车。你写代码的时候,多留个心眼就好。