(* ++ argv)[0]和while(c = * ++ argv [0])之间的区别

时间:2010-01-07 14:27:00

标签: c string pointers argv

我有以下代码片段:

int main(int argc, char *argv[])
{   

     char line[MAXLINE];
     long lineno = 0;
     int c, except = 0, number = 0, found = 0;

     while(--argc > 0 && (*++argv)[0] == '-') //These two lines
        while(c = *++argv[0])                 //These two lines
          switch(c) {
             case 'x':
                  except = 1;
                  break;
             case 'n':
                  number = 1;
                  break;
             default:
                  printf("find: illegal option %c\n", c);
                  argc = 0;
                  found = -1;
                  break;
          }

     ...
}

包含以下表达式:

while(--argc > 0 && (*++argv)[0] == '-')

括号(*++argv)[0]中的此表达式是否与while(c = *++argv[0])的括号不同?

如果是这样,怎么样? (*++argv)是指向下一个参数的指针,*++argv[0]是否指向指向当前char数组中下一个字符的指针?

5 个答案:

答案 0 :(得分:40)

首先,K& R在这个特定的片段上有一个勘误表:

  

117(§5.10):在 find 示例中,程序递增argv[0]。这不是特别禁止的,但也没有特别允许。

现在进行解释。

假设您的程序名为prog,您可以使用:prog -ab -c Hello World执行该程序。您希望能够解析参数以指出已指定选项abc,并且HelloWorld是非选项参数。

argv的类型为char ** - 请记住,函数中的数组参数与指针相同。在程序调用时,事情看起来像这样:

                 +---+         +---+---+---+---+---+
 argv ---------->| 0 |-------->| p | r | o | g | 0 |
                 +---+         +---+---+---+---+---+
                 | 1 |-------->| - | a | b | 0 |
                 +---+         +---+---+---+---+
                 | 2 |-------->| - | c | 0 |
                 +---+         +---+---+---+---+---+---+
                 | 3 |-------->| H | e | l | l | o | 0 |
                 +---+         +---+---+---+---+---+---+
                 | 4 |-------->| W | o | r | l | d | 0 |
                 +---+         +---+---+---+---+---+---+
                 | 5 |-------->NULL
                 +---+

此处argc为5,argv[argc]NULL。最初,argv[0]char *,其中包含字符串"prog"

(*++argv)[0]中,由于括号,argv首先递增,然后取消引用。增量的作用是将argv ---------->箭头“向下移动一个块”,指向1。解除引用的效果是获取指向第一个命令行参数-ab的指针。最后,我们获取此字符串中的第一个字符([0]中的(*++argv)[0]),并测试它是否为'-',因为它表示选项的开头。

对于第二个构造,我们实际上想要沿着当前argv[0]指针所指向的字符串向下走。所以,我们需要将argv[0]视为指针,忽略它的第一个字符(就像我们刚刚测试的那样'-'),并查看其他字符:

++(argv[0])将递增argv[0],以获取指向第一个非-字符的指针,并且取消引用它将为我们提供该字符的值。所以我们得到*++(argv[0])。但是因为在C中,[]++绑定得更紧,我们实际上可以摆脱括号并将表达式设为*++argv[0]。我们希望继续处理此字符,直到它为0(上图中每行中的最后一个字符框)。

表达式

c = *++argv[0]

c分配当前选项的值,的值为c while(c)while(c != 0)的简写,因此while(c = *++argv[0])行基本上将当前选项的值分配给c并对其进行测试以查看我们是否已达到当前的命令行参数。

在此循环结束时,argv将指向第一个非选项参数:

                 +---+         +---+---+---+---+---+
                 | 0 |-------->| p | r | o | g | 0 |
                 +---+         +---+---+---+---+---+
                 | 1 |-------->| - | a | b | 0 |
                 +---+         +---+---+---+---+
                 | 2 |-------->| - | c | 0 |
                 +---+         +---+---+---+---+---+---+
 argv ---------->| 3 |-------->| H | e | l | l | o | 0 |
                 +---+         +---+---+---+---+---+---+
                 | 4 |-------->| W | o | r | l | d | 0 |
                 +---+         +---+---+---+---+---+---+
                 | 5 |-------->NULL
                 +---+

这有帮助吗?

答案 1 :(得分:5)

是的,你是对的。

while(--argc > 0 && (*++argv)[0] == '-')

逐个扫描命令行参数的数组(长度为argc),查找以-选项前缀开头的数组。对于每一个:

while(c = *++argv[0])

正在浏览当前参数中的第一个-后面的一组切换字符(即t中的n-tn,直到它到达字符串null终结符\0,它终止while循环,因为它的计算结果为false。

这种设计允许两者

myApp -t -n

myApp -tn

同时工作并被理解为具有选项tn

答案 2 :(得分:5)

增加argv是一个非常糟糕的主意,因为一旦你这样做,很难恢复原始值。使用整数索引更简单,更清晰,更好 - 毕竟argv是一个数组!

要回答你的问题,++ argv会增加指针。然后将其应用于间接以获取第一个字符。

答案 3 :(得分:4)

括号会更改表达式的计算顺序。

没有括号*++argv[0]

  1. argv[0]获取指向argv当前指向的字符数据的指针。
  2. ++将该指针递增到字符数组中的下一个字符。
  3. *获得角色。
  4. 括号(*++argv)[0]

    1. ++argv将argv指针递增为指向下一个参数。
    2. *表示它获取指向字符数据的指针。
    3. [0]获取字符数组中的第一个字符。

答案 4 :(得分:2)

是的,这两个表达式有所不同(尽管只是略有不同)。 IMO,这段代码有点过于聪明。你最好用这样的东西:

for (int i=1; i<argc; i++)
    if (argv[i][0] == '-') {
       size_t len = strlen(argv[i]);
       for (int j=0; j<len; ++j)
           switch(argv[i][j]) {
               case 'x':
               // ...

这几乎与上面的代码相同,但是我怀疑任何人(根本不知道C)会弄清楚它究竟是做什么的。