Z
ZHANK
编程在线教程C 语言教程动态内存管理 malloc/free
结构体与内存

动态内存管理 malloc/free

malloc/calloc/realloc/free、内存泄漏、悬空指针、valgrind

动态内存管理 malloc/free

堆(heap)是你向操作系统申请的内存——手动申请,手动释放。用的好灵活高效,用的不好内存泄漏、悬空指针。

学完本章你将: 掌握 malloc/calloc/realloc/free、内存泄漏排查、valgrind 检测。


malloc —— 申请内存

c
#include <stdio.h>
#include <stdlib.h>  // malloc, free

int main() {
    // 申请 5 个 int 的空间
    int *arr = (int *)malloc(5 * sizeof(int));

    if (arr == NULL) {
        printf("内存分配失败!\n");
        return 1;
    }

    for (int i = 0; i < 5; i++) {
        arr[i] = i * 10;
    }
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);  // 0 10 20 30 40
    }

    free(arr);   // 用完了,释放!
    return 0;
}

calloc —— 申请 + 清零

c
// calloc(n, size) → 分配 n 个大小为 size 的空间并清零
int *arr = (int *)calloc(5, sizeof(int));
// 等价于 malloc(5 * sizeof(int)) + 手动清零

realloc —— 调整大小

c
int *arr = (int *)malloc(3 * sizeof(int));
arr[0] = 1; arr[1] = 2; arr[2] = 3;

// 扩大到 5 个元素
arr = (int *)realloc(arr, 5 * sizeof(int));
arr[3] = 4; arr[4] = 5;

free(arr);

⚠️ realloc 可能移动数据到新地址!始终用返回值覆盖原指针,不要假设地址不变。


内存泄漏 —— 致命错误

c
// ❌ 内存泄漏
void leak() {
    int *p = malloc(100);
    // 忘了 free —— 函数返回后 p 消失,但内存没释放
}

// ✅ 正确做法
void noLeak() {
    int *p = malloc(100);
    // ... 使用 ...
    free(p);
}

常见内存错误

c
// 1. 重复释放
int *p = malloc(10);
free(p);
// free(p);  // ❌ 未定义行为!

// 2. 使用已释放的内存
int *p = malloc(10);
free(p);
*p = 42;  // ❌ 悬空指针!

// 3. free 非 malloc 的地址
int x;
// free(&x);  // ❌ 不是堆内存!

// ✅ 防御:释放后置 NULL
free(p);
p = NULL;

// ✅ 检测工具
// valgrind --leak-check=full ./program