动态分配内存

动态分配内存


1动态分配内存_mallloc_free

困境
(回础10.4讲)
需要用一个数组来保存用户的输入,但是却不知道用户会输 入多少条数据。
(1) 如果设一个太大的数组,则显得浪费内存
(2) 如果设得太小,又怕不够
问题:如何做到恰好够用、又一点不浪费呢?

困境
C/C++里,要求数组长度为常量
int Contact[100]; // 长度必须在代码里固定
不能这样:
int n = 0;
scanf(“%d”, &n);
int Contact[n]; // 编译错误!!数组长度必须为常量

动态内存分配 – malloc/free
系统中存在一个内存管理器(MM, Memory Manager),它负责 管理一堆闲置内存。它被设计用于解决此类问题。
MM提供的服务:应用程序可以向MM申请(借出)一块指定大 小的内存,用完之后再释放(还回)。
例如,
void* ptr = malloc (1024); // 申请,从MM借出内存
free(ptr); // 释放,还回MM

动态内存分配 – malloc/free
malloc函数

 void* malloc(int size) 

参数size: 指定要申请的内存空间的大小
返回值: void* ,指向这一块内存地址
(MM不关心你拿这块内存来存储何种数据,所以返回void*)
应用程序在使用malloc时,要把返回值转换成目标类型。例如, 要申请一块空间存放1000个Contact对象,则

 int size = 1000 * sizeof(Contact); 
 Contact* p = (Contact*) malloc(size);

这块内存和数组没有本质区别,用法完全相同。根据第9章,数 组本质上就是一块连续的内存,两者是一样的。

动态内存分配 – malloc/free
free函数

void free(void* ptr) 

ptr: 先前malloc返回的内存地址
返回值: void* ,指向这一块内存地址

动态内存分配 – malloc/free
举例:
先计算需要多少字节的内存空间
char* p = (char*)malloc(8); // 申请8个字节
for(int i=0; i<0; i++)
{
p[i] = i + 1;
}
free§; // 释放
// 观察内存:p指向的内存里的数据是显而易见的

动态内存分配 – malloc/free
举例:
int size = 4 * sizeof(Contact);
Contact* p = (Contact*) malloc (size);
p[0].id = 1;
strcpy(p[0].name, “shaofa”);
free §;

动态内存分配 – malloc/free
举例:
// 用户自己决定要输入多少条记录
int n = 0;
scanf(“%d”,&n);
// 用户需要多少,就分配多少内存

 int size = n * sizeof(Contact);
  Contact* p = (Contact*) malloc(size);
// 释放
 free(p);
// 观察内存:p指向的内存里的数据是显而易见的

关于MM
(1) MM是一个系统级的东西,所有的应用程序都向同一个MM申请内存。
(2) 何为借出?实际上,在内存被借出时,MM只是把它管理的内存标记 了一下,表示该段内存已经被占用。比如,它把每一段被占用的内存给 记录下来(首地址,长度) (p0,n0) (p1, n1) (p2, n2) …
(3) MM非常慷慨:①只要有人malloc,它都同意借出 ②你不归还,它 永远不会主动要求你free。
这意味着,用户程序应该自觉得及时free,以便不耽误别的应用程序的 使用。如果有个应用程序不停地malloc,而不free,那最终会用光MM的 内存。当MM没有更多闲置内存时,malloc返回NULL,表示内存已经用完。

关于MM
MM管理的内存区域称为“堆”Heap,相当于一个仓库。当用 程序要malloc时,就从仓库里登记借出。当free时,就将这 一块内存放回仓库。
再次重申:应用程序在malloc之后,应该尽早free!

关于MM
为何free的时候只需一个首地址呢?为什么不传递长度?
实际上,MM对借出的内存块进行标识 (p0, n0) (p1, n1) (p2, n2) … 它内部已经保证任意两块内存不会“交叠”,即不会重叠, 不会把一块内存同时借给两个应用程序使用。
所以,每块内存的首地址都是不同的,在free的时候只需要 指明首地址即可。

小结

  1. 使用malloc申请内存,具体申请多大的空间有你决定
  2. 使用free释放内存
  3. 使用原则:需要的时候再申请,不需要的时候立即释放
2malloc和free的具体用法举例

何为“对象”
对象指的一块内存
Contact a; // a是一个对象,即存放着一个对象的数据
Contact* p = (Contact*) malloc(sizeof(Contact));
确切地说:p指向了一个对象

malloc/free示例
示例:用Citizen表示一个市民,用Car表示一个辆车。他起初没 有车,但未来可能有一辆车。
struct Car
{
char maker[32]; // 制造商
int price; // 价格
};
struct Citizen
{
char name[32]; // 名字
int deposite; // 存款
Car* car; // NULL时表示没车
};

malloc/free示例
定义一个对象,开始没车
Citizen shaofa = { “shaofa”, 100, NULL };
后来,他可能买了一辆车
void buy(Citizen* owner)
{
// 创建一个对象
Car* car = (Car*) malloc(sizeof(Car));
strcpy(car->maker, “Chevrolet”);
car->price = 10;
// 保存此对象 (确切地说是记住了指针)
owner->car = car; // 有车了
owner->deposite -= car->price; // 钱没了
}

malloc/free示例
终有一天,这车会报废。。。
void discard(Citizen* who)
{
free(who->car); // 此对象被销毁
who->car = NULL; // 回到无车状态
}

malloc/free示例
也有可能会买给别人,
void sell(Citizen* owner, Citizen* other)
{
Car* car = owner->car;
car->price *= 0.5; //半价出售
other->car = car; // 别人拥有了这辆车
owner->deposite += car->price; // 收回一部分成本
//free(car); // oh,no! 不能free,这车在别人手里
owner->car = NULL; // 回到无车状态
}

注意事项
(1)不是malloc的指针,不可以free
例如,
int a = 10;
int* p = a;
free (p ); // 开什么玩笑??这个指针根本不是从MM那 里借来的

注意事项
(2) malloc的内存,必须及时free
怎么样才算“及时”?
“不及时”会怎样?
MM里可用的内存是有限的,你用完了就得尽快还,因为别的应用 程序也需要MM的内存。
只借不还,积累到一定程度,MM没有更多内存可用,于是malloc 返回NULL。
while(1)
{
void* ptr = malloc(1024*512);
}

注意事项
(3) 要free必须free首地址
错误的例子:
char* p = (char*) malloc(100); // 100个字节
free (p+50); // 借了100, 只还50?
要还就得全还,否则MM那边处理不了。(p, n)

注意事项
(4) malloc的返回值需要检测
char* ptr = (char*) malloc(1024); // 512K
if(ptr != NULL)
{

}
原因是:MM可能此时没有闲置内存可用。(虽然这种情况一 般不会发生)

注意事项
(5) free之后,该指针不应再使用
free之后,该内存交还给MM,该内存不再可用(失效)。
以下代码是错误的:
char* p = (char*) malloc(100);
free §;
for(int i=0; i<100; i++)
{
p[i] = i; //该内存已经被free,绝不可继续使用!
}
良好的编程习惯是:

free(p); 
p = NULL;  // 置为空指针

注意事项
(6) malloc得到的内存,可以任意位置释放
不一定要在相同的函数里释放,在应用程序的任意一个角落 释放都是有效的。
也就是说:这一块内存被malloc出来之后,完全交给你处置。

学习资源 《C语言/C++学习指南》语法篇(从入门到精通)》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值