2. malloc 的魔法:malloc函数原型、参数与返回值

好,咱们正式开始接触动态内存分配的第一个核心函数——malloc

说实话,我刚开始学C语言那会儿,看到malloc这个名字,第一反应是「这玩意儿是干嘛的?内存还能动态分配?」。后来真正用上了,才发现它就像一把瑞士军刀——用好了,代码灵活又高效;用不好,程序崩溃得莫名其妙。

今天咱们就把malloc的底裤扒干净,看看它到底是怎么工作的。

2.1 函数原型:长什么样?

先看官方定义:

#include <stdlib.h>

void *malloc(size_t size);

嗯,就这么简单。一个函数名,一个参数,一个返回值。

但别小看它。我见过不少新手,甚至工作两三年的工程师,在这个函数上栽过跟头。咱们一个一个拆开看。

2.2 参数:你要多大?

size 参数的类型是 size_t,说白了就是一个无符号整数。它告诉系统:「嘿,给我留这么一大块内存。」

单位是字节。不是比特,不是字,是字节。

举个例子:

int *p = (int *)malloc(4);

这行代码的意思是:向系统申请4个字节的内存,用来存一个 int

但问题来了——int在不同平台上大小不一样。在32位系统上是4字节,在64位系统上可能还是4字节(取决于编译器),但有些嵌入式平台上可能是2字节。

所以,我个人的习惯是:永远不要写死数字。用 sizeof 运算符:

int *p = (int *)malloc(sizeof(int));

这样,不管平台怎么变,代码都能正确申请到合适的大小。

小技巧: 如果你要申请一个数组,比如10个int,可以这样写:
int *arr = (int *)malloc(10 * sizeof(int));
这样代码更清晰,也更容易维护。

2.3 返回值:成功还是失败?

malloc 返回的是 void *——一个无类型指针。说白了,就是一块内存的起始地址,但系统不知道你要用它存什么类型的数据。

所以我们需要强制类型转换

int *p = (int *)malloc(sizeof(int));

void * 转成 int *,告诉编译器:「这块内存我要用来存int。」

但这里有个关键点:malloc 可能失败

为什么会失败?内存不够了呗。比如你申请1GB,但系统只剩512MB了,那 malloc 就会返回 NULL

我曾经在一个嵌入式项目里吃过这个亏。当时申请了一块缓冲区,没检查返回值就直接用了。结果程序跑着跑着就崩了,查了两天才发现是内存不足导致 malloc 返回了 NULL

所以,每次 malloc 之后,一定要检查返回值

int *p = (int *)malloc(sizeof(int));
if (p == NULL) {
    // 处理错误,比如打印日志、退出程序等
    printf("内存分配失败!\n");
    return -1;
}
警告: 永远不要假设 malloc 一定会成功。在资源受限的嵌入式系统、长时间运行的服务端程序、或者处理大数据时,malloc 失败是真实存在的风险。

2.4 申请一块整型内存:完整示例

好了,理论说完了,咱们写个完整的例子:

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 申请一块整型内存
    int *p = (int *)malloc(sizeof(int));
    
    // 检查是否成功
    if (p == NULL) {
        printf("内存分配失败,程序退出。\n");
        return 1;
    }
    
    // 使用这块内存
    *p = 42;
    printf("p 指向的值是:%d\n", *p);
    
    // 释放内存
    free(p);
    
    return 0;
}

运行结果:

p 指向的值是:42

你看,流程其实很简单:申请 → 检查 → 使用 → 释放。

嗯,这里要注意:free(p) 这一步很多人会忘。我刚开始写C的时候也经常漏掉,结果程序跑着跑着内存就爆了。后来养成了习惯,每次 malloc 之后,马上写对应的 free,就像配对一样。

2.5 知识体系图

下面这张图帮你理清 malloc 的核心逻辑:

malloc 核心知识体系 malloc 函数原型:void *malloc(size_t size) 参数:size_t size(字节数) 返回值:void *(成功)或 NULL(失败) 关键要点 • 用 sizeof 计算大小 • 必须检查返回值 • 使用后要 free • 强制类型转换 • 配对 malloc/free 常见错误 • 忘记检查 NULL • 忘记 free 导致内存泄漏 • 写死数字不用 sizeof • 重复 free 同一块内存 • 使用已 free 的指针

2.6 避坑指南

最后,分享几个我踩过的坑:

  • 不要忘记包含头文件#include <stdlib.h> 是必须的。少了它,编译器会警告,甚至报错。
  • 不要对 NULL 指针解引用:如果 malloc 返回 NULL,你直接 *p = 42,程序立马崩溃。
  • 不要重复 free:同一块内存只能 free 一次。重复 free 会导致未定义行为,程序可能崩溃,也可能不崩溃——但迟早会出问题。
  • 不要忘记 free:每次 malloc 都要有对应的 free。否则内存泄漏,程序跑久了内存就爆了。

我曾经在一个网络服务器项目里,因为忘记 free 一个缓冲区,导致内存泄漏。服务器跑了三天后,内存占用从 50MB 涨到了 2GB,最后被系统 OOM killer 干掉了。从那以后,我每次写 malloc,都会立刻写对应的 free,就像条件反射一样。

好了,malloc 的基本用法就这些。下一节咱们聊聊 callocrealloc,看看它们和 malloc 有什么不同。


公众号:蓝海资料掘金营,微信deep3321