C语言 for循环的初始化和增量部分中的逗号是如何工作的?

qeeaahzv  于 2023-04-29  发布在  其他
关注(0)|答案(9)|浏览(92)

我在代码中遇到了一个for循环,看起来像这样:

for ( argc--, argv++; argc > 0; argc--, argv++ )

它是如何工作的?通常,for循环看起来像这样:

for (initialization; condition; increment) {/*body of the loop*/}

但是这里没有包含任何逗号--逗号的意思和作用是什么?

ny6fqffe

ny6fqffe1#

在C标准中(6.8.5.3 for语句)for语句以下列形式表示

for ( clause-1 ; expression-2 ; expression-3 ) statement

并且根据 * 子句-1 *,写有
如果子句-1是表达式,则在对控制表达式进行第一次求值之前,将其求值为void表达式
在此声明

for ( argc--, argv++; argc > 0; argc--, argv++ )
  • 子句-1* 是基于逗号运算符的表达式argc--, argv++。从C标准(6.5.17逗号运算符)

2逗号运算符的左操作数被计算为空表达式;在其求值和右操作数的求值之间存在序列点。则计算右操作数;结果具有其类型和值。
唯一的特殊性是在for语句中不使用运算符的结果。该表达式用于其副作用。
通常传递给运行程序的第一个参数是程序名。clause-1 中的表达式跳过第一个参数。
比较这两个程序的输出。让我们假设用户指定了命令行参数

first second third

此程序的程序输出

#include <stdio.h>

int main( int argc, char * argv[] )
{
    for ( argc--, argv++; argc > 0; argc--, argv++ )
    {
        puts( *argv );
    }        

    return 0;
}

first 
second 
third

以及当 * 子句-1 * 为空时此程序的程序输出(既不是表达式也不是声明)

#include <stdio.h>

int main( int argc, char * argv[] )
{
    for ( /*argc--, argv++*/; argc > 0; argc--, argv++ )
    {
        puts( *argv );
    }        

    return 0;
}

./prog.exe
first 
second 
third

为了使逗号操作符清晰,我们可以将一个程序看作第一个演示程序,其中使用了while循环来代替for循环。

#include <stdio.h>

int main( int argc, char * argv[] )
{
    while ( argv++, --argc > 0 )
    {
        puts( *argv );
    }        

    return 0;
}

输出将与第一个演示程序中的输出相同

first 
second 
third

在while语句中也使用了逗号运算符。不同之处在于,在这种情况下,逗号运算符的值用作条件的值。
请注意,expression-3 本身也表示一个带有逗号运算符的表达式。
同样,当问题用C标记时,你应该知道在C中for语句的第二个子句(在C++中它被命名为 condition)也可以是表达式或声明。

uhry853o

uhry853o2#

正如在许多答案中已经说明的,这是 * 逗号运算符 *,所以

argc--, argv++

只有一个表达式。
逗号运算符计算两边的值,先左后右。结果就是右边。所以你可以写一些奇怪的东西比如

int a = (x += 5, x + 2);

这将在将x + 2的结果分配给a之前将5加到x。这样的代码容易混淆,应该避免。但它展示了 * 逗号运算符 * 的一个重要属性:

作为序列点:使用上面的代码,您可以保证在x + 2被计算之前,5已经被添加到x(x的值 * 确实 * 改变了)。

逗号操作符的主要合理用法是在您的问题中显示的。在更复杂的for循环中,它可以方便地使用e。例如多种副作用和有保证的顺序。
为了澄清为什么测序 * 可能 * 重要(它不在你的例子中,因为副作用并不依赖于彼此),看看这个(人工的)例子:

int i, j;
for (i = j = 0; i < 10; ++i, j+=i)
{
    printf("%d\n", j);
}

如果逗号操作符没有在这里引入序列点,您将不知道j+=i是否会添加递增的i或未递增的i

31moq8wy

31moq8wy3#

对于多次初始化和多次更新/增量,我们使用comma operator(,)。我们用comma(,)分隔每个示例。
在这种情况下,当进入for循环时,执行初始化部分中的argc--argv++表达式。从那时起,每次循环迭代时,增量部分中的argc--argv++表达式都会执行。

fykwrbwg

fykwrbwg4#

在这个for循环中,comma operator用于第一个和最后一个表达式。所以for语句如下

for(
    (argc--, argv++);  // Expression 1
    argc > 0;          // Expression 2
    (argc--, argv++)   // Expression 3
  )

只有三个表达式(argc--, argv++)argc > 0(argc--, argv++)
表达式1不一定是声明语句,它可以是任何有效的表达式,甚至可以省略

for(;expression2; expression3)

或者可以省略所有表达式

for(;;)

在给定的for循环中,(argc--, argv++)被用作第一个表达式来更新变量argcargvargc将递减1,指针argv将递增1)。一旦对这些变量的副作用完成,程序将在检查argc > 0是否为true后进入循环体。你这么做的后果就是这样

for( i = 1; i < 10; i++)

i = 1i更新为1,然后检查条件。对i的更新只进行一次,其余的则通过表达式i++进行更新。

ryhaxcpt

ryhaxcpt5#

for ( argc--, argv++; argc > 0; argc--, argv++ )  
{ ... }

执行以下操作:
1.执行“* 初始化 ”部分:减少argc并增加argv
1.检查argv > 0,如果不是,则退出循环
1.执行{ ... }
1.执行“Updation”部分:减少argc并增加argv
1.后藤步骤2。以上
由于“
Initialization *”和“Updation”相同,因此也可以写为

while (argc--, argv++, argc > 0)
{ ... }

此表达式

(argc--, argv++, argc > 0)

由三个子表达式组成,由逗号操作符分隔。
这些子表达式从左到右执行。
整个表达式的计算结果为最右侧子表达式的结果。

amrnrhlw

amrnrhlw6#

argv拥有命令行参数。第一个问题是程序的名称。
因此,循环从argv[1]开始,处理命令行给出的每个参数,而不处理程序名

xtfmy6hx

xtfmy6hx7#

for ( argc--, argv++; argc > 0; argc--, argv++ )

可以读作

for ( (argc--), argv++; argc > 0; (argc--), argv++ )

由于逗号运算符的优先级可能最低,所以左手运算符总是先计算

nbnkbykc

nbnkbykc8#

for循环中的初始化参数并不意味着只初始化具有特定值的变量。
它还可以有一个或多个正则表达式,由逗号分隔。
希望能有帮助!!

ig9co6j1

ig9co6j19#

for ( argc--, argv++; argc > 0; argc--, argv++ )表示循环开始时,argcargv的值分别设置为它们初始值的负1和正1。每次迭代都会减少和增加它们的值,一旦argc达到0(意味着所有输入参数都被读取),迭代就会停止。

相关问题