示例讨论 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,了解下指针使用,指针变量是个地址值,只是他们指向的内容不同,具体不多说了,你自己看书去。