为什么该程序无法正常运行?

时间:2020-02-08 13:35:39

标签: c

我是一名CS学生,准备参加C语言入门CS考试。我正在解决过去的一些测试,其中一个是这个问题:

查看下面的代码,并指出是否有任何错误。如果是这样,请更正它们。另外,如果程序有任何输入,请将其写下来。

问题附带的代码是这样的:

#include <stdio.h>
#ifdef SIZE
#define MAX_SIZE (2*(SIZE))
#endif
int main() {
  int i;
  int arr[MAX_SIZE + 1];
  for (i = 0; i < sizeof(arr)/sizeof(int);) {
    arr[i] = i++;
    printf("%d ", arr[i-1]);
  }
  return 0;
}  

因此,我当然注意到它不会编译,因为预处理器只会跳过定义部分,而MAX_SIZE是未声明的变量。 除了应该没有其他编译错误之外,我确实注意到arr[i] = i++,但是即使有些不可预测地也可以工作(尽管在测试中我会称其为错误),所以为了测试我复制的答案将其安装到我的IDE中,并据我所知对其进行了修复。 (我随机选了5个)

#include <stdio.h>
#define SIZE 5

#ifdef SIZE
#define MAX_SIZE (2*(SIZE))
#endif

int main()
{
  int i;
  int arr[MAX_SIZE + 1];
  for (i = 0; i < sizeof(arr)/sizeof(int);)
  {
    arr[i] = i++;
    printf("%d ", arr[i-1]);
  }
  return 0;
}

令我惊讶的是,该功能一直无休止地循环打印8张。

经过一番挖掘,我发现由于某些原因,i等于10时,它停止增加。进一步的挖掘使我意识到,它仅在SIZE为奇数时发生,而在++为前缀的情况下不会发生(如++i)。 如果应用了上述更改,则输出与我预期的一样,只是未分配arr[0]

所有这些使我得出结论,这是某种编译器优化错误,如果有人可以向我解释一下这里到底发生了什么,我真的很想这么做。

2 个答案:

答案 0 :(得分:4)

在同一条语句中使用变量的值同时对它施加副作用的方法是undefined behavior

因此,此:

arr[i] = i++;

是错误,并且会调用未定义的行为,这意味着允许编译器执行任何操作。在您的情况下,这恰好导致无限循环。使用++i代替i++也是调用未定义行为的错误。它“似乎起作用”的事实只是一个巧合。

通常,为了能够在同一条语句中多次使用同一变量,在该语句中不能执行任何更改变量值的副作用。

C11 standard第6.5节第2点(第76页)开始:

如果相对于相同标量对象上的不同副作用或使用相同标量对象的值进行的值计算,相对于标量对象的副作用未排序,则该行为未定义。如果一个表达式的子表达式有多个允许的排序,则如果在任何排序中都出现这种无序的副作用,则行为是不确定的。

[...]

本段呈现未定义的语句表达式,例如

i = ++i + 1;
a[i++] = i;

同时允许

i = i + 1;
a[i] = i;

答案 1 :(得分:3)

问题出在这一行:

arr[i] = i++;

这会调用未定义的行为。更改为

arr[i] = i;
i++;

它将按照您想要的方式工作。

让我们采用以下代码:

i=0;
arr[i] = i++;

根据++的工作原理,某个数组元素获取值0是合理的。但是,是a[0]还是a[1]都获取值0? i++返回 0,但是完成后i将具有值1。这是C具有未定义行为的许多情况之一,这基本上意味着任何事情都可能发生。该标准允许编译器产生所需的内容。