📄 第20章 指针二 为指针分配和释放空间.htm
字号:
lang=zh-cn>则程序无法通过编译,报错:“不能将</SPAN> void* <SPAN lang=zh-cn>赋值给</SPAN> int
*<SPAN lang=zh-cn> 类型变量”。所以必须通过</SPAN> <B>(int *)<SPAN lang=zh-cn>
</SPAN></B><SPAN lang=zh-cn>来将强制转换。</SPAN></P>
<P><SPAN lang=zh-cn>第二、函数的实参为 </SPAN>sizeof(int) <SPAN
lang=zh-cn>,用于指明一个整型数据需要的大小。如果你写成:</SPAN></P>
<P> </P>
<P>int* p = (int *) malloc (1);</P>
<P><SPAN
lang=zh-cn>代码也能通过编译,但事实上只分配了1个字节大小的内存空间,当你往里头存入一个整数,就会有3个字节无家可归,而直接“住进邻居家”!造成的结果是后面的内存中原有数据内容全部被清空。</SPAN></P>
<P> </P>
<P>malloc <SPAN lang=zh-cn>也可以达到</SPAN> new [] <SPAN
lang=zh-cn>的效果,申请出一段连续的内存,方法无非是指定你所需要内存大小。</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>比如想分配100个</SPAN>int<SPAN lang=zh-cn>类型的空间:</SPAN></P>
<P> </P>
<P>int* p = (int *) malloc ( sizeof(int) * 100 ); //<SPAN
lang=zh-cn>分配可以放得下100个整数的内存空间。</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>另外有一点不能直接看出的区别是,</SPAN>malloc <SPAN
lang=zh-cn>只管分配内存,并不能对所得的内存进行初始化,所以得到的一片新内存中,其值将是随机的。</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>除了分配及最后释放的方法不一样以外,通过</SPAN>malloc<SPAN
lang=zh-cn>或new得到指针,在其它操作上保持一致。</SPAN></P>
<P> </P>
<H4><B><A name=20.5.2>20.5.2</A> <SPAN lang=zh-cn>释放内存 </SPAN>free<SPAN
lang=zh-cn> 函数</SPAN></B></H4>
<P> </P>
<P><SPAN lang=zh-cn>需要包含头文件</SPAN>(<SPAN lang=zh-cn>和</SPAN> malloc <SPAN
lang=zh-cn>一样</SPAN>)<SPAN lang=zh-cn>:</SPAN></P>
<P>#include <alloc.h></P>
<P><SPAN lang=zh-cn>或</SPAN></P>
<P>#include <stdlib.h></P>
<P> </P>
<P><SPAN lang=zh-cn>函数声明:</SPAN></P>
<P><SPAN lang=zh-cn>void free(void *block);</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>即:</SPAN> void free(<SPAN lang=zh-cn>指针变量</SPAN>)<SPAN
lang=zh-cn>;</SPAN></P>
<P><SPAN lang=zh-cn>之所以把形参中的指针声明为</SPAN> void* <SPAN
lang=zh-cn>,是因为</SPAN>free<SPAN
lang=zh-cn>必须可以释放任意类型的指针,而任意类型的指针都可以转换为</SPAN>void *<SPAN
lang=zh-cn>。</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>举例:</SPAN></P>
<P> </P>
<P>int* p = (int *) malloc(4); </P>
<P> </P>
<P>*p = 100;</P>
<P> </P>
<P>free(p); //<SPAN lang=zh-cn>释放</SPAN> p <SPAN
lang=zh-cn>所指的内存空间</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>或者:</SPAN></P>
<P> </P>
<P>int* p = (int *) malloc ( sizeof(int) * 100 ); //<SPAN
lang=zh-cn>分配可以放得下100个整数的内存空间。</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>……</SPAN></P>
<P> </P>
<P>free(p);</P>
<P> </P>
<P>free <SPAN lang=zh-cn>不管你的指针指向多大的空间</SPAN>,<SPAN
lang=zh-cn>均可以正确地进行释放,这一点释放比</SPAN> delete/delete [] <SPAN
lang=zh-cn>要方便。不过,必须注意,如果你在分配指针时,用的是</SPAN>new<SPAN
lang=zh-cn>或</SPAN>new[]<SPAN
lang=zh-cn>,那么抱歉,当你在释放内存时,你并不能图方便而使用</SPAN>free<SPAN
lang=zh-cn>来释放。反过来,你用</SPAN>malloc <SPAN
lang=zh-cn>分配的内存,也不能用</SPAN>delete<SPAN lang=zh-cn>/de</SPAN>lete[] <SPAN
lang=zh-cn>来释放。一句话,</SPAN>new/delete<SPAN
lang=zh-cn>、</SPAN>new[]/delete[]<SPAN lang=zh-cn>、</SPAN>malloc/free<SPAN
lang=zh-cn> 三对均需配套使用,不可混用!</SPAN></P>
<P> </P>
<P>int* p = new int[100];</P>
<P>... ...</P>
<P>free(p); //ERROR!<SPAN lang=zh-cn> p 是由</SPAN>new <SPAN
lang=zh-cn>所得。</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>这也是我们必须学习 </SPAN>malloc <SPAN lang=zh-cn>与</SPAN> free
<SPAN lang=zh-cn>的重要理由之一,有时候,我们调用操作系统的函数(</SPAN>Windows <SPAN
lang=zh-cn>API)时,会遇到由我们的程序来分配内存,API函数来释放内存;或API函数来分配内存,而我们的程序来负责释放,这时,必须用</SPAN>malloc<SPAN
lang=zh-cn>或</SPAN>free<SPAN lang=zh-cn>来进行相应的工作。</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>当然,保证所说的内存分配与释放方式不匹配的错误发生,</SPAN>Windows API<SPAN
lang=zh-cn>函数也提供了一套专门的内存管理函数给程序员</SPAN>,<SPAN
lang=zh-cn>为了不在这一章里放太多相混的内容,我们在</SPAN>Windows<SPAN
lang=zh-cn>编程的课程再讲相关内容。</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>最后还有一个函数,也是我们要学习C方式的内存管理函数的原因。</SPAN></P>
<P> </P>
<H4><B><A name=20.5.3>20.5.3</A> <SPAN lang=zh-cn>重</SPAN>调空间的<SPAN
lang=zh-cn>大小</SPAN>: <SPAN lang=en-us>realloc </SPAN>函数</B></H4>
<P> </P>
<P><SPAN lang=zh-cn>需要包含头文件</SPAN>(<SPAN lang=zh-cn>和</SPAN> malloc <SPAN
lang=zh-cn>一样</SPAN>)<SPAN lang=zh-cn>:</SPAN></P>
<P>#include <alloc.h></P>
<P><SPAN lang=zh-cn>或</SPAN></P>
<P>#include <stdlib.h></P>
<P> </P>
<P><SPAN lang=zh-cn>函数声明:</SPAN></P>
<P>void *realloc(void *block, <SPAN lang=en-us>int</SPAN> size);</P>
<P> </P>
<P><SPAN lang=en-us>block </SPAN>是指向要扩张或缩小的内存空间的指针。<SPAN
lang=en-us>size</SPAN> 指定新的大小。</P>
<P> </P>
<P><SPAN lang=en-us>realloc </SPAN>可以对给定的指针所指的空间进行扩大或者缩小。<SPAN
lang=en-us>size </SPAN>是新的目标大小。比如,原来空间大小是40个字节,现在可以将<SPAN lang=en-us>size
</SPAN>指定为60,这样就扩张了20个字节;或者,将<SPAN lang=en-us>size
</SPAN>指定为20,则等于将空间缩小了20个字节。</P>
<P> </P>
<P>无论是扩张或是缩小,原有内存的中内容将保持不变。当然,对于缩小,则被缩小的那一部分的内容会丢失。</P>
<P> </P>
<P>举例:</P>
<P> </P>
<P><SPAN lang=en-us>/</SPAN>/先用<SPAN lang=en-us> malloc </SPAN>分配一指针</P>
<P><SPAN lang=en-us>int* p = (int *) malloc (sizeof(int) * 10);
//</SPAN>可以存放10个整数</P>
<P> </P>
<P>……</P>
<P><SPAN lang=en-us>//</SPAN>现在,由于些某原因,我们需要向p所指的空间中存放15个整数</P>
<P>//原来的空间不够了:</P>
<P><SPAN lang=en-us>p = (int *) realloc (p, sizeof(int) *15);
//</SPAN>空间扩张了<SPAN lang=en-us> (15 - 10) * sizeof(int) = 20
</SPAN>个字节</P>
<P> </P>
<P>……</P>
<P> </P>
<P><SPAN lang=en-us>//</SPAN>接下来,我们决定将p所指内存空间紧缩为5个整数的大小:</P>
<P><SPAN lang=en-us>p = (int *) realloc (p, sizeof(int) * 5);
//</SPAN>缩小了<SPAN lang=en-us> (15 - 5) * sizeof(int) = 40 </SPAN>个字节</P>
<P> </P>
<P>……</P>
<P> </P>
<P><SPAN lang=en-us>free (p);</SPAN></P>
<P> </P>
<P>这么看起来,<SPAN lang=en-us>realloc
</SPAN>有点像是施工队对一个已建的房屋进行改修:可以将房间后面再扩建几间,也可以拆掉几间。不管是扩还是拆,屋里原来的东西并不改变。</P>
<P>不过,这里要特别提醒一点:这个施工队有时会做这种事:1、在一块新的空地上新建一座指定大小的房屋;2、接着,将原来屋子里的东西原样照搬到新屋;3、拆掉原来的屋子。</P>
<P>这是什么指意呢?</P>
<P><B><SPAN lang=en-us>realloc
</SPAN>并不保证调整后的内存空间和原来的内存空间保持同一内存地址。相反,<SPAN lang=en-us>realloc
</SPAN>返回的指针很可能指向一个新的地址。</B></P>
<P>所以,在代码中,我们必须将<SPAN lang=en-us>realloc</SPAN>返回的值,重新赋值给<SPAN lang=en-us>
p :</SPAN></P>
<P> </P>
<P><SPAN lang=en-us>p = (int *) realloc (p, sizeof(int) *15);</SPAN></P>
<P> </P>
<P> </P>
<P>甚至,你可以传一个空指针(0)给<SPAN lang=en-us> realloc </SPAN>,则此时<SPAN
lang=en-us>realloc </SPAN>作用完全相当于<SPAN lang=en-us>malloc</SPAN>。</P>
<P> </P>
<P><SPAN lang=en-us>int* p = (int *) realloc (<B>0</B>,sizeof(int) *
10); //</SPAN>分配一个全新的内存空间,</P>
<P> </P>
<P>这一行,作用完全等同于:</P>
<P> </P>
<P><SPAN lang=en-us>int* p = (int *) malloc(sizeof(int) * 10); </SPAN></P>
<P> </P>
<H4><B><SPAN lang=zh-cn><A name=20.5.4>20.5.4</A> </SPAN><SPAN
lang=en-us>malloc</SPAN>、<SPAN lang=en-us>realloc</SPAN>、<SPAN
lang=en-us>free</SPAN>的例子</B></H4>
<P> </P>
<P>打开CB6,新建一空白控制台工程。</P>
<P> </P>
<P>第一步:在<SPAN lang=en-us> Unit1.cpp </SPAN>中的最前面,加入引用<SPAN lang=en-us>
alloc.h</SPAN> 等头文件的代码:</P>
<P> </P>
<P>……</P>
<P>#pragma hdrstop</P>
<P><B>#include <alloc.h><SPAN lang=en-us>
//</SPAN>三个函数的声明都这个头文件里</B></P>
<P><B><SPAN lang=en-us>#include <iostream.h> </SPAN></B></P>
<P>……</P>
<P> </P>
<P>第二步:将以下代码加入主函数<SPAN lang=en-us> main</SPAN> 中间:</P>
<P> </P>
<P>int* p = (int *) malloc (sizeof(int) * 10);</P>
<P> </P>
<P>cout << "realloc 之前p指向的内存地址: " << p << endl;</P>
<P> </P>
<P>for (int i=0; i<10; i++)</P>
<P>{</P>
<P><SPAN lang=en-us> </SPAN>p[i] = i + 1;</P>
<P>}</P>
<P> </P>
<P>cout << "realloc 之前p指向的内存中的内容:" << endl;</P>
<P> </P>
<P>for (int i=0; i<10; i++)</P>
<P>{</P>
<P><SPAN lang=en-us> </SPAN>cout << p[i] <<
",";</P>
<P><SPAN lang=en-us>}</SPAN></P>
<P>cout << endl;</P>
<P> </P>
<P>p = (int *) realloc (p, sizeof(int) * 15);</P>
<P> </P>
<P>cout << "realloc 之后p指向的内存地址: " << p << endl;
<P>
<P>
<P>cout << "realloc 之后p指向的内存中的内容:" << endl;
<P>
<P>for (int i=0; i<15; i++)
<P>{
<P> cout << p[i] << ",";
<P>}
<P>cout << endl;
<P>
<P>
<P>free (p);
<P>
<P>
<P>system("PAUSE");
<P> </P>
<P> </P>
<P>运行结果:</P>
<P align=center><IMG height=118
src="第20章 指针二 为指针分配和释放空间.files/ls20.h12.gif" width=396 border=0></P>
<P align=center><SPAN lang=en-us>(malloc, realloc, free </SPAN>上机<SPAN
lang=zh-cn>题</SPAN><SPAN lang=en-us>)</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>从图中我们看到 </SPAN>realloc<SPAN lang=zh-cn>
前后的p指向的内存地址同样是</SPAN> 9647936 <SPAN
lang=zh-cn>。但记住,这并不是结论,真正的结论我们已经说过“</SPAN>realloc <SPAN
lang=zh-cn><B>并不保证</B>返回和原来一样的地址。”所谓的“并不保证”的意思是:“我尽力去做了,但仍然有可能做不到。”。</SPAN></P>
<P> </P>
<P><SPAN lang=zh-cn>无论调用几次</SPAN> realloc,<SPAN lang=zh-cn>最后我们只需一次</SPAN>
free<SPAN lang=zh-cn>。</SPAN></P></TD></TR>
<TR>
<TD
style="FONT-SIZE: 10pt; TEXT-INDENT: 20px; LINE-HEIGHT: 150%; FONT-FAMILY: ËÎÌå"
width="100%" height=37> </TD></TR></TBODY></TABLE></CENTER></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -