C++中for循环将z-1替换为z--后输出异常的原因
原因解释
两者效果不一致的核心是后置自减运算符z--和算术减法表达式z - 1的执行逻辑完全不等价,你修改后的代码还触发了数组越界的未定义行为,才会出现不符合预期的输出。
首先明确代码中变量的初始值:你定义的数组a包含3个int类型元素,sizeof(a)得到整个数组占用的总字节数,sizeof(int)得到单个int占用的字节数,计算后z的初始值为3,对应数组长度。C++数组下标从0开始计数,因此长度为3的数组合法下标范围是0、1、2,对应元素分别是1、2、3。
原写法int i = z - 1的执行流程
这是普通的二元算术运算,整个计算过程不会修改z本身的值:
- 运算时直接读取z的当前值3,减去1得到结果2
- 变量z全程保持初始值3不变
- 循环变量i初始值为2,刚好对应数组最后一个元素的下标,后续循环i从2逐次递减到0,依次访问
a[2]、a[1]、a[0],输出结果为3 2 1,符合预期。
修改后写法int i = z--;的执行流程
z--是后置自减运算符,它的固定运算规则是:先返回变量当前的原始值作为整个表达式的结果,再对变量本身执行减1操作。逐行拆解执行步骤:
- 执行循环初始化语句
int i = z--;:- 第一步先读取z的当前值3,作为
z--表达式的返回值,因此i被直接赋值为3 - 赋值完成后,z本身被修改,值从3变为2
- 第一步先读取z的当前值3,作为
- 第一次循环判断
i >= 0:此时i=3,条件成立,进入循环体执行输出:访问a[3]。由于数组合法最大下标是2,访问a[3]属于数组越界,是C++中的未定义行为——你运行时输出的第一个2,就是越界读取到的相邻内存位置的随机值,换编译环境或运行时机这个值都可能变化,甚至直接触发程序崩溃。 - 第一次循环执行完毕,运行循环步进语句
i--,i的值从3变为2 - 第二次循环判断成立,访问
a[2],输出元素3 - 步进后i变为1,第三次循环判断成立,访问
a[1],输出元素2 - 步进后i变为0,第四次循环判断成立,访问
a[0],输出元素1 - 步进后i变为-1,循环判断不成立,程序结束
最终输出的内容就是越界读到的随机值2,拼接上后续正常输出的3、2、1,也就是你看到的2 3 2 1。
补充说明:如果要在初始化i的时候用自减运算符实现和
z-1相同的效果,需要使用前置自减写法int i = --z;。前置自减的规则是先将变量z的值减1,再返回减1后的结果赋值给i,此时i初始值为2,循环逻辑和原写法一致。但日常写代码不推荐这种写法,z - 1不会额外修改z的值,逻辑更直白,不容易引入修改变量带来的隐性bug。
内容的提问来源于stack exchange,提问作者Hideo Takahashi
相关产品推荐
相关产品推荐

