Sadia1990
Sadia1990

Reputation: 97

C: strncpy unexpectedly truncating string

I am reading a file line by line, where each line is of the format:

" number1 \t number2".

I am using strtok and strncpy to split and then store the two values as needed. However, I find that after strncpy, number1 is truncated by one digit.

Any ideas of why this could be and how to solve it?

For simplicity, I have hard coded a line_of_text to simulate the problem.

Thanks!

Code:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


int main()
{
  char line_of_text[80] = "  18306000  \t 100\n"; 
  // NB: There's a \t between the two values, the rest are spaces.

  char* token;

  int digits_per_num = 9;

  char first_token[digits_per_num];
  char second_token[digits_per_num];

  token = strtok (line_of_text, "\t");

  printf("first token: %s\n", token);

  if (token != NULL)
    {
      strncpy (first_token, token, digits_per_num);
    }

    token = strtok (NULL, ",\t\n");
    if (token != NULL)
    {
      strncpy (second_token, token, digits_per_num);
    }


    printf("first token copy: %s\n", first_token);
    printf("second token copy: %s\n", second_token);

}

Output:

first token:  18306000
first token copy: 1830600<junk>
second token copy: 100

Upvotes: 0

Views: 1384

Answers (2)

M.M
M.M

Reputation: 141648

The problem is that the buffer is not big enough for the string; and the strncpy function does not null-terminate the buffer in that case.

Just increasing the buffer size as you suggested in comments is not a robust solution, as then if someone supplies different input with a longer number, the same problem will recur.

One option is to manually terminate the buffer:

strncpy(first_token, token, digits_per_num);
first_token[digits_per_num - 1] = 0;

(Note: using sizeof first_token instead of digits_per_num would be more robust too).

However in this case the invalid input is handled by silent truncation. If this does not suit your program then you could use different logic, and entirely avoid the unintuitive strncpy function:

if ( strlen(token) + 1 > digits_per_num )
{
     fprintf(stderr, "Error, input was more than 9 digits\n");
     exit(EXIT_FAILURE);
}
strcpy(first_token, token);

It's safe to use strcpy when you previously checked the length.

Upvotes: 1

Bill Lynch
Bill Lynch

Reputation: 82006

The first token consists of the 10 bytes: 18306000\0.

strncpy() only writes the null character in if it fits in the destination buffer. But you've allocated one character too few so it doesn't.

The easiest fix is to include spaces in your delimiter on both strtok calls:

token = strtok (line_of_text, " \t\n,");

I'd also recommend using snprintf() instead of strncpy so you're always guaranteed to get a null character at the end of your strings.

Upvotes: 4

Related Questions