Ответ 1
Во-первых, K & R имеют ошибки в этом конкретном фрагменте:
117 (§5.10): В примере поиска программа увеличивает
argv[0]
. Это специально не запрещено, но не разрешено также.
Теперь для объяснения.
Скажем, ваша программа называется prog
, и вы выполняете ее с помощью: prog -ab -c Hello World
. Вы хотите проанализировать аргументы, чтобы сказать, что были указаны параметры a
, b
и c
, а Hello
и World
- аргументы без параметров.
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]
in (*++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
+---+
Помогает ли это?