On pg. 109 of K&R, we see:
void writelines(char *lineptr[], int nlines)
{
while (nlines -- > 0) printf("%s\n", *lineptr++);
}
I'm confused about what *lineptr++ does exactly. From my understanding, printf requires a char pointer, so we provide that with *lineptr. Then we increment lineptr up to the next char pointer in the array? Isn't this illegal?
On page 99, K&R writes that "an array name is not a variable; constructions like a=pa [where a is an array, pa is a pointer to an array] and a++ are illegal."
The selected answer of Adam Rosenfield is wrong. The answer of coobird too. For that reason I down voted both answers.
Adam Markowitz interpretation of *lineptr++
is right, but he doesn't answer the main question whether this is legal C99 code. Only Tom Future does; unfortunately he doesn't explain *lineptr++
. I granted them a point each.
So for short, lineptr
is a variable and can be manipulated as a pointer. It is thus legal to increment the pointer.
lineptr
is a pointer into a sequence of pointers to sequences of chars. In other words it is a pointer to the first string of a string array. According to the code we can assume that the strings are null ('\0') terminated char sequences. nlines
is the number of strings in the array.
The while test expression is nlines-- > 0
. nlines--
is a post decrement (because --
is on the right of the variable). It is thus executed after the test has been performed and regardless of the test result, so in any case.
So, if the nlines
value given as argument was 0
, the test is performed first and returns false
; the instructions in the loop are not executed. Note that since nlines
is decremented anyway, the value of nlines
after the while
loop will be -1
.
If nlines == 1
, the test will return true
and nlines
will be decremented; the instructions in the loop will be executed once. Note that while these instructions are executed the value of nlines
is 0
. When the test is performed again, we are back to the case when nlines == 0
.
The printf
instruction uses the *lineptr++
expression. It is a post increment of the pointer (++
is on the right of the variable). This means the expression is evaluated first and the increment is performed after its use. So on the first execution printf
receives a copy of the first element of the string array, which is a pointer to the first char of the strings. The lineptr
is incremented only after that. The next time the printf
is to be executed, lineptr
points on the second element and will be move to the third when the second string has been printed. This makes sense because we obviously want to print the first string. If Adam Rosenfield was right, the first string would have been skipped and at the end we would try to print the string beyond the last one which is obviously a bad thing to do.
So, the printf
instruction is a concise form of the two following instructions
printf("%s\n", *lineptr);
++lineptr; // or lineptr++, which is equivalent but not as good. lineptr += 1; is ok too.
Note, as a rule of thumb, that when pre- and post-increment are equivalent in their action, the pre-increment is preferable for performance reasons. The compilers will take care to switch it for you. Well, most of the time. It is better to the the pre- operators yourself, whenever possible, so it is used always. The reason becomes more explicit once you implement a post- and pre- increment yourself in C++.