Reputation: 97
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
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
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