动态内存管理

在C语言中,我们已经知道有两种方式来获取内存空间:定义变量和创建数组
1 | int x = 10;//在栈空间获取4个字节来存储10 |
他们特点很明显:内存空间都是固定的,数组也需要在声明的时候就指定长度(但c99中支持了数组定义时[]内写变量)。
但是实际情况是:在有些情况下只有程序运行的时候我们才知道它需要多大的内存,而那时原先申请固定内存已经不满足了。这个时候就需要来动态开辟内存。
C语言中共有三个申请内存空间的函数:malloc , calloc ,realloc,也提供了一个将空间还给内存的函数:free。这四个函数都在头文件stdlib.h中声明。
malloc和free
malloc函数的原型:
1 | void* malloc(size_t size); |
size_t为无符号整形,即在内存中申请一块连续可用的大小为size的空间(大小为字节), 若申请并开辟成功,则返回值是指向这块空间起始位置的指针,类型为void* 需要我们自己来决定申请的类型。若申请失败,则返回NULL,因此使用mallloc函数时需要做检查。如果参数 size 为0,malloc的行为是标准是未定义的,出现的情况取决于你使用编译器。
例如申请一个16字节的空间
1 | int *p = (int*)malloc(4*sizeof(int)); |
这样p就指向了一个16字节的空间:
有借有换,再借不难。我们向内存申请了空间,当我们不需要的时候,就需要将空间还给内存,C语言提供了free函数来对内存进行释放和回收,否则会有内存泄露的风险。函数原型:
1 | void free (void* ptr); |
free用来释放我们自己动态开辟的内存,不能释放非动态开辟的。
举例:
1 |
|
calloc
calloc函数原型:
1 | void* calloc(size_t num,size_t size); |
calloc函数的功能:是为num(元素个数)个大小为size(一个元素所占的字节数)的函数申请一块空间,并且把空间内的每个字节都初始化为0
calloc与malloc函数区别就是将每个字节都置为0且calloc函数可自定义每个元素长度,calloc更适合初始化大型数据结构,比如创建数组或结构体
举例:
1 |
|
realloc
realloc函数可以对我们申请到的空间动态的调整。函数原型:
1 | void* realloc(void* ptr,size_t size); |
ptr为我们要调整内存的地址,size是重新调整之后的大小。返回值仍然是是调整之后的内存起始位置。
当我们缩小空间时,会直接在原空间后面切除。如果后面有数据也会直接丢失。
1 | int* p = (int*)malloc(10); |
当我们放大空间时就会有问题:
我们知道申请的空间在内存中是连续的,所以在使用realloc函数拓展内存时我们会遇到两种情况:
第一种是后面的内存够用:会直接往后延长
第二种是后面的内存不够用:
此时realloc会在堆区找一块新的连续空间,将原内存块的数据拷贝到新内存,然后再释放掉原内存块。
1 |
|
这是输出结果:可以看到p的地址发生了改变。
这时就要考虑一个问题:要是realloc失败了呢?
此时p就会得到一个NULL,而原数据就消失在内存的茫茫大海中了(并不会被释放)此时我们丢了数据又泄露了内存。而解决方法就是和上面一样:使用一个临时指针来接受返回值,若失败了仍然可以操作原内存。
1 | int *p = (int*)malloc(10 * sizeof(int)); |
动态内存常见的问题:
内存泄露:使用了malloc但是未释放内存
重复释放内存:
1
2
3
4
5
6
7free(p);
free(p);//对同已块空间连续释放两次,会导致程序崩溃
//解决方法是:释放完内存后立即置空
//即:
free(p);
p=NULL;
//这时再free(p)就不会报错了迷航指针
1
2
3int* p = malloc(100);
free(p);
*p = 10;//这里操作已经释放的内存解决方法同上:操作完就置空free(p);p=NULL
对非动态开辟的内存free释放
1
2
3
4
5
6int main()
{
int a = 10;
int* p = &a;
free(p);//这里会报错
}使用free释放动态开辟内存的一部分
1
2
3int* p = (int*)malloc(10);
p++;
free(p);//这时p已经指向了下一个位置,解决方法是使用*(p+i)即p[i]或者使用新指针指向下一个位置申请多少内存就只能使用多少内存,不能越界访问。
- 标题: 动态内存管理
- 作者: qmtt
- 创建于 : 2025-03-16 21:51:43
- 更新于 : 2025-04-21 11:08:18
- 链接: https://qmtt.wang/2025/03/16/动态内存管理/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。