views:

242

answers:

3

Hello.

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?

+9  A: 

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.

gregjor
+2  A: 

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;

}
Roland Illig
+1 thanks for all this useful information!
alex
You're right that `*--t = '\0';` should not contain the decrement; but you do need to null terminate the string with `*t = '\0';` because the loop does not copy the NUL.
Jonathan Leffler
Maybe the code was meant to be `*s = '\0'`. I still don't see a reason to modify anything related to `t`. When `strcat` is called, `t` is already assumed to point to a string, which (by definition) includes that it is NUL-terminated.
Roland Illig
A: 

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.

drewk