分享

new,delete和指针

 冉亮 2010-07-14

20.1 理解指针的两种改变

普通变量(非指针,简单类型变量)只能改变值:

1) int a = 100;

2) ...

3) a = 200; 

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 改变指针所指的变量的值

复习前一章,我们知道通过 * (地址解析符),可以得到、或改变指针所指的变量的值。

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指向的变量;右值是普通的值。

理解,区分对指针的两种改变,才能学会如何使用指针。

请思考:上一章讲的指针的加减操作,是对指针的哪一种改变? 

最后需要说明,严格意义上,指针仍然只有一种改变,即改变指针本身的值。改变指针指向的变量,应视为对另一变量的改变,只不过在代码上,它通过指针来进行,而不是直接对另一变量进行操作。

为指针分配、释放内存空间

之前,我们给指针下的定义是指针是一个变量,它存放的值是另一个变量的地址

比如:

int a;

int* p = &a;

看,a 就是另一个变量p指向了a

我们知道,变量总是要占用一定的内存空间,比如上面的a,就占用了4个字节(sizeof(int))。这四个字节属于谁?当然属于变量a,而不是p

现在要讲的是:也可以单独为指针分配一段新的内存空间。这一段内容不属于某个变量。

20.2C++方式的内存分配与释放 new delete

在内存管理上,C++ C 有着完全不同的两套方案。当然,C++的总是同时兼容CC的那一套方案在C++里同样可行。

我们首先看看纯C++的那一套: new delete

new ,从字面上看意思为 ;而delete 字面意思为删除。二者在C++中内存管理中大致的功能,应是一个为新建,一个为删除

20.2.1new

new c++的一个关键字。被当作像 +-* / 一样的操作符。它的操作结果是在申请到一段指定数据类型大小的内存。

语法:

指针变量 = new数据类型;

new将做三件事: 

1、主动计算指定数据类型需要的内存空间大小;

2、返回正确的指针类型;

3、在分配内存的一,将按照语法规则,初始化所分配的内存。

这是什么意思呢?看看例子吧:

int* p;

p = new int;

和以往不一样,p 这回不再寄人篱下,并不是指向某个已存在的变量,而是直接指向一段由new分配而来的新内存空间。

p指向一段由new分配而来的新内存空间 这句话等同于:

new分配一段新的内存空间,然后将该内存空间的地址存入到变量p中。

所以,最终p中仍然是存储了一个变量的地址,只是,这是一个无名变量。

指向原有的某个变量,和指向一段新分配的内存空间,有什么区别呢?

原有的变量,可以比喻成指向一间原有的并且有主的房间。而新分配的内存空间,则像是一个临时建筑物。我们必须在不用它的时候,主动将它拆迁。拆迁的工作由delete来完成。

当指针变量通过 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指针变量;

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)

第二步:

接下来我们来观察指针变量被delete之后,所指向的内存会是什么。但,这是一件犯了CC++编程大忌的事:访问一个已经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就一个字:拆!

请大家自行在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;

*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个字节。

图示为:


(
指针变量p指向一段连续的内存空间)

new int只是分配了一个整数的内存空间,而 new int[N]却分配了N个整数的连续空间。看来,new[] new 威力更猛,所以,我们同样得记得:用 new [] 分配出空间,当不在需要时,必须及时调用 delete [] 来释放。

delete [] 语法:

delete [] 指针变量;

如:

//分配了可以存放1000int的连续内存空间:

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的内存,再释放。

这是程序代码的抓图:

 

 

各步运行结果:

程序显示

任务管理器抓图

第一步:分配内存之前

 

(任务管理显示我的机器使用了207兆的内存)

第二步:分配了100兆的内存

 

(多出了100M)

第三步:又释放出这100

 

(回到207)

 

注意:使用 new 得来的空间,必须用 delete 来释放;使用 new [] 得来的空间,必须用 delete [] 来释放。彼此之间不能混用。

new [] 分配出连续空间后,指针变量指向该空间的首地址。

20.3.3 详解指向连续空间的指针

通过 new []指向连续空间以后,p 就变得和一个一维数组很是类似。我们先来复习一下数组相关知识。

假设是这么一个数组:

int arr[20];

arr的内存示意图为(为了不太占用版面我缩小了一点):

 


(
数组 arr的内存示意) 

和指针变量相比, 数组没有一个单独的内存空间而存放其内存地址。即:指针变量p是一个独立的变量,只不过它的值指向另一段连续的内存空间;而数组arr,本身代表的就是一段连续空间。

