目录
为什么要进行动态内存管理
普通常见的内存开辟的方法有:
int val = 10;//在栈空间上开辟四个字节
char arr[10] = {0};//在栈空间上开辟10个字节的连续空间
但是上述方法有两个不足之处:
- 空间开辟的大小是一定的
- 数组在声明的时候,必须指定数组的长度,它所需要的内存在编译的时候分配
有时候我们在开辟空间时,只有在程序运行的时候才能知道它需要的空间大小,此时上述的开辟空间的方法就无法满足要求,这时候就需要用到动态开辟空间
动态内存开辟函数
malloc和free
C语言提供的 malloc 函数:
void* malloc (size_t size);
该函数向内存申请了一块连续的空间,并返回指向这块空间的指针。
- 如果开辟成功,返回指向该空间的指针
- 如果开辟失败,返回一个NULL指针,所以malloc的返回值一定要进行判空
- 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用时由使用者决定
-
如果参数 size 为 0,malloc 的行为是标准未定义的,取决于编译器
C语言提供的 free 函数:
void free (void* ptr);
该函数用来释放动态开辟的内存。
- 如果参数 ptr 指向的空间不是动态开辟来的,那么 free 函数的行为就是未定义的
- 如果参数 ptr 是NULL指针,则函数什么都不用做
calloc
C语言中 calloc 函数也用来动态内存开辟
void* calloc (size_t num,size_t size);
- 函数功能是 为 num 个大小为 size 的元素开辟一块空间,空间的每个字节初始化为 0
- 与函数 malloc 的区别:calloc 会在返回地址之前将申请的空间的每个字节初始化为 0 ,所以如果我们对于申请的内存空间的内容要求初始化,就可以用calloc函数
realloc
realloc 函数动态开辟内存更加灵活
void* realloc (void* ptr,size_t size);
-
ptr 是要调整的内存地址
- size 是调整之后的大小
- 返回值为调整之后的内存起始位置
- 该函数在调整原空间大小的基础上,还会降原来内存中的数据移动到新的空间
- 两种调整内存的情况
- 原有空间足够大:要拓展的空间内存直接在原有内存之后直接追加,原来空间的数据不变
- 原有空间之后没有足够的空间:在堆空间上重新找到一块合适的连续空间,将原有数据和要追加的数据一起搬移到到新开辟的空间上
常见的动态内存错误
- 对NULL指针的解应用操作
void test()
{
int *p = (int *)malloc(sizeof(int)*4);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
}
- 对非动态开辟空间使用free释放
void test()
{
int a = 10;
int *p = &a;
free(p);
}
- 对动态开辟的空间未进行free释放(内存泄漏)
- 对同一块动态内存多次重复free
- free释放一块动态内存的一部分
void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
- 对的动态开辟的空间越界访问