C:strncpy意外截断字符串

时间:2016-09-19 01:18:50

标签: 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

2 个答案:

答案 0 :(得分:3)

第一个标记由10个字节组成:18306000\0

strncpy()只有在符合目标缓冲区的情况下才会写入空字符。但是你分配的一个字符太少而不是。

最简单的解决方法是在两个strtok调用的分隔符中包含空格:

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

我还建议您使用snprintf()代替strncpy,这样您就可以保证在字符串末尾获得一个空字符。

答案 1 :(得分: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是安全的。