内部条件的顺序是否重要

  • 本文关键字:是否 顺序 条件 内部 c
  • 更新时间 :
  • 英文 :


例如:

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指针会导致程序崩溃。

这个概念通常被称为";"短路";

这里有两个单独的问题:

  1. 条件内部的顺序是否重要?

  2. 有人能向我解释为什么会发生这种情况吗?

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 )

排序是至关重要的,因为如果pNULLp->left将导致运行时错误,但短路评估确保不会对其进行评估。

短路评估也适用于||,但在这种情况下,当左侧为true时,表达式短路。因此,在这两种情况下,操作数的顺序都很重要。

最新更新