2

I just run this code and what i get for n=1 is not what i expect to get. Can you explain why is this happening?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXRIGA 11
int main()
{
    char s[MAXRIGA+2];
    char a[MAXRIGA]="pippo";
    strncpy(s, a, 1); //       n=1
    printf("%s", s);
    return 0;
}

returns

pF

instead if n=2 or more i get what i want.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXRIGA 11
int main()
{
    char s[MAXRIGA+2];
    char a[MAXRIGA]="pippo";
    strncpy(s, a, 2); //       n=2
    printf("%s", s);
    return 0;
}

returns

pi
Synchronyze
  • 128
  • 1
  • 10
  • 2
    Try `char s[MAXRIGA+2] = {0};`. – Fiddling Bits Dec 29 '15 at 21:51
  • 1
    DO NOT USE `strncpy`, it does not do what you think it does. If you think you know, think again and read the C documentation to verify. – chqrlie Dec 29 '15 at 21:53
  • 4
    My rant on the `strncpy` function: http://the-flat-trantor-society.blogspot.com/2012/03/no-strncpy-is-not-safer-strcpy.html – Keith Thompson Dec 29 '15 at 21:55
  • Read Keith's column, very informative. Note that `strncat` is not a safer version of `strcat` either, it is just a variant that limits the number of characters it appends to the destination buffer, but it is cumbersome to use it to avoid buffer overflows. – chqrlie Dec 29 '15 at 22:00

3 Answers3

9

From man strncpy:

The strncpy() function is similar, except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.

You are copying only one byte from the source string, which is not a null-terminator. So you get an undefined behavior here, as trying to print a non-terminated string. The same for n=2, which appears to work by accident.

Eugene Sh.
  • 17,802
  • 8
  • 40
  • 61
5

strncpy does not append the null terminator onto strings. You need to manually add it after using strncpy.

Like this:

strncpy(s, a, 1); //       n=1
s[1]=0;
printf("%s", s);

The F (from pF) is simply any arbitrary character that still happens to reside in the position in memory encountered before any null terminator is found. Strictly speaking your code should produce Buffer overrun error, or Access violation error.

Add the null terminator after using strncpy and your problem will disappear :)

Grantly
  • 2,546
  • 2
  • 21
  • 31
  • 1
    `strncpy` does not append the null terminator onto strings *unless there's enough room to do so*. – Keith Thompson Dec 29 '15 at 21:54
  • 1
    @KeithThompson It is not appending them anyway. It is copying them, if the source contain them. – Eugene Sh. Dec 29 '15 at 21:55
  • 2
    @EugeneSh. actually, if there is room, it **is** appending null bytes all the way to the end of the destination buffer!!! This thing is a specialized function that should not have made it into the standard. – chqrlie Dec 29 '15 at 22:03
  • Actually EugeneSh is correct. strncpy appends nothing. It only copies what it is 'told' to copy... Whether there is a null terminator in the characters to be copied is irrelevant, it is poignant to caution anyone who uses strncpy to ensure that null terminators are 'appended'. (Unless you really know what you are doing, unlike the OP) – Grantly Dec 29 '15 at 22:08
  • Well, yeah. From the man page: `If the length of src is less than n, strncpy() writes additional null bytes to dest to ensure that a total of n bytes are written.` So it is *padding* the source by nulls. But only if it has one already :) – Eugene Sh. Dec 29 '15 at 22:24
  • @Grantly: I'm not sure what you mean. The word *append* might not be the best to describe the padding behavior. The fact that the destination is not null terminated if the source is longer is the real problem with `strncpy`. I have seen countless occurrences of bad usage of this function. An overwhelming majority to be precise. It is never the right tool for the job, because even in the very few cases where its semantics are a good fit, it still gives casual readers the wrong message. – chqrlie Dec 29 '15 at 22:55
  • I used the word 'append' to try to be precise, and to fit the question. It does do padding and copying - and for a novice - it does not append a null terminator. Even though padding and appending can be presumed the same. When trouble starts - like with the OP - it is suffice to point out that the coder must 'append' the null terminator either directly or indirectly. – Grantly Dec 29 '15 at 23:45
3

Since you are not initializing the array s it contains random values. Strings in C are terminated by a NULL character, so when you initialize the array a with "pippo" the values it contains are:

offset | 0 | 1 | 2 | 3 | 4 |  5 |
value  | p | i | p | p | o | \0 |

When you call printf it needs to decide where the end of the string is and it does this by printing characters until it gets to the terminating NULL. If s contains random data and you only copy in a single character then printf will print the string until it gets to a byte that happens to be NULL. In this case, it looks like the 3rd byte of the random data was \0 so printf prints characters up to that point.

Turn
  • 6,656
  • 32
  • 41