C 中完整的“for”循环语法是啥?
Posted
技术标签:
【中文标题】C 中完整的“for”循环语法是啥?【英文标题】:What is the full "for" loop syntax in C?C 中完整的“for”循环语法是什么? 【发布时间】:2010-09-21 13:10:19 【问题描述】:我在阅读其他人的代码时看到了一些非常奇怪的for
循环。我一直在尝试在 C 中搜索 for
循环的完整语法解释,但这非常困难,因为“for”这个词出现在不相关的句子中,这使得搜索几乎不可能在 Google 中有效。
读了this thread之后我想到了这个问题,这让我又好奇了。
for
在这里:
for(p=0;p+=(a&1)*b,a!=1;a>>=1,b<<=1);
中间条件有一个逗号分隔两段代码,这个逗号有什么作用?我理解右侧的逗号是a>>=1
和b<<=1
。
但是在循环退出条件中,会发生什么?它会在p==0
、a==1
或两者都发生时退出?
如果有人能帮助我理解这一点,并可能为我指出完整的 for
循环语法描述的方向,那就太好了。
【问题讨论】:
@Jesus -- 你将“kinda”更正为“kind of”,“coma”更正为“comma”,将“I”和“Does”大写,但将“ppl”留给人们?跨度> 更正了一些错误。帖子现在看起来好多了。有趣的问题。 【参考方案1】:逗号不排除for循环;它是逗号运算符。
x = (a, b);
会先做 a,然后做 b,然后将 x 设置为 b 的值。
for 语法是:
for (init; condition; increment)
...
这在某种程度上(暂时忽略 continue
和 break
)相当于:
init;
while (condition)
...
increment;
所以你的 for 循环示例(再次忽略 continue
和 break
)相当于
p=0;
while (p+=(a&1)*b,a!=1)
...
a>>=1,b<<=1;
表现得好像是(再次忽略 continue
和 break
):
p=0;
while (true)
p+=(a&1)*b;
if (a == 1) break;
...
a>>=1;
b<<=1;
for 循环的两个额外细节没有在上面简化的 while 循环转换中:
如果省略条件,则始终为true
(导致无限循环,除非break
、goto
或其他东西打破循环)。
continue
就像在增量之前转到标签一样,这与 while 循环中会跳过增量的 continue
不同。
另外,关于逗号运算符的一个重要细节:它是一个序列点,例如 &&
和 ||
(这就是为什么我可以将它拆分为单独的语句并保持其含义不变)。
C99 的变化
C99 标准引入了本说明前面未提及的一些细微差别(这对 C89/C90 非常有用)。
首先,所有循环本身都是块。实际上,
for (...) ...
本身是用一对大括号包裹的
for (...) ...
标准说:
ISO/IEC 9899:1999 §6.8.5 迭代声明
¶5 迭代语句是一个块,其范围是其范围的严格子集 封闭块。循环体也是一个块,其范围是范围的严格子集 迭代语句。
这在基本原理中也用额外的大括号进行了描述。
其次,C99 中的init
部分可以是(单个)声明,如
for (int i = 0; i < sizeof(something); i++) ...
现在“循环中的块”开始发挥作用了;它解释了为什么不能在循环外访问变量i
。你可以声明多个变量,但它们必须是同一类型:
for (int i = 0, j = sizeof(something); i < j; i++, j--) ...
标准说:
ISO/IEC 9899:1999 §6.8.5.3 for 声明
声明
for ( clause-1 ; expression-2 ; expression-3 ) statement
的行为如下:表达式 expression-2 是控制表达式 在每次执行循环体之前进行评估。表达式表达式 3 是 在每次执行循环体后评估为 void 表达式。如果第 1 条是 声明,它声明的任何变量的范围是声明的其余部分,并且 整个循环,包括其他两个表达式;按执行顺序到达 在控制表达式的第一次评估之前。如果 Clause-1 是一个表达式,它是 在控制表达式的第一次评估之前评估为 void 表达式。133)
clause-1 和 expression-3 都可以省略。省略的表达式 2 被替换为 非零常数。
133) 因此,clause-1 指定循环的初始化,可能声明一个或多个变量用于 循环;控制表达式 expression-2 指定在每次迭代之前进行的评估, 这样循环的执行将继续,直到表达式比较等于 0;和表达式 3 指定每次迭代后执行的操作(如递增)。
【讨论】:
在 C 中,逗号的优先级低于赋值,所以 "x = a, b;"将首先将 x 设置为 a,然后执行 b。 @DavidThornley 如果它是 x = a, b;而不是 (a, b)? @TM:如果我理解正确,“x = a, b”会将 a 分配给 x,然后评估 b 并丢弃它的值。【参考方案2】:逗号只是分隔两个表达式,并且在 C 中允许正常表达式的任何地方都有效。这些是按从左到右的顺序执行的。最右边表达式的值是整个表达式的值。
for
循环由三部分组成,其中任何部分也可以为空;一个(第一个)在开始时执行,一个(第三个)在每次迭代结束时执行。这些部分通常分别初始化和增加一个计数器;但他们可以做任何事情。
第二部分是在每次执行开始时执行的测试。如果测试产生false
,则循环中止。仅此而已。
【讨论】:
你的句子“一个(第一个)在开始时执行,每次迭代结束时一个(第三个)”可能会让一些人认为第一部分是在每次迭代开始时执行。【参考方案3】:C 风格的 for 循环由三个表达式组成:
for (initializer; condition; counter) statement_or_statement_block;
初始化程序在循环开始时运行一次。
在每次迭代之前检查条件。只要计算结果为真,循环就会运行。
计数器在每次迭代后运行一次。
这些部分中的每一个都可以是在您编写循环所用的语言中有效的表达式。这意味着可以更有创意地使用它们。任何你想事先做的事情都可以进入初始化程序,任何你想做的事情都可以进入条件或计数器,直到循环不再有主体。
为了实现这一点,逗号运算符非常方便。它允许您将表达式链接在一起以形成一个新的表达式。大多数情况下,它在 for 循环中以这种方式使用,逗号运算符的其他含义(例如值分配注意事项)起着次要作用。
即使您可以通过创造性地使用语法来做一些聪明的事情 - 在我找到 真正 这样做的好理由之前,我会保持清醒。使用 for 循环玩代码高尔夫会使代码更难阅读和理解(和维护)。
***也有一个不错的article on the for loop。
【讨论】:
for
部分是否允许另一个 for
循环,这将允许在同一语句中定义嵌套的 for 循环?换句话说,在 C/C++ 中,复合 for 循环是如何定义的?
我没有足够的 C 语言律师来回答这个问题。尽管如此,有趣和原始的问题。如果您在这里提出实际问题,则很有可能得到答案。
我听取了您的建议,这是一个answer。如果您有这种感觉,请投票赞成这个问题。享受吧!【参考方案4】:
for
循环中的所有内容都是可选的。我们可以初始化多个变量,可以检查多个条件,可以使用逗号运算符迭代多个变量。
下面的for
循环将带你进入一个无限循环。仔细检查条件。
for(;;)
【讨论】:
第一次在 90 年代的旧 C 代码中看到这个,以“goto”退出,真的吗??【参考方案5】:康拉德提到了我想重复的关键点:最右边的表达式的值是整个表达式的值。
当我在 for 循环的“条件”部分放置两个测试时,Gnu 编译器会发出此警告
warning: left-hand operand of comma expression has no effect
我真正想要的“条件”是两个测试之间有一个“&&”。根据 Konrad 的说法,只有逗号右侧的测试会影响条件。
【讨论】:
“最右边的表达式的值是overall expression.
的值”是什么意思?我猜你的意思是“最右边表达式的值是整体comma expression
的值”?【参考方案6】:
for 循环是在特定时间执行 for(;;)
for 循环的语法
for(;;)
或
for(初始化器;条件;计数器)
例如 (rmv=1;rmv
for block 执行到 15 次
1.首先初始化值,因为启动值
(例如)rmv=1 或 rmv=2
2.second 语句是测试条件为真或假,条件为真执行for循环的次数,条件为假时终止块,
例如 i=5;i
i=10;i<10 the condition is false terminate for block,
3.third是递增还是递减
(例如)rmv++ 或 ++rmv
【讨论】:
你的格式太糟糕了。您应该在等宽中编写代码。要制作代码块,请使用 4 个空格缩进属于它的每一行。要制作这样的inline monospace
,请在您想要等宽的文本的开头和结尾使用`。
另外,for(;;)
不是替代语法;这是正常语法,跳过了初始化程序、条件和计数器。以上是关于C 中完整的“for”循环语法是啥?的主要内容,如果未能解决你的问题,请参考以下文章