为什么存在动态内存分配
创建的变量和数组的大小都是固定的,开辟的过多浪费,太少又不满足要求.
所以可以动态申请和管理内存空间
动态内存函数的介绍(头文件是stdlib)
malloc
void* malloc (size_t size);
向内存申请一块连续可用的空间,并返回指向这块空间的起始地址
- malloc函数如果申请内存成功,返回申请到的空间的起始地址
- 如果申请失败,则返回NULL指针,不能使用了(所以返回值一定要做检查)
- 如果参数size为0,取决于编译器
malloc函数申请的空间,是怎么释放的呢?
1.free 释放 – 主动
2. 程序退出后,malloc申请的空间也会被操作系统回收 – 被动
free
void free (void* ptr);
free函数用来释放动态开辟的内存
- 如果参数 ptr 指向的空间不是动态开辟的,那 free 函数的行为是未定义的
- 如果参数 ptr 是NULL指针,则函数什么也不做
ptr还是指向原来位置,是野指针,所以要赋值成NULL
错误(使用free释放一块动态开辟内存的一部分)
void test()
{
int* p = (int*)malloc(100);
int i = 0;
for (i = 0; i < 10; i++)
*p++ = i;
free(p);
p = NULL;
}
free的参数只能是起始地址.
calloc
void* calloc (size_t num, size_t size);
- 第一个参数是元素的个数
- 第二个参数是一个元素多少字节
- 会将空间初始化成0
realloc
void* realloc (void* ptr, size_t size);
- ptr:要调整的内存起始地址
- size:调整之后的新大小
- 返回调整之后的内存起始地址
realloc开辟空间的方式有两种
- 后面的空间足够,直接在后面开辟.
- 后续的空间不够,不能直接增加,会找一块新的足够的空间,一次性开辟足够多的空间
第二种情况:
1.将旧的空间的数据,拷贝到新的空间
2.释放掉旧的空间
3. 返回新的空间起始地址
返回的可能是NULL,所以要先判断一下再赋值给之前指针
#include<stdlib.h>
int main()
{
int* ptr = (int*)malloc(4 * sizeof(int));
if (ptr == NULL)
{
perror("ptr");
return 1;
}
int i = 0;
for (i = 0; i < 4; i++)
ptr[i] = i;
int* p = (int*)realloc(ptr, 20 * sizeof(int));
if (p != NULL)
{
ptr = p;
}
p = NULL;
//....
free(ptr);
ptr = NULL;
return 0;
}
- 第一个参数是NULL,就相当于malloc
#include<stdlib.h>
int main()
{
int* ptr = (int*)realloc(NULL, 40);//==malloc(40)
if (ptr != NULL)
{
//....
}
free(ptr);
ptr = NULL;
return 0;
}
错误案例解析
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void GetMemory(char* p)
{
p = (char*)malloc(100);
}
void Test()
{
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
int main()
{
Test();
return 0;
}
两个错误
- 程序对NULL解引用操作,程序崩溃
- 动态申请的空间没有被释放,内存泄露.
printf(str);没有问题
像是printf(“hello word”);也没有%s,字符串返回的是起始地址