Viku
Viku

Reputation: 2973

strncpy is not working as expected

#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?

Upvotes: 0

Views: 5964

Answers (4)

timothyqiu
timothyqiu

Reputation: 1122

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.

Upvotes: 0

TieDad
TieDad

Reputation: 9929

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.

Upvotes: 4

Adam Rosenfield
Adam Rosenfield

Reputation: 400642

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.

Upvotes: 6

Klarth
Klarth

Reputation: 2045

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'

Upvotes: 1

Related Questions