Reputation:
I was thinking of making a strncpy alternative with terminating '\0' for my own use in a header file, and am wondering what of the following approaches would be better.
int copystring(char *dest,char *source,int elements)
{
int run;
for(run=0;run<elements-1;run++)//last reserved for'\0'
{
dest[run]=source [run];
if (dest[run]=='\0')
{
break;
}
}
dest[elements-1]='\0';//could make conditional but not neccesary.
return 0;
}
OR
int copystring(char *dest,char *source,int elements)
{
strncpy(dest,source,elements-1);
dest[elements-1]='\0';
return 0;
}
The obvious difference to me is that I'm calling one less function with version one, but I was wondering if version two has any advantages, as I don't know the internal workings of strncpy()
As an aside, why does strncpy() take size_t as the final argument? if it's for passing sizeof values, which will only be useful in very limited circumstances, wouldn't an int do just as well?
Upvotes: 2
Views: 983
Reputation: 263497
The simplest replacement for strncpy()
(if you feel that you need one) is probably this:
dest[0] = '\0';
strncat(dest, source, size);
strncat()
, unlike strncpy()
, guarantees that the target is properly null-terminated, and doesn't copy extra null bytes when the target is bigger than the source.
But be sure that this behavior is really what you want. If you use strcpy()
and the target array isn't big enough, you get undefined behavior. With strncpy
or strncat
, you get defined behavior: the value is quietly truncated. If that's what you want, great -- but it rarely is. More commonly, truncating data just gives you bad data, and you should detect it and handle it as an error rather than Procusteanly discarding whatever won't fit. (Imaging truncating "rm -rf $HOME/unimportant_directory"
to "rm -rf $HOME"
before passing it to system()
.)
As an aside, why does
strncpy()
takesize_t
as the final argument? if it's for passingsizeof
values, which will only be useful in very limited circumstances, wouldn't anint
do just as well?
size_t
just makes more sense, since it's the type used to represent sizes and lengths. Using int
would require defining (or leaving undefined) the behavior for negative arguments, and could limit the size of the string you could handle (if, say, int
is 16 bits and size_t
is 32 bits). You can always pass an int
value, and it will be implicitly converted to size_t
.
Another option is the non-standard strlcpy()
function. It's not available on all systems, but you should be able to install it (for example, using the libbsd-dev
package for Debian/Ubuntu/... systems) or build it from source.
Incidentally, here's my rant on the topic of strncpy()
:
http://the-flat-trantor-society.blogspot.com/2012/03/no-strncpy-is-not-safer-strcpy.html
Upvotes: 2