如果拿房间来比喻。指针和数组都是存放地址。只不过,指针是你口袋里的那本通讯录上写着的地址,你可以随时改变它的内容,甚至擦除。而数组是你家门楣上钉着的地址,你家原来是复兴路甲108,你绝对不能趁月黑天高,把它涂改为唐宁街10

数组是的地址,不能改变。当你和定义一个数组,则这个数组就得根据它在内存中的位置,得到一个地址,如上图中的0x1A000000。只要这个数组存在,那么它终生的地址就是这个值。

指针是一个的地址,可以改变地址的值。当你定义一个指针变量,这个变量占用4个字节的内存,你可以往这4字节的内存写入任意一个值,该值被当成一个内存地址。比如,你可以写入上面的0x1A000000,此时,指针p指向第一个元素。也可以改为0x1A000003,此时,指针p指向第二个元素。

所以,当p通过 new []指向一段连续空间的结果是,p 是一个指向数组的指针,而*p是它所指的数组。

我们来看实例,首先看二者的类似之处。下面左边代码使用数组,右边代码使用指针。

 

数组

指针 (通过 new []所得)

//定义:

int arr[20];

//定义:

int* p = new int[20];

 

//让第一个元素值为100

arr[0] = 100;

 

//让第一个元素值为100

p[0] = 100;

//让后面19个元素值分别为其前一元素加 50

for (int i = 1; i < 20; i++)

{

   arr[i] = arr[i-1] + 50;

}

//让后面19个元素值分别为其前一元素加 50

for (int i = 1; i < 20; i++)

{

   p[i] = p[i-1] + 50;

}

//输出所有元素:

for (int i = 0; i < 20; i++)

{

  cout << arr[i] << endl;

}

//输出所有元素:

for (int i = 0; i < 20; i++)

{

  cout << p[i] << endl;

}

//也可以不用[],而通过+号来得到指定元素:

//当然,对于数组,更常用的还是 [] 操作符。

cout << *(arr + 0) << endl; 

//*(arr+0)等于 *arr

cout << *(arr + 1) << endl;

cout << *(arr + 1) << endl;

 

输出结果:

 100

 150

 200

//也可以不用[],而通过+号来得到指定元素:

//其实,对于指针,这样的+-操作用得还要多点。

cout << *(p + 0) << endl;

 //*(p + 0)等于 *p

cout << *(p + 1) << endl;

cout << *(p + 1) << endl;

 

输出结果:

 100

 150

 200

 

 

当指针变量 P 通过 new []指向一连续的内存空间:

1p[N]得到第N个元素 0 <=N <元素个数);

2*(p + N)同样得到第N个元素 0 <=N <元素个数)

p[0] *(p + 0)得到内存空间第0个元素;

把上面右边代码中的大部分 p替换为 arr,则和左边代码变得一模一样。

下面再来比较二者的不同。 

数组

指针

//定义并且初始化:int arr[20]= {0,1,2,3,4,5,6,7,8,9,0,……,19};

 

//定义、并且生成空间,但不能直接初始空间的内容:

int* p = new int[20] {0,1,2,3,4……} // !

 

//只得通过循环一个个设置:

for (int i = 0;  i < 20; i++)

{

   p[i] = i;

}

//不能通过对数组本身 + - 来改变数组的位置:

arr = arr + 1;  //!

cout << *arr << endl;

 

arr++;  //!

cout << *arr << endl;

 

arr--;  //!

cout << *arr << endl;

 

输出结果:

无,因为程序有语法错误,通不过编译。

//可以通过 + - 操作直接改变指针:

p = p + 1;

cout << *p << endl;

 

p++;

cout << *p << endl;

 

p--;

cout << *p << endl;

 

输出结果:

 1

 2

 1

//释放空间:

//数组所带的空间由系统自动分配及回收

//无须也无法由程序来直接释放。

//释放空间:

//指向连续空间的指针,必须使用delete [] 来释放

delete [] p;

 

关于指针本身的 + - 操作,请复习上一章相关内容。

接下来的问题也很重要。

20.4 delete/delete[] 的两个注意点

指针通过 new new[] ,向系统申请得到一段内存空间,我们说过,这段内存空间必须在不需要将它释放了。有点像人类社会的终极目标共产主义下的按需分配。需要了就申请,不需要了,则主动归还。

现在问题就在于这个主动归还。当然,指针并不存在什么思想觉悟方面的问题,说光想申请不想归还。真正的问题是,指针在某些方面的表现似乎有些像花心大萝卜。请看下面代码,演示令人心酸的一幕。

