strncpy()

Jeffrey Kegler jeff at rlgvax.UUCP
Sat Aug 20 03:10:54 AEST 1983


As most of you know, the UNIX philosophy is to have everything have
explicit terminators, instead of being terminated by counts.

In strcpy() this has raised the complaint that a slight error in an
argument to strcpy() can result is destruction of a considerable amount
of data.  This could happen when the string to be copied is not
properly terminated, or is a bad pointer, or is just overlong.  One can
say that it is really up to the programmer to check for these things.
Another part of the UNIX philosophy is, wherever something might be
seen as either a protection or a restriction of the programmer,
depending on point of view, to assume it is a restriction.

For those of us who do desire to be protected from our own lapses,
especially when these lapses may lead to a core with its stack
destroyed, strncpy() exists.  It takes a third argument which gives an
explicit maximum length to the string.  However, for some strange
reason, it still does not guarantee its result will be null terminated
if it is overlong.  Instead it puts characters right up into the last
permitted location.  Always writing

		strncpy(string1, string2, n);
		string1[n] = '\0';

solves the problem, but whenever I see this in code, I wonder why
UNIX's string copy of explicitly n characters does not always result in
a string of n characters.

Further, it always copies a string of the length specified, adding
nulls once the source string has been terminated.  I can think of
situations where this is useful, but one has never occurred to me, and
far more often I wind up copying a string whose maximum length is 5000
and whose average length is 10.  So as a byproduct of this feature, I
would get an average of 4990 extra trips through the loop.

Finally, strncpy() is far less efficient than it could be.  Its main
loop maintains and updates both a string pointer and a count, and each
character copied requires a comparison to n, which is not is a
register.  I would get more into its behavior, but I do not know if the
code is public domain, unlike strcpy(), 4 versions of which are in K&R
on pages 100-101.

Below is the code for my rewrite of strncpy(), which never accesses
anything except a register in its main loop (if your compiler supports
this sort of thing), has a main loop one instruction shorter on the VAX
(all claims are for code generated by the C optimizer), guarantees the
copied string will be a legal string, even where the original was not,
and does no copying beyond the end-of-string.  The main efficiency
improvement does not depend on my changes from the behavior of
strncpy(), and scpy() could be rewritten to simulate strncpy()
exactly.

===========================

/*
 * Copy a string in a fail-safe manner.
 */
void
scpy(s1,s2,n)
register char *s1,*s2;
{
	register char *eos = s1+n-1;

	while(*s1++ = *s2++)
		if (s1 >= eos) {
			*eos = '\0';
			return;
		}
}

==============================

One could argue that the above is not as fail-safe as it should be, because
if n is zero or negative, the byte before s1 is zeroed, and a check for
such an n could be placed before the main loop.



More information about the Comp.lang.c mailing list