pts@watt.acc.Virginia.EDU (Paul T. Shannon) (05/10/89)
I have a question on the strncpy library function. (The same question applies to strcpy as well.) This program fragment seems to be the recommended usage: char *original, *copy; /* assume that original points to a string */ int stringLength; stringLength = strlen (original); copy = malloc (stringLength + 1); /* allow room for terminating null */ copy = strncpy (copy, original, stringLength); Why is this function written so that the pointer to the destination string is both 1. passed as an argument to the function, and 2. returned by the function? Paul Shannon
scs@sloth.pika.mit.edu (Steve Summit) (05/11/89)
In article <630@babbage.acc.virginia.edu> pts@watt.acc.Virginia.EDU (Paul T. Shannon) writes: >Why is [strncpy] written so that the pointer to the destination string is >both > 1. passed as an argument to the function, and > 2. returned by the function? I think the answer is "because nobody could think of anything else for it to return." (It is occasionally suggested, both for str[n]cpy and str[n]cat, that returning a pointer to the end of the copied characters would have been more useful.) The one use I've seen for str[n]cpy's return value is the following idiom, which is close to what you were trying to do: copy = strcpy(alloc(strlen(original) + 1), original); The purported advantage here is that you only have one assignment to "copy," which is more "concise." The disadvantage is that someone reading the code might be puzzled. It's probably not worth arguing about; I tend to split my usage between the idiom and the two-line form copy = alloc(strlen(original) + 1); (void)strcpy(copy, original); depending on what mood I'm in. (Note that the one-line form absolutely depends on a "safe" wrapper around malloc, that checks for a NULL return and prints an error message and exits or something rather than returning NULL. I usually call my wrapper function "alloc," as in the examples above.) Returning to your code, you don't want to use strncpy after all: > > char *original, *copy; /* assume that original points to a string */ > int stringLength; > > stringLength = strlen (original); > copy = malloc (stringLength + 1); /* allow room for terminating null */ > copy = strncpy (copy, original, stringLength); Your copied string won't necessarily be nul-terminated, and in fact strncpy does not guarantee nul termination in any case. The third argument to strncpy tells it how many characters it may write to the destination string, including the nul termination. If strncpy runs out of room for the nul, it won't append it. On those (rare, because of the lack of a guarantee) occasions when I use strncpy, it's usually something like (void)strncpy(dest, src, len); dest[len] = '\0'; /* ensure nul termination */ (presumably, if I'm using strncpy in the first place, I can handle truncation, so losing one more character won't hurt). Another little-known fact about strncpy is that it pads the destination string with nuls (\0's) out to the requested length, even if that means appending more than one nul. (That is, char buf[14] = "xxxxxxxxxxxxxx"; strncpy(buf, "hello.c", 14); leaves "hello.c\0\0\0\0\0\0\0" in buf.) The only reason I know of for this behavior is that the old V7 filesystem required it*; if you patched a directory entry by hand, but left garbage within a 14-character filename slot but after what you thought was a trailing nul, the filename couldn't be found. (The kernel evidently did something more like memcmp than strncmp when searching for filenames. I'm drifting into unix-wizards territory here; don't assume that this scenario had any affect on normal user programs. Henry will correct me if this didn't apply to "vanilla" V7; it did come up in V7 derivatives I've used.) I wouldn't depend on the nul-padding behavior, but if you're ever writing a strncpy, you'd better provide it, because there are undoubtedly programs out there that do depend on it. Steve Summit scs@adam.pika.mit.edu * This is, I'll admit, a far-fetched argument; the kernel isn't necessarily linked against the same C library routines as are user programs.
rkl@cbnewsh.ATT.COM (kevin.laux) (05/11/89)
In article <630@babbage.acc.virginia.edu>, pts@watt.acc.Virginia.EDU (Paul T. Shannon) writes: } I have a question on the strncpy library function. (The same question applies to } strcpy as well.) This program fragment seems to be the recommended usage: } [deleted fragment] } } Why is this function written so that the pointer to the destination string is } both } 1. passed as an argument to the function, and } 2. returned by the function? } The return of the destination pointer allows for the function to be passed as an argument to other functions, as in: printf ("<format...> %s\n", <args>, strncpy (dest, src, count)); --rkl