【问题标题】:Why does fscanf ignore the first string in my text file? [closed]为什么 fscanf 会忽略我的文本文件中的第一个字符串? [关闭]
【发布时间】:2018-12-22 04:17:33
【问题描述】:

我想从文件的每一行中读取 2 个字符串和一个整数。文件中的空白位置未知。第一个字符串的长度未指定,第二个字符串为 2 个字符。代码如下:

int main (int argc, char **argv)
{
    char firstString[50], secondString[2];
    int number = 0;
    FILE *fp;

    fp = fopen(argv[1], "r"); // Opens file to read
    if (fp == NULL) // Checks if file exists
    {
        printf("Error in opening file.\n");
        exit(0);
    }

    while (fscanf(fp, "%50s %2s %1d", firstString, secondString, number) == 3)
    {
        printf("First String is %s.\n", firstString);
        printf("Second String is %s.\n", secondString);
        printf("Number is %d.\n", number);
    }

    fclose(fp);
    return 0;
}

输出总是类似于:

First String is .

Second String is AB.

Number is 3.

First String is .

Second String is CD.

Number is 1.

【问题讨论】:

  • 旁白:secondString[2] 不足以容纳%2s 指定的长度为 2 的字符串。空终止符没有空间。同样,第一个说明符应该是%49s
  • number ==> &number.
  • 您的代码无法编译。什么是患者 ID?编辑您的问题。还包括一个示例输入文件。
  • stringlength可能是2,但是需要的数组size是3。
  • 请发布显示问题的Minimal, Complete, and Verifiable example。该代码显然不是您正在使用的代码。不要遗漏#include 库标题。

标签: c file scanf


【解决方案1】:

如果要读取 50 个字符的字符串,则数组需要能够容纳 51 个字符。这是因为在 C 中,字符串总是以 \0 字符结尾。所以把数组声明改成这一行:

char firstString[50], secondString[2];

您的代码中的另一个问题是您需要在fscanf 语句中的number 前面放置一个&。像这样:

while (fscanf(fp, "%50s %2s %1d", firstString, secondString, &number) == 3)

很高兴您检查了fopenfscanf 的返回值。您应该做的另一件事是打开编译器警告。使用 -Wall -Wextra 编译代码会产生以下警告:

warning: format ‘%d’ expects argument of type ‘int *’, but argument 5 has type ‘int’ [-Wformat=]
     while (fscanf(fp, "%50s %2s %1d", firstString, secondString, number) == 3)
                                   ^
warning: unused parameter ‘argc’ [-Wunused-parameter]
 int main (int argc, char **argv)
               ^~~~

如您所见,警告提示您number 的问题。

另一个警告不是很重要。不使用argc 并不总是错误的,但您可以通过以下方式使您的代码更安全:

if(argc < 2) {
     printf("No input file given as argument.\n");
     exit(0);
}

将错误消息打印到 stderr 而不是 stdout 也是一个好主意。使用perror 是一种方法。与printf 非常相似的另一种方法是只使用fprintf。实际上,fprintf(stdout, ... ) 的含义与printf( ... ) 相同。所以只需使用 fprintf 并指定 stderr。您的第一个错误打印输出可能是 fprintf(stderr, "Error in opening file: %s\n", argv[1])

【讨论】:

    【解决方案2】:

    我认为您可能会在 firstString 中得到一个空字符串,因为 secondString 的长度不足以容纳 2 个字符 一个空字节,而且碰巧在您的使用编译器的机器,secondString 存储在内存中的 firstString 之前。当fscanf()AB 和一个空字节复制到secondString 时,空字节会删除firstString 的第一个字节,使其看起来(是)空的。

    您可以通过打印 &amp;firstString[1]"[%s]" 来证明这一点,并看到它包含您所期望的大部分内容。

    标准不保证该布局;这只是一个合理的猜测,可以解释你所看到的。您要么需要使用%2c 而不是%2s 才能将AB 转换为secondString(但是名称'string' 是用词不当;它不再是一个以null 结尾的字符串)。或者您需要将secondString 的大小增加到至少 3 个字节——允许终端为空。 firstString 也有类似的大小问题。代码中数组的大小(例如 N 字节)与 scanf() 格式的字符串大小(N-1 字节)之间的“一比一”差异令人讨厌,但多年的传统却使之成为神圣(因此它出现在 1978 年左右的第 7 版 Unix 中)。可悲的是,现在改变它比独自离开更糟糕。

    您还需要修复对fscanf() 的调用,以便您传递&amp;number 而不仅仅是number

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-08
      • 2020-05-23
      • 1970-01-01
      • 2014-06-15
      • 2017-09-06
      • 1970-01-01
      • 1970-01-01
      • 2020-07-15
      相关资源
      最近更新 更多