您现在的位置是:首页 >技术交流 >【C语言】动态内存管理网站首页技术交流
【C语言】动态内存管理
简介【C语言】动态内存管理
一、为什么存在动态内存分配
我们已经知道的一些内存开辟方式有:
int val = 20; //在栈上开辟4个字节的空间
char arr[10] = {0};//在栈上开辟10个字节的连续空间
上述方式开辟的内存大小是固定的,而实际需要的空间大小有时在程序运行过程才能知道。于是便有了动态内存分配,也就是在堆上动态申请内存。
二、动态内存函数
下面我们要介绍的动态内存函数有:malloc
,calloc
,free
和realloc
,这些函数都在stdlib.h
头文件中声明。
1. malloc
void* malloc (size_t size);
- 用于向内存申请一块连续可用的空间。
- 申请成功,函数返回的是这块空间的起始地址。
- 申请失败,函数返回的是空指针。
- 返回值类型是
void*
,这种类型的指针不知道步长,也不能解引用。所以函数的返回值要手动强转成需要的类型,再接收检查是否为空指针。 - 参数
size
是要开辟多少个字节的空间。
2. calloc
void* calloc (size_t num, size_t size);
- 类似
malloc
,作用是为num
个大小为size
的元素开辟一块空间。 - 不同的是
calloc
会把每个字节都初始化为0,而malloc
函数不会。
3. free
动态内存分配是在堆区上开辟空间的,它不会自动销毁,需要自己回收,或者程序结束时自动回收。如果不及时回收动态内存,会造成很多严重的后果,如内存泄露。
所以C语言提供了一个函数,用于回收动态分配的内存。
void free (void* ptr);
- 用于释放动态内存。
ptr
是要释放的空间的起始地址。- 如果
ptr
指向的空间不是动态开辟的,函数的行为是未定义的。 - 如果
ptr
是空指针,函数什么事也不做。 free
释放空间后,我们需要手动将ptr
置空,防止出现野指针。
4. realloc
有时候我们发现之前申请的空间太小了,会对内存的大小进行调整。
所以C语言提供了一个函数,用于对动态内存的大小进行调整。
void* realloc (void* ptr, size_t size);
ptr
是要调整的内存起始地址,size
是我们期望调整之后的内存大小。- 调整成功,函数返回的是调整之后的内存起始地址。
- 调整失败,函数返回的是空指针。
realloc
调整内存空间,有两种情况:- 原空间后面有足够大的空间
- 直接在原有内存后面追加空间,原空间的数据不会发生变化。
- 原空间后面没有足够大的空间
- 此时要扩展内存,就会另找一个大小合适的连续空间来使用。
原空间的数据将拷贝到新空间中,然后原空间内存的使用权会被回收。
- 此时要扩展内存,就会另找一个大小合适的连续空间来使用。
- 原空间后面有足够大的空间
来看一段代码:
//正常开辟动态内存
int *ptr = (int*)malloc(100);
//假设开辟成功
//下面要扩展容量
//错误做法
ptr = (int*)realloc(ptr, 1000);
//正确做法
int*p = (int*)realloc(ptr, 1000);
if(p != NULL)
{
ptr = p;
}
错误做法:
我们想用上面接收了malloc
返回值的指针ptr
来接受realloc
的返回值。这样如果realloc
调整失败,ptr
将接收到一个空指针。这样我们就会丢失malloc
开辟的内存空间的地址,导致后面无法释放malloc
开辟的内存,造成内存泄漏。
正确做法:
另外定义一个指针变量p
来接收realloc
的返回值。先判断p
不是空指针,保证realloc
调整成功,返回的是调整好的空间地址。如果realloc
另找了一个大小合适的空间来使用,旧空间也会自动回收。现在就可以安心将p
的值赋给ptr
了。
类似坑还有很多,我们只需注意一下几点:
• 动态开辟的内存空间,最后一定要释放。
• 想要释放内存,便要保证存放该内存地址的指针还存在。
• 释放完内存后,指针必须置空,防止非法访问。
三、常见错误
- 对空指针解引用。
- 越界访问。
- 非动态开辟的内存用
free
释放。 - 只释放了一块动态内存的一部分。
- 对同一块动态内存重复释放。
- 动态开辟的内存忘记释放。
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。