Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
一个简单C程序的奇怪行为_C_Arrays_Pre Increment - Fatal编程技术网

一个简单C程序的奇怪行为

一个简单C程序的奇怪行为,c,arrays,pre-increment,C,Arrays,Pre Increment,如果我运行以下代码,graph[0][0]获取1,而graph[0][1]获取4 换句话说,线图[0][++graph[0][0]]=4将1放入图形[0][0]中,将4放入图形[0][1] 如果有人能提供合理的解释,我将不胜感激 我从Visual C++ 2015和Android C编译器(CPPRIDOD)中观察到这一点。 让我们把它分解一下: ++graph[0][0] 这预先增加了图形[0][0]处的值,这意味着现在图形[0][0]=1,然后表达式的值是1(因为这是图形[0][0]的最终

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

换句话说,线
图[0][++graph[0][0]]=4
1
放入
图形[0][0]
中,将
4
放入
图形[0][1]

如果有人能提供合理的解释,我将不胜感激

我从Visual C++ 2015和Android C编译器(CPPRIDOD)中观察到这一点。 让我们把它分解一下:

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

那么

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


就这样!现在
图形[0][0]=1
图形[0][1]=4
您正在通过执行
++graph[0][0]
图形[0][0]
添加一个。然后将
图形[0][1]
设置为
4
。也许您想先执行
graph[0][graph[0][0]+1]=4

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

然后直线
图[0][++图[0][0]]=4
这里graph[0][0]=0在表达式中,您只需增加graph[0][0]的值,因此基本上指定
graph[0][1]=4你自己


请注意,您使用了增量前运算符(++x),因此它首先会递增,值也会更改,但如果您要使用增量后运算符(x++),则
图形[0][0]=4本身

首先让我们看看一元(前缀)递增运算符的作用

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

那么,万一

graph[0][++graph[0][0]] = 4;
首先,将
图形[0][0]
的值增加1,然后将该值用于索引

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

然后,该指令的简化版本如下

graph[0][1] = 4;
因此,你得到

  • 图形[0][0]
    为1
  • 图形[0][1]
    如图4所示

另外,FWIW,
main()
的建议签名是
intmain(void)

让我们把这个表达式的事实列出来

graph[0][++graph[0][0]] = 4;
  • 根据6.5.1,数组索引
    ++图[0][0]
    的计算在数组元素
    图[0][++图[0][0]]
    的计算之前排序,而数组元素
    图[0][0]
    的计算又在整个赋值运算符的计算之前排序

  • ++graph[0][0]
    的值必须是
    1
    。请注意,这并不意味着整个预增量及其副作用必须“先发生”。这仅仅意味着必须首先计算预增量(即
    1
    )的结果。
    图形[0][0]
    的实际修改(即将
    图形[0][0]
    0
    更改为
    1
    )可能要晚得多。没有人知道什么时候会发生(在声明结束前的某个时候)

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

注意,在这种情况下,我们可以最终确定
++
修改
图形[0][0]
,而
=
修改
图形[0][1]
。我们有两个未排序的副作用(这是危险的),但它们作用于两个不同的对象(这使它们安全)。这正是我们在这种情况下避免未定义行为的原因

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

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

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

阅读并避免编写这种不可读的代码。@BasileStarynkevitch先生,这真的是UB吗?我们不是在不同的元素上操作吗?@BasileStarynkevitch这一个看起来定义很好,因为它使用了预增量。如果它是
graph[0][graph[0][0]+]=4
,它将是一个UB。类似地,将
-1
存储在
图形[0][0]
中会导致UB带有前置增量。但它仍然非常隐蔽,无法读取。而一个小小的改变就可以让这一切变得更美好。请看Sasblinklight的评论。@AnT您能解释一下吗?你所说的
在没有订单的情况下强加订单是什么意思?这不是未定义的行为。@Jashaszun:不,这不是未定义的行为。但是你声称“现在
图[0][0]=1
”有误导性。无需在原始表达式的上下文中计算
++graph[0][0]
,即可立即修改
graph[0][0]
。所有这些
++
所做的就是生成值
1
,并将其发送到求值链上,但您不能声称“现在
graph[0][0]=1
”。很可能
图形[0][0]
会保持
0
一段时间。它将在很久以后(在完整语句结束之前)变为
1
。C语言不保证exa何时运行
graph[0][0] = -1;
graph[0][++graph[0][0]] = 4;