C 语言 动态内存分配

一、核心作用

普通数组大小必须编译期确定;

动态内存可以程序运行时申请内存,堆(heap)上分配,用完手动释放。

bash 复制代码
头文件:<stdlib.h>

二、4 个核心函数

1. malloc

• 功能:分配size 字节连续内存,不初始化,内容随机垃圾值

• 返回:成功→内存首地址;失败→NULL

bash 复制代码
// 分配能存5个int的空间
int *p = (int *)malloc(5 * sizeof(int));
if(p == NULL)

{

    // 必须判空!
    perror("malloc fail");
    return -1;
}

2. calloc

复制代码
void *calloc(size_t num, size_t size);

• 功能:分配num个、每个size字节的内存,自动初始化为 0

bash 复制代码
int *p = (int *)calloc(5, sizeof(int));

3. realloc 重新调整大小

复制代码
void *realloc(void *ptr, size_t new_size);

• 扩容 / 缩容已有动态内存

• 注意:

  1. 不要直接 p = realloc(p, ...),失败会返回 NULL,丢失原地址造成内存泄漏

  2. 扩容不一定原地,可能拷贝数据到新地址

bash 复制代码
int *tmp = realloc(p, 10 * sizeof(int));
if(tmp != NULL){
    p = tmp;
}

4. free 释放内存

bash 复制代码
void free(void *ptr);

• 归还堆内存,必须配对使用

• 规则:

  • free 只能释放 malloc/calloc/realloc 得到的指针
  • 不能重复 free、不能 free 栈上变量
  • free 之后指针变成野指针,建议手动置 NULL
bash 复制代码
free(p);
p = NULL;

三、完整示例

bash 复制代码
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int n = 5;
    // 堆区申请内存,不初始化
    int *arr = (int *)malloc(n * sizeof(int));

    // ⚠重点:必须判断分配是否成功
    if(arr == NULL){
        printf("malloc fault\n");
        return 1; // 异常退出
    }

    for(int i = 0; i < n; i++){
        arr[i] = i + 1;
    }

    // ⚠易错:realloc先用临时指针接收,失败不会覆盖原地址
    int *tmp = realloc(arr, 10 * sizeof(int));
    if(tmp == NULL)
    {
        printf("realloc fault\n");
        free(arr);
        arr = NULL;
        return 1;
    }
    arr = tmp;

    // ⚠扩容新增区域数据随机,如需使用要手动赋值

    free(arr);      // ⚠堆内存使用完必须释放
    arr = NULL;     // ⚠防止野指针

    return 0; // 正常退出
}

四、常见坑

  1. 忘记 free → 内存泄漏

  2. free 之后继续使用指针 → 野指针访问(程序崩溃)

  3. 重复 free 同一地址

  4. realloc 直接赋值原指针,分配失败丢失内存

  5. 不判断 malloc 返回 NULL,内存不足直接崩溃

  6. sizeof( )写错,大小分配不足造成越界

五、栈内存 vs 堆内存

区域 分配方式 释放 生命周期
栈 (stack) 局部数组、局部变量 函数结束自动回收 函数内有效
堆 (heap) malloc/calloc 手动 free 直到 free 或程序结束
相关推荐
JPower_mr.g1 分钟前
SmartCall 音色管理技术解析:基于 SPI 的可扩展音色注册架构
java·开发语言·人工智能·ai·架构·开源
测试开发Kevin3 分钟前
IDEA工程结构解析:项目、模块、库、Facet、Artifact (工件) 概念说明
java·ide·intellij idea
大侠归来4 分钟前
Spring Boot 2.1 → 3.5 迁移推演:从实战出发的完整路线图
java·spring boot·后端
淡海水8 分钟前
02-04-原理篇-GC Roots与对象图遍历
算法·unity·c#·图·gc·遍历·roots
Wang's Blog11 分钟前
Java 中间件之 RabbitMQ 快速入门: SpringAMQP 的 DirectExchange 路由模式
java·中间件·java-rabbitmq
ClickHouseDB11 分钟前
ClickHouse 大规模 OpenTelemetry 数据接入架构的可靠性演进
算法
Shaoshing18 分钟前
BHU 润石工作室 251019自建赛题解
算法
Sweet锦25 分钟前
jDCS 开源项目:面向工业现场的 Modbus RTU 数据采集基础框架
java·spring boot·物联网·开源
海马26 分钟前
Spring Boot 开发知识整理
java·spring boot·后端
xiaolinudao12327 分钟前
将多个 Excel 表格中的数据合并到单个表中|6 种实现方案全解析
java·前端·excel