动态内存管理是C语言编程中至关重要的部分,它允许程序在运行时根据需要申请和释放内存空间。
| 内存管理函数 | 标准 | 说明 |
|---|---|---|
| malloc | C89 | 分配内存 |
| free | C89 | 释放内存 |
| realloc | C89 | 重新分配内存 |
| calloc | C89 | 分配一组内存 |
| aligned_alloc | C11 | 分配对齐的内存 |
动态内存管理主要通过标准库头文件 stdlib.h 中提供的 malloc 和 free 函数实现,前者负责分配内存,后者负责释放内存。
/*********************************************
* @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) = i 将 ptr + 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
说明:
调用 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 函数比较 array 和 ptr 指向的内存中前 10 * sizeof(int) 字节数据是否相同。
然后通过 memcpy 函数将 array 的前 10 * sizeof(int) 字节数据复制到 ptr 指向的内存中。
最后再次比较 array 和 ptr 指向的内存中前 10 * sizeof(int) 字节数据是否相同。
内存泄露(Memory Leak) 是指程序中分配了内存,但在不再需要时未能及时释放,导致系统可用内存逐渐减少的现象。
这种现象会随着程序运行时间的增长而不断累积,最终可能导致程序崩溃或系统性能下降。
例如:
int* ptr = (int*)malloc(10 * sizeof(int)); // 分配内存,大小为 10 个 int
// ...
ptr = (int*)malloc(10 * sizeof(int)); // 分配内存,大小为 10 个 int
这段代码中,第二次分配内存时,直接将地址赋值给了 ptr;这样一来,永久丢失了第一次分配的内存地址,从而无法释放第一次分配的内存。