Выбранный ответ Адама Розенфилда неверен. Ответ Coobird тоже. По этой причине я проголосовал против обоих ответов.
Адам Марковиц интерпретирует *lineptr++
правильно, но он не отвечает на главный вопрос, является ли это законным кодом C99. Только Том Будущий делает; к сожалению, он не объясняет *lineptr++
. Я дал им по одному очку.
Итак, для краткости, lineptr
является переменной и может управляться как указатель. Таким образом, законно увеличивать указатель.
lineptr
- указатель на последовательность указателей на последовательности символов. Другими словами, это указатель на первую строку массива строк. Согласно коду, мы можем предположить, что строки являются нулевыми ('\ 0') символами в конце. nlines
- количество строк в массиве.
Тестовое выражение while: nlines-- > 0
. nlines--
- это пост-декремент (потому что --
справа от переменной). Таким образом, он выполняется после теста был выполнен и независимо от результата теста, так что в любом случае.
Итак, если значение nlines
, заданное в качестве аргумента, было 0
, тест выполняется первым и возвращает false
; инструкции в цикле не выполняются. Обратите внимание, что поскольку nlines
все равно уменьшается, значение nlines
после цикла while
будет -1
.
Если nlines == 1
, тест вернет true
и nlines
будет уменьшено; инструкции в цикле будут выполнены один раз. Обратите внимание, что во время выполнения этих инструкций значение nlines
равно 0
. Когда тест проводится снова, мы возвращаемся к случаю, когда nlines == 0
.
В инструкции printf
используется выражение *lineptr++
. Это постинкрементный указатель (++
справа от переменной). Это означает, что выражение вычисляется первым, а приращение выполняется после его использования. Таким образом, при первом выполнении printf
получает копию первого элемента массива строк, который является указателем на первый символ строки. lineptr
увеличивается только после этого. В следующий раз, когда будет выполнено printf
, lineptr
будет указывать на второй элемент и перейдет к третьему, когда будет напечатана вторая строка. Это имеет смысл, потому что мы, очевидно, хотим напечатать первую строку. Если бы Адам Розенфилд был прав, первая строка была бы пропущена, и в конце мы попытались бы напечатать строку за последней, что, очевидно, является плохой вещью.
Итак, инструкция printf
представляет собой краткую форму двух следующих инструкций
printf("%s\n", *lineptr);
++lineptr; // or lineptr++, which is equivalent but not as good. lineptr += 1; is ok too.
Обратите внимание, как правило, когда предварительное и последующее увеличение эквивалентны по своему действию, предварительное увеличение предпочтительнее по соображениям производительности. Компиляторы позаботятся, чтобы переключить его для вас. Ну, большую часть времени. Лучше, если это возможно, самим предоператорам, поэтому они используются всегда. Причина становится более очевидной, когда вы сами реализуете пост- и прекремент в C ++.