Разница между (*++argv) [0] и while (c = *++argv[0])

у меня есть следующий фрагмент кода:

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 %cn", c);
                  argc = 0;
                  found = -1;
                  break;
          }

     ...
}

, содержащие следующие выражения:

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

делает ли это выражение в скобках (*++argv)[0] отличается от while(c = *++argv[0]) без скобок?

если да, то как? Делает (*++argv) означает указатель на следующий аргумент, а не *++argv[0] средний указатель на следующий символ в текущем массиве символов, на который указывается?

5 ответов


во-первых, у K&R есть ошибки на этом конкретном фрагменте:

117(§5.10): в найти пример, программа увеличивает argv[0]. Это не запрещено, но и не разрешено.

теперь для объяснения.

Допустим, ваша программа называется prog, и вы выполняете его с:prog -ab -c Hello World. Вы хотите иметь возможность анализировать аргументы, чтобы сказать, что options a, b и c были указаны и Hello и World являются аргументами non-option.

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] is NULL. В начале, argv[0] - это char * содержит строку "prog".

на (*++argv)[0] из-за скобки, argv сначала увеличивается, и затем разыграли. Эффект приращения состоит в том, чтобы переместить это argv ----------> стрелка "один блок вниз", чтобы указать на 1. Эффект разыменования заключается в том, чтобы получить указатель на первый аргумент командной строки,-ab. Наконец, возьмем первый символ ([0] на (*++argv)[0]) этой строки и проверьте ее, чтобы узнать, является ли она '-', потому что это означает начало вариант.

для второй конструкции мы действительно хотим спуститься по строке, на которую указывает текущий


Incrementing argv-очень плохая идея, так как после этого вам трудно вернуть исходное значение. Проще, понятнее и лучше использовать целочисленный индекс - ведь argv-это массив!

чтобы ответить на ваш вопрос ++argv увеличивает указатель. Затем к нему применяется косвенность, чтобы получить первый символ.


да, вы правы.

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

сканирует массив (длины argc) аргументов командной строки один за другим, ища те, которые начинаются с - префикс вариант. Для каждого из них:

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

просматривает набор символов переключателя, которые следуют за первым - в текущем аргументе (т. е. t и n на -tn, пока он не попадет в строку null terminator , который завершает цикл while, так как он оценивает как ложный.

эта конструкция позволяет как

myApp -t -n

и

myApp -tn

как работать, так и пониматься как имеющие параметры t и n.


скобки изменяют порядок вычисления выражений.

без скобок *++argv[0]:

  1. argv[0] получает указатель на символьные данные, на которые в настоящее время указывает argv.
  2. ++ увеличивает указатель на следующий символ в массиве символов.
  3. * возвращает символ.

в скобки (*++argv)[0]:

  1. ++argv увеличивает argv указатель на следующий аргумент.
  2. * переносит его, чтобы получить указатель на символьные данные.
  3. [0] получает первый символ в символьном массиве.

да, два выражения различаются (хотя и незначительно). ИМО, этот код немного на чрезмерно умной стороне. Тебе бы лучше сделать что-нибудь вроде этого:--2-->

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) будет иметь какие-либо трудности с выяснением того, что он действительно делает.