Is K&R teaching bad readability?
It has been a while since I looked at C (still learning) and I just got back into the K&R book.
I just had a go to Exercise 5-3 (p107).
Write a pointer version of the function strcat that we showed in Chapter 2: strcat(s,t) copies the string t to the end of s.
I came up with this...
void strcat(char *s, char *t);
void strcat(char *s, char *t) {
while (*s++ != '\0');
s--;
while (*t != '\0') {
*s++ = *t++;
}
*--t = '\0';
}
int main() {
char str[] = "Hey, hello";
char str2[] = " are you?";
strcat(开发者_开发百科str, str2);
printf("%s\n", str);
return 0;
}
It seems to work.
What I am wondering, is that the K&R book often writes exercises with as little lines as possible - I'd expect had they provided their own code sample for above, you'd get things like this...
void strcat(char *s, char *t) {
while (*s++ != '\0');
s--;
while ((*s++ = *t++) != '\0');
*--t = '\0';
}
To me, this is less readable (maybe this example isn't as good, but I often look at their code and think if that was separated into a few lines, I'd understand it much better). The examples provided in the book seem to advocate this sort of assignment in the condition part of a loop, and in fact cramming as much code as possible per line.
Is the book right in trying to do as much possible where you can, even if readability suffers?
Is this just The C Way?
K&R explain the importance of idioms in the book. Yes, brevity of code is valued by C programmers, but it's not deliberately terse to punish beginners. After some time reading and writing C you start to recognize patterns, so when you see them in someone else's code you know what you're looking at.
Go through the iterations of strcpy()
given as an example in K&R -- they explain their philosophy of brevity vs. clarity, and talk about idioms.
You should not expect your program to work, since you are invoking undefined behavior.
You define two buffers of a certain size (str
is 11 bytes long, str2
is 10 bytes long). Then, during strcat
, you try to write to str[11]
, which doesn't exist. From this point on there is no guarantee whatsoever about the execution of your program. It may crash, it may do what you expected, or it might just print "42" and make you wonder why.
Furthermore, you should not change *t
in strcat
, since in newer versions of C t
has type const char *
.
And third, when re-implementing a function that is also provided by your environment, give it another name. Otherwise your compiler might replace it with some builtin code that is equivalent to the function call. For example GCC has __builtin_strlen
which sometimes replaces calls to strlen
.
The fixed version of the code looks like this:
#include <stdio.h>
/* renamed strcat to str_cat to avoid confusing the compiler */
void str_cat(char *s, const char *t) { /* added the const qualifier to t */
while (*s++ != '\0');
s--;
while (*t != '\0') {
*s++ = *t++;
}
/* removed the needless modification of *t */
*s = '\0'; /* edit: added this line after the comment from Jonathan Leffler */
}
int main() {
char str[80] = "Hey, hello"; /* note the large array size here */
char str2[] = " are you?";
str_cat(str, str2);
printf("%s\n", str);
return 0;
}
Other more readable, more efficient examples can be found by using Google Codesearch.
Look at the source code for Android and BSD in particular as good examples of more modern C implementation of strcat
.
Instead of strcat
you should be writing an implementation of strlcat
and many examples of that source can be found as well.
精彩评论