Exercise 5-5. Write versions of the library functions
strncpy,strncat, andstrncmp, which operate on at most the firstncharacters of their argument strings. For example,strncpy(s,t,n)copies at mostncharacters ofttos. See the description in Appendix B.
Three functions, each with a character count limit n. The non-obvious behaviour from the C standard is worth matching exactly: strncpy pads with null bytes if t is shorter than n, and does not null-terminate if t is exactly or longer than n. strncat always null-terminates. strncmp returns the difference of the first differing characters (or 0 if the first n match).
Solution
/* K&R Exercise 5-5 — strncpy, strncat, strncmp
* Compile: gcc -ansi -Wall ex5-5.c -o ex5-5 */
#include <stdio.h>
/* Copy at most n chars of t into s; pad with '\0' if t is shorter than n.
* Does NOT null-terminate if t has n or more characters. */
char *my_strncpy(char *s, const char *t, int n)
{
char *start = s;
while (n > 0 && *t != '\0') {
*s++ = *t++;
n--;
}
while (n-- > 0) /* pad with nulls */
*s++ = '\0';
return start;
}
/* Append at most n chars of t to s; always null-terminates. */
char *my_strncat(char *s, const char *t, int n)
{
char *start = s;
while (*s) s++; /* advance to end of s */
while (n-- > 0 && *t != '\0')
*s++ = *t++;
*s = '\0'; /* always null-terminate */
return start;
}
/* Compare at most n chars of s and t; return negative/0/positive. */
int my_strncmp(const char *s, const char *t, int n)
{
for ( ; n > 0; n--, s++, t++) {
if (*s != *t)
return (unsigned char)*s - (unsigned char)*t;
if (*s == '\0')
return 0; /* both ended before n chars */
}
return 0;
}
int main(void)
{
char buf[20];
/* strncpy */
my_strncpy(buf, "hello", 3);
buf[3] = '\0'; /* must terminate manually when n <= strlen(t) */
printf("strncpy 3: '%s'\n", buf); /* hel */
my_strncpy(buf, "hi", 8);
printf("strncpy 8: '%s' (padded with nulls)\n", buf); /* hi + 6 nulls */
/* strncat */
char s[20] = "foo";
my_strncat(s, "barbaz", 3);
printf("strncat 3: '%s'\n", s); /* foobar */
/* strncmp */
printf("strncmp abc/abd 2: %d\n", my_strncmp("abc","abd",2)); /* 0 */
printf("strncmp abc/abd 3: %d\n", my_strncmp("abc","abd",3)); /* negative */
printf("strncmp abc/abc 5: %d\n", my_strncmp("abc","abc",5)); /* 0 */
return 0;
}
Compile and Run
gcc -ansi -Wall ex5-5.c -o ex5-5
./ex5-5
Sample Output
strncpy 3: 'hel' strncpy 8: 'hi' (padded with nulls) strncat 3: 'foobar' strncmp abc/abd 2: 0 strncmp abc/abd 3: -1 strncmp abc/abc 5: 0
What This Exercise Teaches
strncpynull-padding rule — this is one of C’s famous gotchas: iftis shorter thann, the extra space is zeroed; but iftis longer, no null terminator is added — the caller must add itstrncatalways terminates — unlikestrncpy,strncatalways writes a'\0'after the appended characters; the buffer needs room forstrlen(s) + n + 1bytes- Unsigned char in comparison —
(unsigned char)*s - (unsigned char)*tavoids sign-extension bugs when characters have values > 127
Set Up Your C Environment
← Exercise 5-4 |
Chapter 5 Solutions |
Exercise 5-6 →
Book: The C Programming Language, 2nd Ed — Kernighan & Ritchie