读书人

示例讨论 c++ 中 new 初始化位置。 附

发布时间: 2012-04-10 21:03:56 作者: rapoo

示例讨论 c++ 中 new 初始化位置。 附有代码,近来看看,讨论一下啊!
代码如下

struct Node
{
int data;
}; //自定义结构

void initNode(Node* n, int d);
void f1();

//main 函数
int _tmain(int argc, _TCHAR* argv[])
{
f1();

char c;
cin > > c;
return 0;
}//main

void initNode(Node* n, int d)
{
//n = new Node(); //(1)
n-> data = d;
}

void f1()
{
Node* newNode = NULL;
newNode = new Node(); //(2)

initNode(newNode, 1);

cout < < newNode-> data < < endl;
}

上述代码,运行正常

但,若将(1)处取消注释,(2)处注释
(也就是 newNode = new Node(); 放的位置不同)
则运行时错误。

这个问题该如何理解呢?

[解决办法]
要把
void initNode(Node* n, int d)
改成
void initNode(Node* &n, int d)
[解决办法]
函数参数默认是按值传递的,所以尽管initNode()中将new Node()赋给n,但f1()中的newNode不会变,还是NULL。改成按引用传递后,才会同时改变newNode。
[解决办法]
变量的作用域问题...如2楼兄台所说...

你在initNode()函数中的赋值只能在该函数中使用...出了该函数该地址的数据将被销毁...除非使用引用或其它方法将该地址的数据保存下来...
[解决办法]
1、initNode()中new出来的内存确实不会自动释放,必须手动释放。
2、这个理解是这样的,在函数按值传递的时候,是有一份临时的参数,在这里我把你定义的p的临时变量定义为_p,在new的时候,其实把你的首地址交给了_p,而原先的p依然是以前所指定的那个值,所以当离开的时候,你的p是没有任何变化的,导致出现了上面的错误。
[解决办法]
建议再看看传值和传址的区别,搞懂就明白了
[解决办法]
1、按值传递与按址传递
2、变量的生存期与作用域
[解决办法]
这样哈:
void fun(int arg)
{
arg = 100;
}

则:
int para = 10;

fun(para);

那么:para还是为10;

同样:
void funp(int * p)
{
p = new ... //将一段地址给了p;
}

有:
int * param = NULL //param 现在的值是NULL

那么,
funp(p)以后:
param 的值还是一个NULL哦

[解决办法]
以你这个你认为正常的程序来看,其实并不正常!

可以这样证明,在你的Node中加入一个析构函数,例如:

struct Node
{
int data;
~Node(void)//如果Node被析构,屏幕输出将显示 "析构Node! "。
{
cout < < "析构Node! " < < endl;
}
};

事实上在你的上述程序执行中至结束,你都看不到Node被析构,但你是应该看到屏幕输出 "析构Node! "的。这证明在你的程序中,Node根本没有被解构,内存泄漏了!

其次如你所说: "但,若将(1)处取消注释,(2)处注释 ",则你的f1()函数将如下:

void f1()
{
Node* newNode = NULL;//正确的习惯,初始化指针为空;

initNode(newNode, 1);//newNode指针值本身是值传递!
cout < < newNode-> data < < endl;//这而仍在使用空指针!
}
也就是说你提到的运行时错误产生自上述f1()函数的最后一个语句:

cout < < newNode-> data < < endl;//这而仍在使用空指针!

使用空指针当然会产生运行时错误!
事实上,在我的VC7.1上该语句产生运行时错误: "读取位置 0x00000000 时发生访问冲突 。 "

另外,仍然有在堆上创建对象,却没有释放堆空间,造成内存资源泄漏的问题!

正确的修改你的程序如下:

struct Node
{
int data;
~Node(void)//这个析构函数纯粹为了演示析构而设!
{
cout < < "析构Node! " < < endl;


}
};//自定义结构

void initNode(Node* &n, int d);//修改:第一参数是Node型指针的引用形参;
void f1();

//main 函数
int _tmain(int argc, _TCHAR* argv[])
{
f1();

_PAUSE;//这是一个利于观察演示结果的宏;
return 0;
}//main
/*
如下修改后的第一形参将接受一个Node指针的引用而不是Node指针的值,
  这样既可以避免临时对象的产生,在函数内部又可以修改实参(名为n的Node指针)
*/
void initNode(Node* &n, int d)
{
//函数得到一个任意值的Node指针的引用n(包括空指针);
n = new Node(); //函数修改n引用指向的Node指针;
n-> data = d; //使用;
}

void f1()
{
Node* newNode = NULL;

initNode(newNode, 1);//该语句等同于new Node();
cout < < newNode-> data < < endl;

delete newNode;//C\C++程序员著名的责任-释放堆空间!
}

演示这个程序,你将看到程序正常运行,堆对象被析构,无内存泄漏!
[解决办法]
里外打印 newNode 的值就清楚了。理解参数“按值传递”的意思。
[解决办法]
高人真多,呵呵!建议搂主找几本C++的基础书看看,比如C++ Primer,了解下指针使用,指针变量是个地址值,只是他们指向的内容不同,具体不多说了,你自己看书去。

读书人网 >C++

热点推荐