动态内存分配

在这里插入图片描述

C语言函数的副本机制


函数的副本机制:形式参数会开辟内存,新建一个变量,容纳传递过来的实际参数的值
注意:

函数的形参、return 都有副本机制、数组没有副本机制 (为了节约内存,数组拷贝非常耗费时间与空间)
函数形参和局部变量的生命周期、函数调用结束后就会被回收。


动态分配

1、malloc和free是C标准库中提供的两个函数,用以动态申请和释放内存,malloc()函数的基本调用格式为:
2、void malloc( unsigned int size );
3、参数size是个无符号整型数,用户由此控制申请内存的大小,执行成功时,系统会为程序开辟一块大小为size个内存字节的区域,并将该区域的首地址返回,用户可利用该地址管理并使用该块内存,如果申请失败(比如内存大小不够用),返回空指针NULL。
4、malloc()函数返回类型是void
,用其返回值对其他类型指针赋值时,必须进行显式转换。size仅仅是申请字节的大小,并不管申请的内存块中存储的数据类型,因此,申请内存的长度须由程序员通过“长度×sizeof(类型)”的方式给出,举例来说:
5、int* p=(int*) malloc(5* sizeof(int) );
6、Free就是释放内存,例如free(p)


1、C语言标准库函数还提供了calloc函数用以动态申请内存,和malloc函数以字节为单位申请内存不同,calloc函数是以目标对象为单位分配的,目标对象可以是数组,也可以是后面会讲到的结构体等。

 calloc函数的原型为:
 void* calloc(size_t num, size_t size);
 malloc()函数返回类型也是void*,需要强制转换才能为其他类型的指针赋值。calloc需要两个参数以指定申请内存块的大小,一是对象占据的内存字节数size,二是对象的个数num。
 size_t类型是无符号整型,在Windows及LCC编译环境下,其定义为:
 typedef unsigned int size_t;
 为已经分配的内存重新分配空间并复制内容
 realloc()函数有两个参数
 已分配的内存地址
 重新分配的字节数
void *realloc( void *ptr, size_t size );

2、 calloc会自动将内存初始化为0,malloc就不会

int num;
scanf("%d",&num);
(1)malloc
//动态数组,输入19,就有19个元素,初始化

int *p=(int *)malloc(sizeof(int)*num);

如果指针p==NULL则内存分配失败,否则就分配成功

(2)calloc

int *p=(int *)calloc(num,sizeof(int)); //动态分配
//第一个参数,多少个, 第二个参数元素占多大
如果指针p==NULL则内存分配失败,否则就分配成功

(3)relloc

relloc 如果可以拓展就拓展,否则就重新分配
拓展就是在原来地址后面增加内存。
不够的情况下,就回收原来的内存,并在回收之前分配一片内存,将原来的内容拷贝过来。然后收回原来的内存。

addnum增加的个数
在这里插入图片描述


1、 数组只能处理小数据
例如:定义数组 int a[1024102410] ; 运行报错

在这里插入图片描述

2、动态分配,是指用户可以在程序运行期间根据需要申请或释放内存,大小也完全可控。动态分配不像数组内存那样需要预先分配空间,而是由系统根据程序需要动态分配,大小完全按照用户的要求来,当使用完毕后,用户还可释放所申请的动态内存,由系统回收,以备他用。
malloc和free是C标准库中提供的两个函数,用以动态申请和释放内存

 malloc()函数的基本调用格式为:
 void *malloc( unsigned int size );
 参数size是个无符号整型数,用户由此控制申请内存的大小,执行成功时,系统会为程序开辟一块大小为size个内存字节的区域,并将该区域的首地址返回,用户可利用该地址管理并使用该块内存,如果申请失败(比如内存大小不够用),返回空指针NULL。


记住下面的规则:

【规则1】用malloc 或new 申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL 的内存。
【规则2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
【规则3】避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。
【规则4】动态内存的申请与释放必须配对,防止内存泄漏。
【规则5】用free 或delete 释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。


系统响应:

对于堆,应知道系统有一个记录空闲内存地址的链表,当系统收到程序申请时,遍历该链表,寻找第一个空间大于申请空间的堆结点,删除空闲结点链表中的该结点,并将该结点空间分配给程序(大多数系统会在这块内存空间首地址记录本次分配的大小,这样delete才能正确释放本内存空间,另外系统会将多余的部分重新放入空闲链表中)。
对于栈,只要栈的剩余空间大于所申请空间,系统为程序提供内存,否则报异常提示栈溢出。

空间大小:

堆是不连续的内存区域(因为系统是用链表来存储空闲内存地址,自然不是连续的),堆大小受限于计算机系统中有效的虚拟内存(32bit系统理论上是4G),所以堆的空间比较灵活,比较大。
栈是一块连续的内存区域,大小是操作系统预定好的,windows下栈大小是2M(也有是1M,在编译时确定,VC中可设置)。

碎片问题:

对于堆,频繁的new/delete会造成大量碎片,使程序效率降低。
对于栈,它是一个先进后出的队列,进出一一对应,不会产生碎片。
生长方向:
堆向上,向高地址方向增长。
栈向下,向低地址方向增长。

分配方式:

堆都是动态分配(没有静态分配的堆)。
栈有静态分配和动态分配,静态分配由编译器完成(如局部变量分配),动态分配由alloca函数分配,但栈的动态分配的资源由编译器进行释放,无需程序员实现。

分配效率:

堆由C/C++函数库提供,机制很复杂。所以堆的效率比栈低很多。
栈是极其系统提供的数据结构,计算机在底层对栈提供支持,分配专门寄存器存放栈地址,栈操作有专门指令
在栈区开辟一段内存,系统会自己回收。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值