目录
为何存在动态显存分配
目前我们晓得的显存分配方法主要有这样的方式
int a = 10; // 4 byteint c[10];// 40 byte
问题在于一旦我们将显存分配完后代码就写死了打印时该内存不能为written,很难再去根据我们的需求去改变所需的显存空间,所以c语言就给了我们一种便捷的功能供我们根据需求去申请空间
malloc和free
我们可以使用stdlib.h或malloc.h头文件,但我们通常使用stdlib.h
c语言提供了动态显存分配的函数
void*p=malloc(size_tsize);
这个函数向显存申请一块连续可用的空间,并返回指向这块空间的表针
1.假如开辟成功,则返回指向该空间的表针
2.假如开辟失败,则返回NULL,因而malloc返回值一定要检测
3.返回值类型时void*因而malloc函数并不晓得开辟空间的类型,具体在使用时使用者自己来决定
4.假如size为0,malloc函数的行为是未定义的,具体由编译器决定让我们先看一段代码
//void* p = malloc(40); int* p = (int*)malloc(40);
用malloc函数开辟的显存类型为void*,但在使用时为我们会发觉void*类型的表针无法使用,所以在实际操作时,我们作为代码的编撰者常常会将该表针强制类型转换为我们所须要的类型
我们在使用此函数时要注意开辟失败的情况,所以我们在使用表针时可以这样设计代码
int* p = (int*)malloc(40); //如果开辟成功 if (p == NULL) { return -1; } //开辟成功
当我们想要给空间初始化时也很简单
int i = 0; for (i = 0; i < 10; i++) { *(p + i) = 0; }
如今让我们瞧瞧怎么释放空间
free(p);
当我们使用完p指向的空间时,我们就可以将空间释放,将显存还给操作系统,而当我们将显存释放后我们还要注意一件事,让我们先来瞧瞧代码的调试结果
上图是刚为p开辟空间时p指向的地址,让我们再瞧瞧将p指向空间释放掉后p指向的空间
与刚才p指向的地址完全相同,所以说free可以将p指向的地址释放掉,但不会改变p的值,就好象我们去酒店开房,当我们退房后却没有把锁匙还了,其实这是一件很危险的事情,所以当我们将空间释放后我们常常会把p设为空表针
p = NULL;
假如free函数指向的空间不是动态开辟的,这么free函数的行为是未定义的
而假如free指向的是NULL表针,则函数哪些都不做
free(NULL);
所以前面的代码是正确的,只是该函数不进行任何操作
calloc
首先,malloc函数和calloc函数都是拿来开辟动态显存的,这么calloc和malloc有哪些区别呢?让我们先瞧瞧calloc的定义吧
我们发觉calloc会开辟一个链表并将每位元素初始化为0,而malloc不一样,他只会申请一块空间,并将初始地址返回。这么calloc定义中的num和size分别代表哪些呢,我们也可以在msdn瞧瞧
num代表元素的个数,size代表每位元素有几个字节,假如我们想开辟一段有10个int类型元素的字段打印时该内存不能为written,我们该怎么使用calloc呢?
int* p = (int*)calloc(10, sizeof(int));
其实我们也得注意显存分配失败的情况,所以我们还得加上这样的代码
if (p == NULL) { printf("%s", strerror(errno));//打印错误信息 return -1; }
我们也可以把数列的元素都复印下来
int i = 0; for (i = 0; i < 10; i++) { printf("%d ", *(p + i)); }
所以使用时我们应当如何在malloc和calloc之间选择呢?很简单,当我们想给显存初始化时就用calloc,不想初始化时就用malloc
reallc
有时我们会发觉显存空间分配太大了,有时又会发觉显存空间分配太小了,而realloc的出现可以让显存调整愈加便捷,首先让我们瞧瞧msdn中对realloc的定义
realloc的第一个参数是我们想要更改显存的表针,第二个是我们想更改成的大小,单位是字节,所以假如我们想把之前的p更改为20个整型的大小应当怎样做呢?我们会发觉显存调整会有两种情况,在这儿我们第一次p指向的空间为10个整形也就是40个字节,第二次想给他调整为20个整形也就是80个字节,我们先来看两张图
当我们想扩大空间时,会遇见原空间后空间充足与不足两种情况,当空间充足时则直接在旁边开辟显存,若不足则另寻一片空间能使显存连续开辟。如今我们再来看看,我们要怎样用代码实现显存变化
int* ptr = (int*)realloc(p, 20 * sizeof(int)); if (ptr != NULL) { p = ptr; }
这儿我先用一个临时表针ptr而不是直接用p来接收realloc的返回值,缘由在于假如该显存改变失败它将返回一个空表针,倘若直接用p接受的话还会让我们连原先的空间都找不到了,所以我们先用ptr来接收,假如开辟成功,也就是说ptr不等于空表针,则将p形参为ptr。
使用free释放动态开辟显存的一部份
我们先来思索一下这样一段代码是否正确
int* p = (int*)malloc(10 * sizeof(int)); if (p == NULL) { return -1; } int i = 0; for (i = 0; i < 10; i++) { *p++ = i; } free(p); p = NULL;
这段代码或许是错的,由于我们会发觉当我们使用free函数的时侯,p的值早已发生改变了,但是即使我们只将p减小5个int大小也是错误的,所以当我们使用free时必须从开辟空间的初始位置开始
动态显存开辟忘掉释放
我们释放动态显存有两种方式,
1.我们主动用free释放掉
2.当程序结束时系统手动将其释放
所以在有些时侯忘掉释放显存不会导致太大的影响,并且常常我们会让一个程序不断地运行,造成这一块不须要的空间不被释放,以至于难以使用,导致显存泄露,所以当我们开辟动态显存后必须将其释放