2016-09-19 263 views
0

我正在逐行读取文件,其中每行的格式为:C:strncpy意外截断字符串

“number1 \ t number2”。

我正在使用strtok和strncpy来分割,然后根据需要存储这两个值。 但是,我发现在strncpy之后,number1被截断了一个数字。

任何想法,为什么这可能是以及如何解决它?

为了简单起见,我硬编码了line_of_text来模拟问题。

谢谢!

代码:

#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); 

} 

输出:

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

'“18306000 100 \ n”'是'“\ t18306000 \ t100 \ n”'? – BLUEPIXY

+0

不,它是:“18306000 \ t100 \ n” - 所以只有两个值之间的选项卡,其余是空格。对不起,我之前没有说清楚。 – Sadia1990

+1

在字符串文字中使用'\ t'(对于'line_of_text')来显示标签的位置 - 这就是转义序列的用途!你可能需要在调用'strtok()'时使用'“\ t”'作为分隔符,就像@BLUEPIXY指出的那样(相当简单)。请注意,您需要在字符串上允许空终止符;你遇到了缓冲区溢出和未定义的行为,因为你不能确保你的字符串足够短。请记住,如果源太长而不适合,'strncpy()'不会终止目标。所有'strn *()'函数都有怪癖。 –

回答

2

第一令牌由10个字节组成:18306000\0

strncpy()只写入空字符,如果它适合目标缓冲区。但是你已经分配了一个字符太少,所以它没有。

最简单的解决方法是包括两个strtok的电话等分隔的空间:

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

我也建议使用snprintf()代替strncpy所以你总是保证在最后得到一个空字符你的字符串。

+3

该标记实际上是空间,空间,空间,空间,空间,18306000。共12个字符(不含终结者) –

+0

好的,非常感谢!我将digits_per_num的值增加到了12,并且已经解决了这个问题。 – Sadia1990

1

问题是缓冲区不够大的字符串;在这种情况下,strncpy函数不会空终止缓冲区。

只是按照您在评论中所建议的方式增加缓冲区大小并不是一个可靠的解决方案,因为如果有人提供具有更长数字的不同输入,则会重复出现相同的问题。

一种选择是手动终止缓冲:

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

(注:使用sizeof first_token代替digits_per_num会更稳健太)。

但是在这种情况下,无效输入由无声截断处理。如果这个不适合你的程序,那么你可以使用不同的逻辑,并且完全避免了直观strncpy功能:

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

它的安全使用strcpy当先前检查的长度。