来自简单C程序的奇怪行为

时间:2015-07-27 18:17:33

标签: c arrays pre-increment

如果我运行以下代码,graph[0][0]获得1graph[0][1]获得4

换句话说,行graph[0][++graph[0][0]] = 4;1放入graph[0][0],将4放入graph[0][1]

如果有人能提供合理的解释,我真的很感激。

我从Visual C ++ 2015以及Android C编译器(CppDriod)中观察到了这一点。

static int graph[10][10];
void main(void)
{
    graph[0][++graph[0][0]] = 4;
}

5 个答案:

答案 0 :(得分:5)

让我们分解一下:

++graph[0][0]

这会预先增加graph[0][0]处的值,这意味着现在为graph[0][0] = 1,然后表达式的值为1(因为这是{{1}的最终值}})。

然后,

graph[0][0]

基本上,graph[0][/*previous expression = 1*/] = 4;

就是这样!现在graph[0][1] = 4;graph[0][0] = 1

答案 1 :(得分:2)

首先让我们看看一元(前缀)增量运算符是什么。

  

前缀++运算符的操作数的值递增。结果是增量后操作数的新值。

所以,在

的情况下
graph[0][++graph[0][0]] = 4;

首先,graph[0][0]的值加1,然后该值用于索引。

现在,graph是一个静态全局变量,由于隐式初始化,默认情况下,数组中的所有成员都被初始化为0。因此,++graph[0][0]会将graph[0][0]的值增加为1,并返回1的值。

然后,指令的简化版本看起来像

graph[0][1] = 4;

因此,你得到了

  • graph[0][0]为1
  • graph[0][1]为4。

另外,FWIW,main()的推荐签名是int main(void)

答案 2 :(得分:1)

您通过执行graph[0][0]++graph[0][0]添加一个。然后将graph[0][1]设置为4。也许你想做graph[0][graph[0][0]+1] = 4

答案 3 :(得分:1)

首先,您的变量graph[10][10]是静态的,因此它将使用值0进行初始化。

然后在{strong> graph [0] [0] = 0 行graph[0][++graph[0][0]] = 4 ;,只需递增 graph [0] [0] 的值,基本上你自己分配graph[0][1] = 4;

请注意,您已经使用了预增量运算符(++ x),因此它首先会增加并且值会更改但是如果您使用后增量运算符(x ++)则graph[0][0] = 4;本身< /强>

答案 4 :(得分:0)

让我们排列关于这个表达的事实

graph[0][++graph[0][0]] = 4;
  • 根据6.5.1,在计算数组元素++graph[0][0]之前对数组索引graph[0][++graph[0][0]]的计算进行排序,然后在计算整个赋值运算符之前对其进行排序。

  • ++graph[0][0]的值必须为1。请注意,这并不意味着整个预增量及其副作用必须首先发生&#34;。它只是意味着必须首先计算该预增量的结果(1)。 graph[0][0]的实际修改(即graph[0][0]0更改为1)可能会在很晚之后发生。没有人知道它何时会发生(在声明结束之前的某个时间)。

  • 这意味着赋值运算符修改的元素为graph[0][1]。这是4应该去的地方。将4分配给graph[0][1]也是=运算符的副作用,这将在语句结束之前的某个时间发生。

请注意,在这种情况下,我们可以最终确定++修改graph[0][0],而=修改graph[0][1]。我们有两个未经测试的副作用(这是危险的),但它们作用于两个不同的物体(这使它们安全)。在这种情况下,这正是使我们免于未定义行为的原因。

但是,这取决于graph数组的初始值。如果你试试这个

graph[0][0] = -1;
graph[0][++graph[0][0]] = 4;

即使表达式本身看起来相同,行为也会立即变为未定义。在这种情况下,++的副作用和=的副作用将应用于同一数组元素graph[0][0]。副作用相互之间没有排序,这意味着行为未定义。