0
#include <iostream>
using namespace std 
#include <string.h>
int main(){
    char token[] = "some random string";
    char c[23];  
    strcpy( c, token);
    strncpy(c, token, 5); 
    c[strlen(c)] = '\0';
    cout<<c;
    return 0 ;
}

My output is: some random string. But I expect it to be: some. Can anyone please explain why it is behaving like this?

Deanie
  • 2,316
  • 2
  • 19
  • 35
Viku
  • 2,845
  • 4
  • 35
  • 63

4 Answers4

6

It's working just fine—bear in mind that strncpy does not necessarily null-terminate the string. When you do this:

strncpy(c, token, 5);

It copies the first 5 bytes of token into c but does not null-terminate the result. Furthermore, this line is useless:

c[strlen(c)] = '\0';

strlen(c) looks for an existing null terminator, and as soon as you find one, you overwrite it with another null terminator, which is pointless.

In new code, strncpy should seldom, if ever be used. Its intended use (fixed-length buffers which are not necessarily null-terminated) have long been obseleted. Prefer instead a function like strlcpy (note: strlcpy is not standard; it's only available in BSD-like systems).

Or, if you're coding in C++ instead of pure C, just use std::string and avoid tricky issues like this altogether.

Community
  • 1
  • 1
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • if i have to explicitely give the '\0' . Then i can get output some by making c[4] = '\0' without calling strncpy(..). Then what is the importance of strncpy(...); – Viku Dec 25 '12 at 04:14
  • The importance of strncpy is to avoid buffer overflows. Think about what would happen if the destination buffer was smaller than the source string. – drescherjm Dec 25 '12 at 04:23
  • 1
    Although I second the recommendation. If this is C++ I would avoid using any of these and instead use std::string. – drescherjm Dec 25 '12 at 04:26
4

I think your output should be "some random string", because your two lines of code do nothing, see the comment.

int main(){
   char token[] = "some random string";
   char c[23];  
   strcpy( c, token);
   strncpy(c, token, 5);  // Does nothing
   c[strlen(c)] = '\0';   // Does nothing
   cout<<c;
   return 0 ;
}

If you want to output "some", you could do this:

strncpy(c, token, 5);
c[5] = '\0';

strncpy() doesn't automatically add trailing '\0' to dest string. If the source string length is bigger than len (3rd argument of strncpy), then len characters copied to dest without trailing '\0'. So you have to give a trailing '\0' explicitly by code.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
TieDad
  • 9,143
  • 5
  • 32
  • 58
  • After strncpy(c,token , 5) , has been executed , value of c shall be some . please correct if i am wrong . – Viku Dec 25 '12 at 04:00
  • 1
    strncpy() doesn't automatically add tailing '\0' to dest string. If the source string length is bigger than len (3rd argument of strncpy), then up to len characters copied to dest without tailing '\0'. So you have to give a tailing '\0' explicitly by code. – TieDad Dec 25 '12 at 04:05
  • if i have to explicitely give the '\0' . Then i can get output some by making c[4] = '\0' without calling strncpy(..). Then what is the importance of strncpy(...); – Viku Dec 25 '12 at 04:14
  • 1
    strncpy is used to make sure not overflow dest buffer. strcpy doesn't care how big dest buffer is, it will not stop copying characters to dest until it found a '\0'. – TieDad Dec 25 '12 at 04:18
  • This answer should be awarded a medal! Thanks. – Vishal Anand Feb 23 '19 at 08:10
1

You need to null terminate after the word "some" instead of null terminating after the entire string. strncpy will copy "some " into c, but it does not necessarily null terminate your string (see man page for strncpy)

c[4] = '\0'
Klarth
  • 2,035
  • 14
  • 26
0

As others have mentioned, unlike snprintf to sprintf, strncpy is not a safer version of strcpy. It merely ensures that "exactly N characters are copied to destination (use NUL if source string is shorter than N)". (man page)

But I think you've already noticed that by the line

c[strlen(c)] = '\0';

It meant to ensure the null termination of c. But it is actually pointless since strlen uses NUL to determine the length of c. So this line barely means "find NUL and write NUL to that location".

The importance of strncpy is to copy a certian part of string. It is not a fix to strcpy, and existed before the introduction of snprintf functions.

timothyqiu
  • 1,072
  • 11
  • 23