国际访客建议访问 Primers 编程伙伴 国际版站点 > C 教程 > 动态内存管理 以获得更好的体验。

# C 语言的动态内存管理

动态内存管理是C语言编程中至关重要的部分,它允许程序在运行时根据需要申请和释放内存空间。

内存管理函数 标准 说明
malloc C89 分配内存
free C89 释放内存
realloc C89 重新分配内存
calloc C89 分配一组内存
aligned_alloc C11 分配对齐的内存

动态内存管理主要通过标准库头文件 stdlib.h 中提供的 mallocfree 函数实现,前者负责分配内存,后者负责释放内存。

/*********************************************
 * @brief 分配内存
 * @param size 分配的内存字节数
 * @return 分配的内存地址
 ********************************************/
void* malloc(size_t size);
/*********************************************
 * @brief 释放内存
 * @param ptr 要释放的内存地址
 ********************************************/
void free(void* ptr);

示例:

#include <stdio.h>
#include <stdlib.h> // 引入 stdlib.h

int main(void)
{
    int* ptr = (int*)malloc(10 * sizeof(int)); // 分配内存,大小为 10 个 int

    if (ptr == NULL) // 判断内存分配是否成功
    {
        return 1; // 返回非 0 表示失败
    }

    for (int i = 0; i < 10; i+=1)
    {
        *(ptr + i) = i; // 向内存中写入值
    }

    for (int i = 0; i < 10; i+=1)
    {
        printf("%d ", *(ptr + i));  // 查看内存中的值
    }
    printf("\n");

    free(ptr); // 释放内存

    return 0;
}

运行结果:

0 1 2 3 4 5 6 7 8 9

说明:

  • 通过 #include <stdlib.h> 引入标准库头文件 stdlib.h

  • 调用 malloc(10 * sizeof(int)) 进行内存分配,大小为 10 个 int

    • (int*) 将返回的指针转从 void* 换为 int* 类型

  • 如果 ptr == NULL,说明内存分配失败,程序返回

    • main 函数返回 0 表示程序运行成功,返回非 0 表示程序运行失败

  • 通过 *(ptr + i) = iptr + i 指向的内存数据设为 i

  • 通过 printf("%d ", *(ptr + i)) 查看 ptr + i 指向的内存数据

  • 通过 free(ptr) 释放分配的内存

    • 释放后 ptr 中的地址就失效了,通常需要通过 ptr = NULL 将指针设为 NULL,避免访问无效的地址

# 内存初始化

通过 malloc 分配的内存不会被初始化,即内存数据是随机的。

可以通过 标准库头文件 string.h 中的 memset 进行初始化。

/*********************************************
 * @brief 使用指定的字节填满内存块
 * @param dest 要设置的内存块
 * @param value 要设置的字节值
 * @param count 内存块的字节数
 * @return 内存块的差异
 ********************************************/
void* memset(const void* dest, int value, size_t count);

示例:

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

int main(void)
{
    int* ptr = (int*)malloc(10 * sizeof(int)); // 分配内存,大小为 10 个 int

    if (ptr == NULL) // 判断内存分配是否成功
    {
        return 1; // 返回非 0 表示失败
    }

    memset(ptr, 0, 10 * sizeof(int)); // 将内存中的所有字节设为 0

    for (int i = 0; i < 10; i+=1)
    {
        printf("%d ", *(ptr + i));  // 查看内存中的值
    }
    printf("\n");

    free(ptr); // 释放内存

    return 0;
}

运行结果:

0 0 0 0 0 0 0 0 0 0

说明:

  • 通过 #include <string.h> 引入标准库头文件 string.h,该文件中声明了 memset 函数

  • 调用 memset(ptr, 0, 10 * sizeof(int))ptr 指向的内存中前 10 * sizeof(int) 字节设为 0

# 内存的常用操作

在标准库头文件 string.h 中提供了常用的内存操作函数。

函数 说明
memcmp 内存块比较
memcpy 复制内存块,不可重叠
memmove 复制内存块,可以重叠

示例:

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

int main(void)
{
    int array[10] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
    int* ptr = (int*)malloc(10 * sizeof(int)); // 分配内存,大小为 10 个 int

    if (ptr == NULL) // 判断内存分配是否成功
    {
        return 1; // 返回非 0 表示失败
    }

    // 比较 array 和 ptr 的数据
    if (memcmp(array, ptr, 10 * sizeof(int)) == 0)
    {
        printf("array 和 ptr 中的数据一样\n");
    }
    else
    {
        printf("array 和 ptr 中的数据不一样\n");
    }

    // 将 arrray 中的数据复制到 ptr 指向的内存
    memcpy(ptr, array, 10 * sizeof(int));

    // 再次比较 array 和 ptr 的数据
    if (memcmp(array, ptr, 10 * sizeof(int)) == 0)
    {
        printf("array 和 ptr 中的数据一样\n");
    }
    else
    {
        printf("array 和 ptr 中的数据不一样\n");
    }

    free(ptr); // 释放内存

    return 0;
}

运行结果:

array 和 ptr 中的数据不一样
array 和 ptr 中的数据一样

这个示例中,首先通过 memcmp 函数比较 arrayptr 指向的内存中前 10 * sizeof(int) 字节数据是否相同。

然后通过 memcpy 函数将 array 的前 10 * sizeof(int) 字节数据复制到 ptr 指向的内存中。

最后再次比较 arrayptr 指向的内存中前 10 * sizeof(int) 字节数据是否相同。

# 内存泄露

内存泄露(Memory Leak) 是指程序中分配了内存,但在不再需要时未能及时释放,导致系统可用内存逐渐减少的现象。

这种现象会随着程序运行时间的增长而不断累积,最终可能导致程序崩溃或系统性能下降。

例如:

int* ptr = (int*)malloc(10 * sizeof(int)); // 分配内存,大小为 10 个 int

// ...

ptr = (int*)malloc(10 * sizeof(int)); // 分配内存,大小为 10 个 int

这段代码中,第二次分配内存时,直接将地址赋值给了 ptr;这样一来,永久丢失了第一次分配的内存地址,从而无法释放第一次分配的内存。

本文 更新于: 2025-11-27 09:38:06 创建于: 2025-11-27 09:38:06