例如:
node* find(node *cur, int id){
node* p;
if (cur->id==id) {
printf("n%d found at %pn", id, cur);
return cur;
}
else {
if (cur->left!=NULL) p=find(cur->left, id);
if ((p==NULL) && (cur->right!=NULL)) p=find(cur->right, id);
}
}
此函数的目的是返回树中id等于输入id的节点的地址。
in main I have:
while (1){
fscanf(fi, "%d", &id);
if (id==-2) break;
fscanf(fi, "%d %d", &left, &right);
cur=find(root, id);
printf("%pn", cur);
if (cur==NULL) continue;
printf("%dnn", cur->id);
if (left!=-1) cur->left=makeNode(left);
if (right!=-1) cur->right=makeNode(right);
}
注意零件
cur=find(root, id);
printf("%pn", cur);
if (cur==NULL) continue;
printf("%dnn", cur->id);
如果我更改:
if ((p==NULL) && (cur->right!=NULL))
p=find(cur->right, id);
收件人:
if ((cur->right!=NULL) && (p==NULL))
p=find(cur->right, id);
我会得到错误的答案,即
使用if ((p==NULL) && (cur->right!=NULL)) p=find(cur->right, id);
,我得到:
2在0x56552970dcd0处找到
0x56552997dcd0
2
4在0x56552370dcf0处找到
但有了if ((cur->right!=NULL) && (p==NULL)) p=find(cur->right, id);
,我得到了
2在0x564024e5cccd0处找到
0x564024e 5cccf0
4在0x5641024 e5cccf0
0X564024e 5Cccf0
4 处找到
有人能向我解释为什么会发生这种情况吗?很抱歉发了这么长的邮件,我的英语不好。提前谢谢。
p
未初始化。这里的每一个引用都是未定义的行为。
您应该从node* p = NULL
开始,以获得一致的输出。
提示:在使用变量之前总是初始化变量。每当你声明某事时,养成立即赋值的习惯。如果您在使用变量时声明变量,这很少是一个麻烦。
其他答案已经指出了代码中的一个错误。
我将处理这一部分:
条件内部的顺序是否重要?
是的,订单很重要我们经常在代码中使用这个事实。
C只评估子条件,直到它知道最终结果。
所以考虑一下:
if (sub-cond1 && sub-cond2) {...}
如果sub-cond1
给出的结果为FALSE,则整个条件的结果将为FALSE。因此sub-cond2
永远不会被评估。
if (sub-cond1 || sub-cond2) {...}
如果sub-cond1
给出的结果为TRUE,则整个条件的结果将为TRUE。因此sub-cond2
永远不会被评估。
实际使用的一个例子:
int* p = foo(...);
if (p != NULL && p->data == 42) {...}
现在,如果foo
返回NULL
,则子条件p != NULL
将为FALSE。因此,p->data == 42
永远不会被求值,这非常好,因为取消引用NULL指针会导致程序崩溃。
这个概念通常被称为";"短路";
这里有两个单独的问题:
-
条件内部的顺序是否重要?
-
有人能向我解释为什么会发生这种情况吗?
2的答案与1无关。错误输出是由于未能初始化p
:
node* p = NULL ;
关于1,尽管它不是错误的原因,但值得回答,因为它是一个更有趣的问题。
有很多事情需要考虑:
- 短路评估
- 副作用
- 表达式复杂性
- 给定第一个表达式的第二个表达式的有效性
对于表达式:
<expr_A>
&&
<expr_B>
如果<expr_A>是CCD_ 15,则<expr_B>不进行评估(短路评估(,因为无论的值如何,整个表达式的结果都将是false
。
如果<expr_B>有副作用,必须进行评估,这可能是一个问题。如果您交换了表达式<expr_B>将总是被评估,并且由此产生的行为可能不同。例如:
if( x && printf( "%s", s ) > 4 )
仅当x
为true时才会打印字符串s
,而:
if( printf( "%s", s ) > 4 && x )
将打印s
,而条件的结果将保持不变。
另一件需要考虑的事情是表达的复杂性。在您的示例中:
if( p == NULL && cur->right != NULL )
右侧的子表达式涉及cur
的获取和取消引用、成员访问,然后是比较,而左侧只是p
的获取和比较。因此,通过将更复杂的表达式放在右边或&&
,可以从短路评估中获得最佳性能优势。
最后,在给定左边的情况下,右边的有效性问题可能会发生,例如,当您取消引用指针时。例如:
if( p != NULL && p->left != NULL )
排序是至关重要的,因为如果p
是NULL
,p->left
将导致运行时错误,但短路评估确保不会对其进行评估。
短路评估也适用于||
,但在这种情况下,当左侧为true
时,表达式短路。因此,在这两种情况下,操作数的顺序都很重要。