/*

  初始化 p  ----- p 的新婚

  通过 new ,将一段新建的内存嫁给指针p

  这一段分配的内存,就是p的原配夫妻

*/

int* p = new int[100];

/*

   使用 p  ----- 恩爱相处

   N 多年恩爱相处,此处略去不表

*/

……

/*

   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 一个指针被删除时,应指向最初的地址

当一个指针通过 +,- 等操作而改变了指向;那么在释放之前,应确保其回到原来的指向。

比如:

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

……

//释放:

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++)

  *p = i;

...

delete [] p; //OK!

上面代码中,共计三次对p进行delete delete[],但不属于重复删除。因为每次delete都对应一次新的new

我们下面所说的例子,均指一次delete之后,没有再次new,而重复进行delete

第二种情况,重复删除同一指向的多个指针

int* p1 = new int(71);

int* p2 = p1;   //p2p1 现在指向同一内存地址

cout << *p1 << endl;

cout << *p2 << endl; 

delete p1;  //OK

delete p2;  //ERROR! p2所指的内存,已通过delete p1而被释放,不可再delete一次。

同样的问题,如果你先删除了p2,则同样不可再删除p1

...

delete p2; //OK

delete p1; //ERROR

第三种情况,删除指向某一普通变量的指针

int a = 100;

int* p = &a;

delete p;  //ERROR

p 不是通过new 得到新的内存空间,而是直接指向固定变量:a。所以删除p等同要强行剥夺a的固有空间,会导致出错。

20.5 C 方式的内存管理

new/delete只在C++里得到支持。在C里,内存管理是通过专门的函数来实现。另外,为了兼容各种编程语言,操作系统提供的接口通常是 C 语言写成的函数声明 Windows 本身也由C和汇编语言写成)。这样,我们就不得不同时学习C的内存管理函数。

20.5.1 分配内存 malloc 函数

需要包含头文件:

#include <alloc.h>

#include <stdlib.h>

函数声明(函数原型)

void *malloc(int size);

说明:malloc 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。

从函数声明上可以看出。malloc new 至少有两个不同: new 返回指定类型的指针,并且可以自动计算所需要大小。比如:

int *p;

p = new int; //返回类型为int* 类型(整数型指针),分配大小为 sizeof(int);

或:

int* parr;

parr = new int [100];  //返回类型为 int* 类型(整数型指针),分配大小为

sizeof(int) * 100;

malloc 则必须由我们计算要字节数,并且在返回后强行转换为实际类型的指针。

int* p;

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

第一malloc 函数返回的是 void * 类型,如果你写成:p = malloc (sizeof(int)); 则程序无法通过编译,报错:不能将 void* 赋值给 int * 类型变量。所以必须通过 (int *) 来将强制转换。

第二、函数的实参为sizeof(int) ,用于指明一个整型数据需要的大小。如果你写成:

int* p = (int *) malloc (1);

代码也能通过编译,但事实上只分配了1个字节大小的内存空间,当你往里头存入一个整数,就会有3个字节无家可归,而直接住进邻居家!造成的结果是后面的内存中原有数据内容全部被清空。

malloc 也可以达到 new [] 的效果,申请出一段连续的内存,方法无非是指定你所需要内存大小。

比如想分配100int类型的空间:

int* p = (int *) malloc ( sizeof(int) * 100 ); //分配可以放得下100个整数的内存空间。

另外有一点不能直接看出的区别是,malloc 只管分配内存,并不能对所得的内存进行初始化,所以得到的一片新内存中,其值将是随机的。

除了分配及最后释放的方法不一样以外,通过mallocnew得到指针,在其它操作上保持一致。

20.5.2 释放内存free 函数

需要包含头文件( malloc 一样)

#include <alloc.h>

#include <stdlib.h>

函数声明:

void free(void *block);

即: void free(指针变量)

之所以把形参中的指针声明为 void* ,是因为free必须可以释放任意类型的指针,而任意类型的指针都可以转换为void *

举例:

int* p = (int *) malloc(4);

*p = 100;

free(p); //释放 p 所指的内存空间

或者:

int* p = (int *) malloc ( sizeof(int) * 100 ); //分配可以放得下100个整数的内存空间。

……

free(p);

free 不管你的指针指向多大的空间,均可以正确地进行释放,这一点释放比 delete/delete [] 要方便。不过,必须注意,如果你在分配指针时,用的是newnew[],那么抱歉,当你在释放内存时,你并不能图方便而使用free来释放。反过来,你用malloc 分配的内存,也不能用delete/delete[] 来释放。一句话,new/deletenew[]/delete[]malloc/free 三对均需配套使用,不可混用!

int* p = new int[100];

... ...

free(p);  //ERROR! p 是由new 所得。

这也是我们必须学习malloc free 的重要理由之一,有时候,我们调用操作系统的函数(Windows API)时,会遇到由我们的程序来分配内存,API函数来释放内存;或API函数来分配内存,而我们的程序来负责释放,这时,必须用mallocfree来进行相应的工作。

当然,保证所说的内存分配与释放方式不匹配的错误发生,Windows API函数也提供了一套专门的内存管理函数给程序员,为了不在这一章里放太多相混的内容,我们在Windows编程的课程再讲相关内容。

最后还有一个函数,也是我们要学习C方式的内存管理函数的原因。

20.5.3 重调空间的大小: realloc函数

需要包含头文件( malloc 一样)

#include <alloc.h>

#include <stdlib.h>

函数声明:

void *realloc(void *block, int size);

block是指向要扩张或缩小的内存空间的指针。size 指定新的大小。

realloc可以对给定的指针所指的空间进行扩大或者缩小。size是新的目标大小。比如,原来空间大小是40个字节,现在可以将size指定为60,这样就扩张了20个字节;或者,将size指定为20,则等于将空间缩小了20个字节。

无论是扩张或是缩小,原有内存的中内容将保持不变。当然,对于缩小,则被缩小的那一部分的内容会丢失。

举例:

//先用 malloc分配一指针

int* p = (int *) malloc (sizeof(int) * 10);  //可以存放10个整数

……

//现在,由于些某原因,我们需要向p所指的空间中存放15个整数

//原来的空间不够了:

p = (int *) realloc (p, sizeof(int) *15); //空间扩张了 (15 - 10) * sizeof(int) = 20个字节

……

//接下来,我们决定将p所指内存空间紧缩为5个整数的大小:

p = (int *) realloc (p, sizeof(int) * 5); //缩小了 (15 - 5) * sizeof(int) = 40个字节

 

free (p);

这么看起来,realloc有点像是施工队对一个已建的房屋进行改修:可以将房间后面再扩建几间,也可以拆掉几间。不管是扩还是拆,屋里原来的东西并不改变。

不过,这里要特别提醒一点:这个施工队有时会做这种事:1、在一块新的空地上新建一座指定大小的房屋;2、接着,将原来屋子里的东西原样照搬到新屋;3、拆掉原来的屋子。

这是什么指意呢?

realloc并不保证调整后的内存空间和原来的内存空间保持同一内存地址。相反,realloc返回的指针很可能指向一个新的地址。

所以,在代码中,我们必须将realloc返回的值,重新赋值给 p :

p = (int *) realloc (p, sizeof(int) *15);

甚至,你可以传一个空指针(0)给 realloc,则此时realloc作用完全相当于malloc

int* p = (int *) realloc (0,sizeof(int) * 10);  //分配一个全新的内存空间,

这一行,作用完全等同于:

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

20.5.4mallocreallocfree的例子

打开CB6,新建一空白控制台工程。

第一步:在 Unit1.cpp中的最前面,加入引用 alloc.h 等头文件的代码:

……

#pragma hdrstop

#include <alloc.h> //三个函数的声明都这个头文件里

#include <iostream.h>

……

第二步:将以下代码加入主函数 main 中间:

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

cout << "realloc 之前p指向的内存地址: " << p << endl;

for (int i=0; i<10; i++)

{

  p[i] = i + 1;

}

cout << "realloc 之前p指向的内存中的内容:" << endl;

for (int i=0; i<10; i++)

{

  cout << p[i] << ",";

}

cout << endl;

p = (int *) realloc (p, sizeof(int) * 15);

cout << "realloc 之后p指向的内存地址: " << p << endl;

cout << "realloc 之后p指向的内存中的内容:" << endl;

for (int i=0; i<15; i++)

{

   cout << p[i] << ",";

}

cout << endl;

free (p);

system("PAUSE");

运行结果:

 

(malloc, realloc, free上机题)

从图中我们看到realloc 前后的p指向的内存地址同样是 9647936 。但记住,这并不是结论,真正的结论我们已经说过realloc 并不保证返回和原来一样的地址。所谓的并不保证的意思是:我尽力去做了,但仍然有可能做不到。

无论调用几次 realloc,最后我们只需一次 free

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多