6045

30 分钟

#C 语言的动态内存管理

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

内存管理函数标准说明
mallocC89分配内存
freeC89释放内存
reallocC89重新分配内存
callocC89分配一组内存
aligned_allocC11分配对齐的内存

动态内存管理主要通过标准库头文件 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/8/1

更新于 2025/8/1