C for循环中的条件检查
考虑以下代码:C for循环中的条件检查,c,for-loop,conditional-statements,C,For Loop,Conditional Statements,考虑以下代码: int main() { int i; int ints[3]; ints[0] = 0; ints[1] = 1; ints[2] = 2; for(i = 0; (ints[i])<4 && i<3; i++) { printf("%d\n", ints[i]); } } int
int main()
{
int i;
int ints[3];
ints[0] = 0;
ints[1] = 1;
ints[2] = 2;
for(i = 0; (ints[i])<4 && i<3; i++)
{
printf("%d\n", ints[i]);
}
}
intmain()
{
int i;
int-int[3];
ints[0]=0;
ints[1]=1;
ints[2]=2;
对于(i=0;(ints[i])最好执行i<3&&ints[i]<4
,因为语句的第二部分仅在第一部分为真时才计算。按照您的方式,它将查找不存在的ints[3]
。在该循环的最后一次迭代中,表达式ints[i]按照编写循环的方式,您的代码将尝试读取不存在的数组元素ints[3]。这是未定义的行为;结果是任何事情都可能发生。现在整个互联网都在骚动,因为OpenSSL中的一些代码调用了未定义的行为。这样做是不好的,因为ints[3]
确实会被访问。现在,由于这是C,您不会得到错误(很遗憾),但您永远无法确定结果会是什么
交换语句将解决问题,因为&&运算符已优化,因此如果第一个条件为false,它不会计算第二个条件。for关键字按以下方式展开:
int i;
for(i = 0; i < 2; i++)
dothing();
虽然这很好,但测试的顺序存在问题:
(ints[i] < 4) && (i < 3)
(ints[i]<4)和&(i<3)
在使用数组索引之前,应始终首先检查它们是否有效:
i = 0:
ints[0] < 4 && 0 < 3
i = 1:
ints[1] < 4 && 1 < 3
i = 2:
ints[2] < 4 && 2 < 3
i = 3:
ints[3] < 4 && 3 < 3 /* illegal access to ints[3] */
i=0:
整数[0]<4&&0<3
i=1:
整数[1]<4&&1<3
i=2:
整数[2]<4&&2<3
i=3:
ints[3]<4&&3<3/*非法访问ints[3]*/
一般的经验法则是,除非有更好的排序理由,否则总是尝试按成本顺序排列条件,例如优先级:在这种情况下,i<3
是两个测试中较便宜的一个,加上它是对可以访问的int
元素的约束,因此检查索引时应该有更高的优先级ity-在使用它测试ints[i]
任何东西之前,您应该检查它。循环终止,这没关系。但是您访问的区域超出了允许的范围。这是未定义的行为。您可以随时获得分段。但您很幸运
试着把iAs Matt说,这种行为在C中是未定义的。因此这将取决于编译器如何处理这一代码序列。在我上一次工作的地方,我们为16位系统编写了一些C,并且我们使用的特定编译器有数组大小限制。然而,按照编译器的工作方式,我们可以对两个数组进行malloc next指向彼此,第一个的指针在达到大小限制后会溢出到第二个。除非您必须这样做,否则这不是您真正想要做的事情,也没有办法解决。我应该像另一个答案建议的那样交换语句吗?这仍然不安全吗?是否需要检查“&&”条件自始至终是自始至终还是依赖于编译器?//编辑:发布时没有看到前面的注释,哪种类型的注释回答了这个问题。如果交换语句,则代码是安全的。&&
是C中的短路运算符。在访问ints[3]之前,条件i<3
变为false
;循环在i<3
计算为false后立即终止。因此,对int[]的所有访问
在数组中,行为已定义。代码是否清晰和可维护是另一回事。只想补充一下:经验法则是避免像瘟疫一样的未定义的行为,除非您的特定编译器对此有定义的结果,并且您有很好的理由这样做。&&运算符会做一件事ndred percent reliable执行第一个测试,如果该测试为假,则根本不执行第二个测试。感谢您的回答,我最初确实将iTo放在了最后一个位置-它们遵循传统的C短路规则;当C计算逻辑表达式时,(x==2&&y==3)| |(z==1)
,它尝试做最小的必要功;因此,如果x为1,它不会检查y,但会测试z;如果x为2,y为3,它不会检查z,但如果x为2,y为4,它会检查x、y和z。
(ints[i] < 4) && (i < 3)
i = 0:
ints[0] < 4 && 0 < 3
i = 1:
ints[1] < 4 && 1 < 3
i = 2:
ints[2] < 4 && 2 < 3
i = 3:
ints[3] < 4 && 3 < 3 /* illegal access to ints[3] */
for(i = 0; i<3 && (ints[i])<4; i++)