无论我检查了多少个引用,我总觉得我的实现是健全的。 但是,这个程序不起作用,我不知道为什么。 请帮忙。谢谢。 我有这个班级
class intNode
{
int x;
intNode * next;
public:
intNode();
intNode(int y, intNode *p);
setNode(int y, intNode *p);
int getX();
void setX(int y);
void setNext(intNode *p);
intNode* getNext();
};
和这个班级
class intList
{
private:
intNode * head;
public:
intList(); //sets head=NULL
void push( int x);
void print();
}
推送如下
void intList::push(int x)
{
intNode *newNode;
newNode->setX(x);
newNode->setNext(head);
head = newNode;
}
并打印如下
void intList::print()
{
intNode *current = head;
cout << "Printing list" << endl;
while(current != NULL)
{
cout << current->getX() << "\t";
current = current->getNext();
}
cout << endl;
}
但不知何故,主要是
中的这段代码intList l;
l.push(5);
l.print();
返回这个奇怪的值:6946556
答案 0 :(得分:2)
让我们检查您的push
方法,看看哪里出错了。
intNode *newNode;
您现在有一个名为newNode
的变量,它是指向intNode
的指针。
此指针当前未设置为任何内容(我们称之为&#34;未初始化&#34;)。
尝试访问未初始化的变量(例如取消引用它或在其上调用方法)会导致undefined behavior,这是另一种说法&#34;所有赌注都已关闭&#34; - 标准没有说明应该发生什么,所以你的编译器可以生成它想要的任何东西。
所以当你这样做的时候:
newNode->setX(x);
您现在正在调用未初始化指针newNode
上的方法。除此之外的任何事情与我们对代码的检查几乎没有关系,因为编译器可能无意中做了许多看似疯狂的事情中的任何一个&#34;当它优化程序时的事情。
例如,g++ 6.4.0
-O0
,您的程序可以正常使用。它打印5.这是因为编译器没有优化任何东西,我们显然得到了幸运&#34;以及newNode
&#34;恰好是&#34;实际上是一个有效的地址。
然而,一旦我转到-O1
,该程序实际上根本没有输出任何值。我怀疑编译器确定push
在所有代码路径上都会产生UB,因此得出结论:push
必须永远不会被调用,并且根本没有为该方法生成任何程序集。所有。 (注意:我现在不在程序集中验证了这一点。)
这只是在调用未定义行为时发生的疯狂事情之一 - 请参阅上面链接的文章以了解其他一些内容。未修改的行为应该在代码中永远。
现在,正确的做法是分配 new 节点并将指针设置为指向它。用
初始化它intNode *newNode = new intNode();
,那么你的代码看起来很好。不要忘记new
是一个堆分配 - 当你不再需要(当你移除节点时)确保它delete
d为你的工作,否则你会在那些没有被使用的情况下留下流浪的记忆(memory leak)。
PS:如果您使用g++
选项调用-Wall
,它会警告您这个错误:
test.cpp: In member function ‘void intList::push(int)’:
test.cpp:30:17: warning: ‘newNode’ is used uninitialized in this function [-Wuninitialized]
newNode->setX(x);
始终注意编译器警告 - 这通常是他们的充分理由!
答案 1 :(得分:1)
在intList::push
中,它不会创建新节点,但会为其使用不确定的指针值。
必须分配新节点:
void intList::push(int x) {
head = new intNode(x, head);
}
您可能希望在启用警告的情况下编译代码,因为这将是编译器警告。对于g++
使用-Wall -Wextra -Werror
命令行选项。
答案 2 :(得分:1)
Treeston很好地解释了为什么在这里发生任意的诡计,但我不喜欢他使用new
的建议。
您的intNode 拥有 next
指针,并且它是唯一所有者,因此您应该使用std::unique_ptr
。类似地,intList 拥有 head
。
class intNode {
friend class intList;
int x;
std::unique_ptr<intNode> next;
public:
intNode();
intNode(int _x, std::unique_ptr<intNode> _next);
int getX();
intNode * getNext();
};
intNode::intNode() {}
intNode::intNode(int _x, std::unique_ptr<intNode> _next)
: x(_x), next(std::move(_next)) {}
class intList {
std::unique_ptr<intNode> head;
public:
void push(int x);
void print();
}
void intList::push(int x) {
head = std::make_unique(x, std::move(head));
}
void intList::print()
{
cout << "Printing list" << endl;
for(intNode * current = head.get(); current; current = current->getNext())
{
cout << current->getX() << "\t";
}
cout << endl;
}