c语言动态分配空间
① c语言-动态分配内存 malloc & free
需要用一个数组来保存用户的输入,但是却不知道用户会输入多少条数据。
(1) 如果设一个太大的数组,则显得浪费内存
(2) 如果设得太小,又怕不够
问题:如何做到恰好够用、又一点不浪费呢?
系统中存在一个内存管理器(MM, Memory Manager),它负责管理一堆闲置内存。它被设计用于解决此类问题。
MM提供的服务:应用程序可以向MM申请(借出)一块指定大小的内存,用完之后再释放(还回)。
应用程序在使用malloc时,要把返回值转换成目标类型。
这块内存和数组没有本质区别,用法完全相同。
需要先计算需要多少字节的内存空间
数组举例子:
释放的时候需要注意, 因为在for循环执行之后,p的地址往前移动了10, 所以需要减去10, 然后再释放p,不然会有问题
// 当销毁时只需要free一次,malloc了几个字节就会free几个字节,和char类型还是int类型无关
free(p);
在一个函数中动态分配的内存,在另一个函数中操作这块内存
(1) MM是一个系统级的东西,所有的应用程序都向同一个MM申请内存。
(2) 何为借出?实际上,在内存被借出时,MM只是把它管理的内存标记了一下,表示该段内存已经被占用。比如,它把每一段被占用的内存给记录下来(首地址,长度)
(p0,n0) (p1, n1) (p2, n2) ...
(3) MM非常慷慨:①只要有人 malloc ,它都同意借出 ②你不归还,它永远不会主动要求你 free 。
(4) MM管理的内存区域称为“堆”Heap
这意味着,用户程序应该自觉得及时 free ,以便不耽误别的应用程序的使用。如果有个应用程序不停地 malloc ,而不 free ,那最终会用光MM的内存。当MM没有更多闲置内存时, malloc 返回 NULL ,表示内存已经用完。
再次重申: 应用程序在malloc之后,应该尽早free !
使用原则:需要的时候再申请,不需要的时候立即释放
实际上,MM对借出的内存块进行标识
(p0, n0) (p1, n1) (p2, n2) ...
它内部已经保证任意两块内存不会“交叠”,即不会重叠,不会把一块内存同时借给两个应用程序使用。
所以,每块内存的首地址都是不同的,在 free 的时候只需要指明首地址即可。
对象指的一块内存
示例:用Citizen表示一个市民,用Car表示一个辆车。他起初没有车,但未来可能有一辆车。
怎么样才算“及时”? “不及时”会怎样?
MM里可用的内存是有限的,你用完了就得尽快还,因为别的应用程序也需要MM的内存。
只借不还,积累到一定程度,MM没有更多内存可用,于是malloc返回NULL。
要还就得全还,否则MM那边处理不了
原因是:MM可能此时没有闲置内存可用。(虽然这种情况一般不会发生)
free之后,该内存交还给MM,该内存不再可用(失效)
不一定要在相同的函数里释放,在应用程序的任意一个角落释放都是有效的。
也就是说:这一块内存被malloc出来之后,完全交给你处置
功能:将 s 中当前位置后面的 n 个字节 (typedef unsigned int size_t )用 ch 替换并返回 s
参数:
参数:
功能:由 src 所指内存区域复制 n 个字节到 dest 所指内存区域。
memmove() 功能用法和 memcpy()) 一样,区别在于: dest
和 src 所指的内存空间重叠时, memmove() 仍然能处理,不过执行效率比 memcpy() 低一些
② C语言动态内存函数分配问题
你的问题是刚刚学习指针的人都有的问题,需要从地址来认识这个问题,C语言的数据都是需要申请空间来存放的,有静态和动态两种,动态分配的空间大小可以按需要分配,并且可以回收,静态是不可以回收的。
首先,分配动态的空间,指针P和空间的首地址是没有直接的联系的,只是为了手续要使用这个刚刚分配的空间才让P指针指向这个刚刚分配的空间的首地址的话,如果还不理解,你可以反向想想如果你分配的这个空间,而不用P指针指向这个首地址,那么你如何使用这个空间呢?
void型是针对地址型的直接分配,为什么不是分配char的空间呢?因为C语言和硬件关系密切,
有写硬件他的地址不是8位存储的,是16位,或者是32位的,那么这个void就忽略了这个硬件地址宽位就分配100个地址就是了,然后,强制转换成char的8位,如果硬件是16位了,那么,每个地址就会多分配了8位,而使用前8为来存储空间了。
返回的指针是分配的100个地址的首地址,不是这个指针P,举个例子吧,空间可以看做是一个队伍,他本身就有一个领头的人,那么P就是一个单独的人,那么,我们如果像要找到这个队伍,需要先找到队伍的领头人,领头的人只在你申请的时候出现一次,后面,你就找不到他了,怎么办?你把他电话给P吧,P可以找到他。呵呵。
如果还是不理解,那就不要理解了,建议去吧队列的方式,用指针和动态分配内存的方式实现一次,就知道了,不能照着书本抄,全部代码要自己写出来,就肯定理解了。
③ c语言中,malloc和free是什么意思
属于内存管理的两个函数,malloc是申请内存的,free是释放内存的。
1、malloc一般用法:
int *t=NULL;
t=(int *)malloc(sizeof(int));
也可以在sizeof前面加上一个'n*'这就成了一个动态分配数组的方法。
2、free一般用法:
int *t=NULL;
t=(int *)malloc(sizeof(int));
free(t);
这样t所指的空间就被释放掉了。
(3)c语言动态分配空间扩展阅读:
malloc函数定义
其函数原型为void *malloc(unsigned int size);其作用是在内存的动态存储区中分配一个长度为size的连续空间。此函数的返回值是分配区域的起始地址,或者说,此函数是一个指针型函数,返回的指针指向该分配域的开头位置。
如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。
④ C语言中的动态内存分配的用法举例
1、malloc函数:其作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。
2、free函数:由于内存区域总是有限的,不能不限制地分配下去,而且一个程序要尽量节省资源,所以当所分配的内存区域不用时,就要释放它,以便其它的变量或者程序使用。这时我们就要用到free函数。
3、calloc函数:其作用是在内存的动态存储区中分配n个长度为 size 的连续空间。函数返回一个指向分配区域的起始位置的指针;如果分配不成功,则返回NULL。
(4)c语言动态分配空间扩展阅读:
函数运算符:
new
运算符new用于向系统申请动态存储空间,并把首地址作为运算结果,它的使用形式为:
指针变量=new 数据类型;
例如:
int *p=new int
该语句的作用是会用new从内存中申请了一个int型变量(4个字节),并将该变量的首地址赋给指针变量p。
new所建立的变量的初始值是任意的,也可在用new分配内存的同时进行初始化。使用形式为:
指针变量=new 数据类型(初始值)。
delete
堆内存可按照要求进行分配,程序对内存的需求量随时会发生变化,有时程序在运行种可能会不再需要由new分配的内存空间,而且程序还未运行结束,这时就需要把先前占用的内存空间释放给堆内存,以后重新分配,供程序的其他部分使用。运算符delete用于释放new分配的内存空间,删除建立的对象,它的使用形式为:
delete指针变量;
其中的指针变量中保存着new分配的内存的首地址。
⑤ c语言中malloc是什么怎么用
malloc() 函数用来动态地分配内存空间,其原型为:void* malloc (size_t size);
说明:
【参数说明】
size 为需要分配的内存空间的大小,以字节(Byte)计。
【函数说明】
malloc() 在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。如果希望在分配内存的同时进行初始化,请使用 calloc() 函数。
【返回值】
分配成功返回指向该内存的地址,失败则返回 NULL。
操作:
由于申请内存空间时可能有也可能没有,所以需要自行判断是否申请成功,再进行后续操作。
如果 size 的值为 0,那么返回值会因标准库实现的不同而不同,可能是 NULL,也可能不是,但返回的指针不应该再次被引用。
注意:函数的返回值类型是 void *,void 并不是说没有返回值或者返回空指针,而是返回的指针类型未知。所以在使用 malloc() 时通常需要进行强制类型转换,将 void 指针转换成我们希望的类型,例如:
#include<stdlib.h>
typedef int ListData;
ListData *data; //存储空间基址
data = ( ListData * ) malloc( 100 * sizeof ( ListData ) );
(5)c语言动态分配空间扩展阅读
实现malloc的方法:
(1)数据结构
首先我们要确定所采用的数据结构。一个简单可行方案是将堆内存空间以块的形式组织起来,每个块由meta区和数据区组成,meta区记录数据块的元信息(数据区大小、空闲标志位、指针等等)。
数据区是真实分配的内存区域,并且数据区的第一个字节地址即为malloc返回的地址 。
(2)寻找合适的block
现在考虑如何在block链中查找合适的block。一般来说有两种查找算法:
First fit:从头开始,使用第一个数据区大小大于要求size的块所谓此次分配的块
Best fit:从头开始,遍历所有块,使用数据区大小大于size且差值最小的块作为此次分配的块
两种方式各有千秋,best fit有较高的内存使用率(payload较高),而first fit具有较高的运行效率。这里我们采用first fit算法。
(3)开辟新的block
如果现有block都不能满足size的要求,则需要在链表最后开辟一个新的block。
(4)分裂block
First fit有一个比较致命的缺点,就是可能会让更小的size占据很大的一块block,此时,为了提高payload,应该在剩余数据区足够大的情况下,将其分裂为一个新的block。
(5)malloc的实现
有了上面的代码,我们就可以实现一个简单的malloc.注意首先我们要定义个block链表的头first_block,初始化为NULL;另外,我们需要剩余空间至少有BLOCK_SIZE+8才执行分裂操作
由于我们需要malloc分配的数据区是按8字节对齐,所以size不为8的倍数时,我们需要将size调整为大于size的最小的8的倍数。