动态内存管理
需要的空间大小在程序运行时才能知道,为了满足这种需求,需要动态分配空间。
一、动态内存函数
1、malloc函数
原型:void *malloc(size_t size);
申请一个连续可用的空间(
以字节为单位),并返回指向这块空间的指针(申请成功)或者返回一个NULL指针(申请失败);
2、free函数
原型:void free(void *ptr);
释放动态开辟的空间:仅仅是
去掉ptr指针和动态开辟的空间的关联
3、calloc函数
原型:void *calloc(size_t num, size_t size);
功能和malloc的唯一区别就是,为num个大小为size的元素开辟一块空间,并将每个空间都初始化为0。
4、realloc函数
原型:void *realloc(void *ptr,size_t size);
对申请的空间大小进行调整。
在扩大原空间时,有两种情况
1、
原有空间之后有足够多的空间时,在原有内存之后直接追加空间;
2、原有空间之后没有足够多的空间时,在堆空间上另找一个合适大小的连续空间来使用。
特注:用realloc函数申请时,考虑到申请失败
ptr = realloc(ptr, 1000);
当申请失败后原空间数据就会丢失,所以这种做法是错误的。
正确的做法:
p = realloc(ptr,1000);
if(p != NULL){
ptr = p;
}
二、总:动态开辟空间的的四大步
1、动态申请空间;//申请的空间必比期望申请的空间大,所以一般建议大块申请。
2、判空(可能存在申请失败);
3、释放空间free;//释放掉后,ptr为野指针(悬垂指针)。
4、将ptr指向NULL。
三、关于动态内存的几点注意:
1、动态申请完,必须要判空;
2、释放内存free函数必须释放的是动态申请的空间(堆上开辟的空间);
3、必须整体申请,整体释放;
四、几个练习
1、Test运行的结果,原因
解析:
正确执行:(改正)
方法1,传址操作:将变量str的地址作为函数参数
char * GetMemory(char **p)
{
*p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str);
if (str != NULL){
strcpy(str, "hello");
printf(str);
}
free(str);//str为空时,函数什么事都不做
str = NULL;
}
运行成功,结果:hello
方法2:通过函数返回值动态开辟,不传参
char * GetMemory()
{
char *p;
p = (char *)malloc(100);
if (p != NULL){
return p;
}
}
void Test(void)
{
char *str = GetMemory();
strcpy(str, "hello");
printf(str);
free(str);
str = NULL;
}
运行成功,结果:hello
2、运行Test函数,结果,原因
char * GetMemory(void)
{
char p[] = "hello";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
编译通过,但不会输出hello(已测试过)
原因:GetMemory函数的数组p是保存在此
函数的栈帧上,函数运行完,栈帧被释放掉,但是释放仅是失效,数组还是存在的,
但是!!!,调用完GetMemory函数,接下来调用的是printf函数,是函数调用就会形成栈帧,则就会覆盖GetMemory函数的栈帧(当前已无效),所以,不会输出“hello”。
五、柔性数组
定义:
结构体中的最后一个元素允许是未知大小的数组,该数组就是柔性数组。
特点:
1、结构体中的柔性数组成员前面必须至少有一个其他成员;
2、结构体的大小不包括柔性数组的内存;
3、包含柔性数组成员的结构体用malloc函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
优势:方便内存释放
使用:
typedef struct st_type{
int i;
int a[0];//柔性数组
}type_a;
int main()
{
int i = 0;
type_a *p = (type_a *)malloc(sizeof(type_a) + 100 * sizeof(int));
if (p != NULL){
p->i = 100;
for (i = 0; i < 100; i++){
p->a[i] = i;
}
}
free(p);
p = NULL;
system("pause");
return 0;
}