第20章 指针 二 为指针分配和释放空间
更新时间:2023-04-22 10:33:01 阅读量: 实用文档 文档下载
- 第20章再次遇到战神王爷推荐度:
- 相关推荐
白话C++
第二十章指针二为指针分配和释放空间
20.1 理解指针的两种“改变”
20.1.1 改变指针的值
20.1.2 改变指针所指的变量的值
20.1.3 两种改变?一种改变?
20.2 C++ 方式的内存分配与释放 new 和 delete
20.2.1 new
20.2.2 在new 时初始化内存的值
20.2.3 delete
20.2.4 实验: new 和 delete
20.2.5 new 和 delete 的关系
20.3 new [] 和 delete []
20.3.1 new[] / delete[] 基本用法
20.3.2 new []/ delete[] 示例
20.3.3 详解指向连续空间的指针
20.4 delete/delete[] 的两个注意点
20.4.1 一个指针被删除时,应指向最初的地址
20.4.2 已释放的空间,不可重复释放
20.5 C 方式的内存管理
20.5.1 分配内存 malloc 函数
20.5.2 释放内存 free 函数
20.5.3 重调空间的大小: realloc 函数
20.5.4 malloc、realloc、free的例子
20.1 理解指针的两种“改变”
普通变量(非指针,简单类型变量)只能改变值:
1) int a = 100;
2) ...
3) a = 200;
白话C++
第 1 行代码,声明int类型变量a,并且初始化a的值为100。
到第 3 行代码,变量a的值被改变成200。
对于非指针的简单变量,能被程序改变的,只有这一种。而指针变量,似乎有两种改变。
20.1.1 改变指针的值
这一点和普通变量一致。但要特别注意,“改变指针的值”引起的结果是什么?其实就是“改变指针的指向”。
因为,指针的值是某个变量的地址。假如指针P原来的值是A变量的地址,现在改为B变量的地址。我们称为:“P由指向A改为指向B”。这就是指针的第一种改变。
以下是示例代码:
int* P;
int A,B;
1) P = &A;
2) ...
3) P = &B;
1) 行代码中,P 的值为 &A,即P指向变量A。
到3)行代码中,P的值变为&B,即改为指向变量B。
下面讲:指针的第二种改变。通过指针,改变指针所指的变量的值。
20.1.2 改变指针所指的变量的值
复习前一章,我们知道通过 * (地址解析符),可以得到、或改变指针所指的变量的值。
白话C++
int* P;
int A = 100;
P = &A;
*P = 200;
cout << A << endl;
代码中加粗的那一行:*P = 200; ,其作用完全等同于:A = 200;
所以,最后一行输出的结果是 200。
这就是指针的第二种改变:所指变量的值,被改变了。
20.1.3 两种改变?一种改变?
两种改变的意义不同:
改变一:改变指针本身的值(改变指向)。
改变二:改变指针指向的变量的值。
从代码上看:
第一种改变,P = &A; 左值(等号左边的值)是变量本身,右值
则是一个地址。
而第二种改变,*P = 200; 左值通过星号对P操作,来取得P指
向的变量;右值是普通的值。
理解,区分对指针的两种改变,才能学会如何使用指针。
请思考:上一章讲的“指针的加减操作”,是对指针的哪一种改变?
白话C++
最后需要说明,严格意义上,指针仍然只有一种改变,即改变指针本身的值。改变指针指向的变量,应视为对另一变量的改变,只不过在代码上,它通过指针来进行,而不是直接对另一变量进行操作。
为指针分配、释放内存空间
之前,我们给指针下的定义是“指针是一个变量,它存放的值是另一个变量的地址”。
比如:
int a;
int* p = &a;
看,a 就是“另一个变量”,p指向了a。
我们知道,变量总是要占用一定的内存空间,比如上面的a,就占用了4个字节(sizeof(int))。这四个字节属于谁?当然属于变量a,而不是p。
现在要讲的是:也可以单独为指针分配一段新的内存空间。这一段内容不属于某个变量。
20.2 C++ 方式的内存分配与释放 new 和 delete
在内存管理上,C++ 和 C 有着完全不同的两套方案。当然,C++的总是同时兼容C。C的那一套方案在C++里同样可行。
我们首先看看纯C++的那一套: new 和 delete。
new ,从字面上看意思为“新”;而delete 字面意思为“删除”。二者在C++中内存管理中大致的功能,应是一个为“新建”,一个为“删除”。
20.2.1 new
白话C++
new 是 c++ 的一个关键字。被当作像 +、-、* 、/ 一样的操作符。它的操作结果是在申请到一段指定数据类型大小的内存。
语法:
指针变量 = new 数据类型;
new 将做三件事:
1、主动计算指定数据类型需要的内存空间大小;
2、返回正确的指针类型;
3、在分配内存的一,将按照语法规则,初始化所分配的内存。
这是什么意思呢?看看例子吧:
int* p;
p = new int;
和以往不一样,p 这回不再“寄人篱下”,并不是指向某个已存在的变量,而是直接指向一段由new 分配而来的新内存空间。
“p 指向一段由new 分配而来的新内存空间”这句话等同于:“new 分配一段新的内存空间,然后将该内存空间的地址存入到变量p中。”
所以,最终p中仍然是存储了一个变量的地址,只是,这是一个“无名”变量。
指向原有的某个变量,和指向一段新分配的内存空间,有什么区别呢?
“原有的变量”,可以比喻成指向一间原有的,并且有主的房间。而“新分配的内存空间”,则像是一个“临时建筑物”。我们必须在不用它的时候,主动将它拆迁。拆迁的工作由delete来完成。
白话C++
当指针变量通过 new ,而得到一个内存地址后,我们就可以像以前的所说的,通过该指针,通过*号,而对该内存地址(一个无名的变量),进行操作。
如:
int* p = new int;
*p = 100;
cout << *p << endl;
屏幕将输出100。
20.2.2 在new 时初始化内存的值
new 也可以在申请内存空间时,直接设置该段内存里要放点什么.
语法:
指针变量 = new 数据类型(初值);
这样,上例可以改为:
int* p = new int(100);
cout << *p << endl;
如果你申请的是字符类型的空间,并且想初始化为‘A':
char* pchar = new char('A');
20.2.3 delete
语法:
delete 指针变量;
白话C++
delete 将释放指定指针所指向的内存空间。
举例:
int* p;
p = new int;
*p = 100;
cout << *p << endl;
delete p;
system("PAUSE");
注意,当一个指针接受delete操作后,它就又成了一个“指向不明”的指针。尽管我们可以猜测它还是指向“原来的房子”,然而,事实上,那座“房子”已经被delete “拆迁”掉了。
20.2.4 实验: new 和 delete
很简单的例子。
第一步:
首先,在CB新建一个控制台程序。然后把上一小节的代码放到main()函数内。运行。结果如下:
(new 和 delete)
按任意键退出后,保存工程(Ctrl + Shift + S)。
第二步:
白话C++
接下来我们来观察指针变量被delete之后,所指向的内存会是什么。但,这是一件犯了C、C++编程大忌的事:访问一个已经delete 的指针的值。如果你最近运气很差,你的CB可能会被强行退出。所以,你明白我们为什么要先存盘了,对不?
在前面的代码中,加入以下加粗加红的一行(同时,你也应注意我的加的注释):
int* p;
p = new int;
*p = 100;
cout << *p << endl;
delete p; //p所指向的内存空间已经被释放
cout << *p << endl; //我们故意去访问此时p所指的内存
system("PAUSE");
运行结果:
(访问delete之后的指针)
44244844??在你的机器可能不是这个数,但一定同样是怪怪的值。原来是好端端的100,现在却成了44244844。不要问我这是为什么?昨天来时,美眉还住在这里一座别致小阁楼里,今日故地重游,这里竟成废墟一片,依稀只见破墙上尚有:“拆!——城建局”的字样?!
new 是管建房的,而 delete就一个字:拆!
白话C++
请大家自行在CB上完成本实验。我没有提供本题的实际工程。20.2.5 new 和 delete 的关系
如果只有“建房”而没有“拆房”,那么程序就会占用内存越来越多。所以,当使用new 为某个指针分配出内存空间后,一定要记得在不需要再使用时,用delete 删除。下面是一个例子。演示new 和 delete 的对应使用。
//建屋和入住:
1) int* p = new int(100);
//使用:
2) cout << *p << endl;
//拆:
3) delete p;
看,第1句,申请了4字节的内存空间,同时存入值为100的整数。
第2句,在屏幕上输出入住者的值 (100)。
第3句,释放内存(这4字节被系统收回准备做其它用途)。入住者呢?自然消失了。
前面举的例子都是在 new 一个 int 类型,其它类型也一样:
char* a = new char('A');
cout << *a << endl;
*a = 'B';
cout << *a << end;
delete a;
bool* b = new bool;
白话C++
*b = true;
if (*b)
cout << "true" << endl;
else
cout << "fale" << endl;
但是这些都是简单数据类型,如果要分配数组一样的连续空间,则需要使另一对武器。
20.3 new [] 和 delete []
new / delete 用于分配和释放单个变量的空间,而 new [] / delete[] 则用于分配连续多个变量的存间。
20.3.1 new[] / delete[] 基本用法
new [] 语法:
指针变量 = new 数据类型[元素个数]
语法实例:
int* p = new int[20];
首先,你需要迅速回想一下,如果是 int* p = new int(20); 那么该是什么作用?否则你很容易在事后把二者混了。
实例中,用 new 申请分配了20个连续的整数所需的空间,即:20 * sizeof(int) = 80个字节。
图示为:
白话C++
(指针变量p指向一段连续的内存空间)
new int 只是分配了一个整数的内存空间,而 new int[N]却分配了N个整数的连续空间。看来,new[] 比 new “威力更猛”,所以,我们同样得记得:用 new [] 分配出空间,当不在需要时,必须及时调用 delete [] 来释放。
delete [] 语法:
delete [] 指针变量;
如:
//分配了可以存放1000个int的连续内存空间:
int* p = new int[1000];
//然后使用这些空间:
……
//最后不需要了,及时释放:
delete [] p;
20.3.2 new []/ delete[] 示例
在 Windows XP 、Windows NT 或 Windows 2000中,按 Ctrl + Alt + Del (其它操作系统,如Windows98/Me等千万不要按些组合键,否则电脑将重启)。可以调出 Windows 任务管理器,其中要以看出当前粗略的的内存使用量。下面我们结合该工具,写一个程序,先分配100M的内存,再释放。
这是程序代码的抓图:
白话C++
各步运行结果: 程序显示
任务管理器抓图
第一步:分配内存之前
(任务管理显示我的机器使用了207兆的内存) 第二步:分配了100兆的内存
(多出了100M) 第三步:又释放出这100兆
(回到207兆)
注意:使用 new 得来的空间,必须用 delete 来释放;使用 new [] 得来的空间,必须用 delete [] 来释放。彼此之间不能混用。
用 new [] 分配出连续空间后,指针变量“指向”该空间的首地址。 20.3.3 详解指向连续空间的指针
在 通过 new [] 指向连续空间以后,p 就变得和一个一维数组很是类似。我们先来复习一下数组相关知识。
假设是这么一个数组:
int arr[20];
则arr 的内存示意图为(为了不太占用版面我缩小了一点):
(数组 arr 的内存示意)
白话C++
和指针变量相比,数组没有一个单独的内存空间而存放其内存地址。即:指针变量p是一个独立的变量,只不过它的值指向另一段连续的内存空间;而数组arr,本身代表的就是一段连续空间。
如果拿房间来比喻。指针和数组都是存放地址。只不过,指针是你口袋里的那本通讯录上写着的地址,你可以随时改变它的内容,甚至擦除。而数组是你家门楣上钉着的地址,你家原来是“复兴路甲108号”,你绝对不能趁月黑天高,把它涂改为“唐宁街10号”。
数组是“实”的地址,不能改变。当你和定义一个数组,则这个数组就得根据它在内存中的位置,得到一个地址,如上图中的
“0x1A000000”。只要这个数组存在,那么它终生的地址就是这个值。
指针是一个“虚”的地址,可以改变地址的值。当你定义一个指针变量,这个变量占用4个字节的内存,你可以往这4字节的内存写入任意一个值,该值被当成一个内存地址。比如,你可以写入上面的“0x1A000000”,此时,指针p指向第一个元素。也可以改为“0x1A000003”,此时,指针p指向第二个元素。
所以,当p通过 new [] 指向一段连续空间的结果是,p 是一个指向数组的指针,而*p是它所指的数组。
我们来看实例,首先看二者的类似之处。下面左边代码使用数组,右边代码使用指针。
白话C++
当指针变量 P 通过 new [] 指向一连续的内存空间:
1、p[N] 得到第N个元素(0 <= N < 元素个数);
2、*(p + N) 同样得到第N个元素(0 <= N < 元素个数)
如 p[0] 或 *(p + 0) 得到内存空间第0个元素;
把上面右边代码中的大部分 p 替换为 arr,则和左边代码变得一模一样。
白话C++
下面再来比较二者的不同。
白话C++
关于指针本身的 + 和 - 操作,请复习上一章相关内容。
接下来的问题也很重要。
20.4 delete/delete[] 的两个注意点
指针通过 new 或 new[] ,向系统“申请”得到一段内存空间,我们说过,这段内存空间必须在不需要将它释放了。有点像人类社会的终极目标“共产主义”下的“按需分配”。需要了就申请,不需要了,则主动归还。
现在问题就在于这个“主动归还”。当然,指针并不存在什么思想觉悟方面的问题,说光想申请不想归还。真正的问题是,指针在某些方面的表现似乎有些像“花心大萝卜”。请看下面代码,演示令人心酸的一幕。
/*
初始化 p ----- p 的新婚
通过 new ,将一段新建的内存“嫁给”指针p
这一段分配的内存,就是p的原配夫妻
*/
int* p = new int[100];
/*
使用 p ----- 恩爱相处
N 多年恩爱相处,此处略去不表
*/
……
/*
白话C++
p 改变指向 ---- 分手
*/
int girl [100]; //第三者出现
p = girl; //p 就这样指向 girl
/*
delete [] p ---- 落幕前的灾难
终于有一天,p老了,上帝选择在这一时刻
惩罚他
*/
delete [] p;
扣除注释,上面只有4行代码。这4行代码完全符合程序世界的宪法:语法。也就是说对它们进行编译,编译器会认为它们毫无错误,轻松放行。
但在灾难在 delete [] p 时发生。
我们原意是要释放 p 最初通过 new int[100]而得到的内存空间,但事实上,p那时已经指向girl[100]了。结果,第一、最初的空间并没有被释放。第二、girl[100] 本由系统自行释放,现在我们却要强行释放它。
20.4.1 一个指针被删除时,应指向最初的地址
当一个指针通过 +,- 等操作而改变了指向;那么在释放之前,应确保其回到原来的指向。
比如:
白话C++
int* p = new int[3];
*p = 1;
cout << *p << endl;
p++; //p的指向改变了,指向了下一元素
*p = 2;
cout << *p << endl;
//错误的释放:
delete [] p;
在 delete [] p 时,p指向的是第二个元素,结果该释放将产生错位:第一个元素没有被释放,而在最后多删除了一个元素。相当你盖房时盖的是前3间,可以在拆房时,漏了头一间,从第二间开始拆起,结果把不是你盖的第4房间倒给一并拆了。
如何消除这一严重错误呢?
第一种方法是把指针正确地"倒"回原始位置:
p--;
delete [] p;
但当我们的指针指向变化很多次时,在释放前要保证一步不错地一一退回,会比较困难。所以另一方法是在最初时“备份”一份。在释放时,直接释放该指针即可。
int* p = new int[3];
int* pbak = *p; //备份
//移动 p
……
白话C++
//释放:
delete [] pbak;
由于pbak正是指向p最初分配后的地址,我们删除pbak,就是删除p最初的指向。此时我们不能再删除一次p。这也就引出new / delete 及 new[] / delete[] 在本章的最后一个问题。
20.4.2 已释放的空间,不可重复释放
第一种情况,错了最直接:
int* p = new int(71);
cout << *p << endl;
delete p; //OK!
delete p; //ERROR! 重复删除p
当然,如果同一指针在delete之后,又通过new 或 new[] 分配了一次内存,则需要再删除一次:
int* p = new int(71);
cout << *p << endl;
delete p; //OK!
...
p = new int(81);
delete p; //OK!
...
p = new int[10];
for (int i=0; i<10; i++)
正在阅读:
第20章 指针 二 为指针分配和释放空间04-22
小学生二年级观赏牡丹花作文06-13
护士长个人年终工作总结优秀8篇07-30
我的不平凡老师作文800字07-16
我的未来一天作文500字07-06
乡镇委员会年度工作总结及下一步工作规划08-02
难忘的生日小学生一年级作文06-14
第四章、形容词和副词doc03-17
2011年度危险源辨识12-14
- 教学能力大赛决赛获奖-教学实施报告-(完整图文版)
- 互联网+数据中心行业分析报告
- 2017上海杨浦区高三一模数学试题及答案
- 招商部差旅接待管理制度(4-25)
- 学生游玩安全注意事项
- 学生信息管理系统(文档模板供参考)
- 叉车门架有限元分析及系统设计
- 2014帮助残疾人志愿者服务情况记录
- 叶绿体中色素的提取和分离实验
- 中国食物成分表2020年最新权威完整改进版
- 推动国土资源领域生态文明建设
- 给水管道冲洗和消毒记录
- 计算机软件专业自我评价
- 高中数学必修1-5知识点归纳
- 2018-2022年中国第五代移动通信技术(5G)产业深度分析及发展前景研究报告发展趋势(目录)
- 生产车间巡查制度
- 2018版中国光热发电行业深度研究报告目录
- (通用)2019年中考数学总复习 第一章 第四节 数的开方与二次根式课件
- 2017_2018学年高中语文第二单元第4课说数课件粤教版
- 上市新药Lumateperone(卢美哌隆)合成检索总结报告
- 指针
- 分配
- 释放
- 空间
- 海利普HLP-SK变频器助力螺杆空压机节能减排
- 第2章作业参考答案
- 西南财经大学成人高等教育2009线性代数B
- 活性污泥_生物膜法系统的脱氮除磷效果研究
- (人教新课标)四年级数学课件 统计图
- 提高急腹症预检分诊准确性的探讨
- 电力电子技术论文1
- 参考文献著录规则实行新的国家标准
- (创新设计)2014-2015学年高二语文语文版选修《中外现代诗歌欣赏
- 小学综合实践活动课程评价标准
- 某大型甲级设计院电气设计2012年图纸抽查问题探讨
- 基于单片机的数字秒表的设计与实现
- 基因检测的营销策划方案
- 理工科类毕业设计(论文)格式模板
- 酒店管理专业《人力资源管理》教学大纲
- 七lesson_34_steven's_report
- Java连接mysql数据库源代码
- 高中生汉式英语成因分析及对策的研究
- 2012汕头高考二模英语试卷
- 2014届北京石景山区高三上期末考试英语试题