Ilustration picture of C programming






C is quirky; take, for instance, the way arrays, strings and pointers are related, and how this relationship can be exploited. As an example:
while(*t++ = *s++);
Given that s is the source string to be copied and t is the destination, this while loop copies the string from s to t. This curt code is possible because of the following: strings are implemented as an array of characters, and the starting of a string is an address (pointer). We can traverse an array by starting from the base of the array, and perform pointer arithmetic to access the elements.
In this code, as long as the characters from the source are non-NULL characters, the truth value in the while loop is non-zero (which is considered true), and hence the characters will be copied to the destination. When the source character value in the string is \0 or NULL, the while condition will be zero, and hence the loop will terminate. The result is that it copies the string from source to destination.

Of course, lots of things can go wrong in code like this.
Here, in the expression *s++, it is difficult to find out which operator has higher precedence — is it dereference (*) or is it postfix increment (++)?
If you look at the large operator precedence table, you’ll find that postfix increment (++) has higher precedence than dereference (*), and hence s++ is executed first, followed by *.
However, because ++ is postfix here, s++ is not effective till the end-of-the-statement (or more technically, the sequence point), and hence *s++ will be the value of the current character of the string to which s points.

Also, from *s++, it is not clear if the ++ applies to the underlying location in the string, or the character in the string. Since ++ is applied first, it applies to the address in the underlying string, which has the effect of changing the address to point to the next character.
Further, in the while loop, we purposefully use = instead of == (to assign the character). As you know, this behaviour is prone to bugs; in fact, mistyping = instead of == is one of the most common sources of bugs in C.

Similarly, there are many other quirks. Consider break and continue statements, for example. The break statement can be used within switch statements or the body of loops (while, for, and do-while). However, the continue statement can be used only within the body of loops, and not within switch statements. That’s a quirk.

By default, if we forget to use a break statement, control will fall-through to the next statement. If you think about it, it makes sense to use continue also — it could direct the control flow to continue to the next case statement, instead of having the default behaviour being to fall-through to the next statement. In this way, it could have also prevented countless bugs caused by forgetting break statements within switch statements.

Komentar