【问题标题】:Strange behaviour with pointers in CC中指针的奇怪行为
【发布时间】:2020-11-28 22:03:54
【问题描述】:

在我的 C 项目中,我有这段代码(一个简单的链表):

while(current_node->v_uk <= version && current_node != NULL)
        current_node = current_node->next;

好吧,这会引发分段错误,但是,如果我将其切换到

while(TRUE){
        if(current_node->v_uk <= version && current_node != NULL)
                break;
        current_node = current_node->next;
}

它按预期工作。我无法弄清楚问题可能是什么

【问题讨论】:

  • 为什么要检查current_node != NULL 之后 current_node-&gt;v_uk?
  • 两种情况都调用 UB (undefined behavior)。 UB 的许多可能表现之一是“它按预期工作”。
  • 这两个代码 sn-ps 没有做同样的事情。第一个在current_node-&gt;v_uk &lt;= version 为假时立即结束循环,如果current_node-&gt;v_uk &lt;= version 始终为真,它将以未定义的行为结束,因为它遵循NULL 指针-您需要检查指针是否为NULL 在你取消引用它之前。第二个在current_node-&gt;v_uk &lt;= version为真时结束循环。

标签: c pointers linked-list segmentation-fault


【解决方案1】:

while 条件中语句的求值顺序是从左到右。所以 current_node->v_ukcurrent_node != NULL 检查之前被评估。

在您的第一个代码 sn-p 中交换这两个。

编辑:感谢 cmets,只是为了说清楚:根据 C 语言的规则,逻辑 AND 操作创建一个序列点,首先评估左侧的参数,然后评估左侧的参数正确的。重要的是要知道并非所有表达式都保证从左到右进行评估,但 && 是其中之一。更多详情请看这里:https://en.cppreference.com/w/c/language/eval_order

【讨论】:

  • 虽然在 OP 的代码中,while 条件包含一个 &amp;&amp; 表达式,该表达式首先从左侧计算,说明“while 条件内部从左到右”的顺序可能会误导读者相信这是while 条件的规则,但不是。例如,在while (foo() + bar()) 中,可能首先评估bar。这个答案应该说明&amp;&amp; 的左操作数首先被评估,右操作数只有在左操作数为真时才被评估。它不应该说明while 条件内的评估顺序是从左到右。
  • @EricPostpischil 是的,你是对的,我会编辑它。所有运算符在 C 中从左到右进行计算。
【解决方案2】:

评估顺序很重要!!逻辑表达式从左到右求值

此表达式首先取消引用指针,然后检查它是否不为 NULL。

  while(current_node->v_uk <= version && current_node != NULL)

你需要:

while(current_node != NULL && current_node->v_uk <= version)

在 C 中,逻辑表达式是用简约的短路方式求值的。因此,如果 current_node 为 null,则整个表达式为 false,并且不会计算逻辑表达式的第二部分 - 不会取消引用 NULL 指针。

【讨论】:

    【解决方案3】:

    两个代码sn-ps

    while(current_node->v_uk <= version && current_node != NULL)
            current_node = current_node->next;
    

    while(TRUE){
            if(current_node->v_uk <= version && current_node != NULL)
                    break;
            current_node = current_node->next;
    }
    

    调用未定义的行为,因为您尝试访问数据成员 v_uk 却不知道 current_node 是否等于 NULL

    在尝试访问数据成员 v_uk 之前,您必须首先检查 current_node 是否等于 NULL

    例如

    while( current_node != NULL && current_node->v_uk <= version )
            current_node = current_node->next;
    

    【讨论】:

      猜你喜欢
      • 2012-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-22
      • 1970-01-01
      • 1970-01-01
      • 2021-07-01
      • 1970-01-01
      相关资源
      最近更新 更多