【问题标题】:Regarding about file input and output in C关于C中的文件输入和输出
【发布时间】:2014-09-15 23:57:58
【问题描述】:

除非我真的被卡住了,否则我通常不会在这里提问!我想知道是否有人可以解释为什么我的代码会打印出“5 47”。我明白为什么有 5,但不明白为什么有 47?例如,我查找了空格 (32) 的 ASCII 值,并尝试将第二个字母更改为 e、f、g,但输出保持“5 47”不变。

一般来说,当我使用fscanf(fp, "%d", &variablename) 时,fscanf 会跳过杂项字符吗?例如:在我的文件 test.txt 中,我有“5 hello 6 ben jerry\n”。我将如何扫描 5 和 6? fscanf(fp, "%d %d", &test1, &test2) 会在 5 和 6 中扫描,跳过“你好”这个词吗?

这是我用来测试输出的简单代码:

int main(int argc, char *argv[]) {
  int blah, test;
  FILE * fp;
  fp = fopen(argv[1], "r");
  fscanf(fp, "%d %d", &blah, &test);
  printf("%d %d\n", blah, test);
  return 0;
}

我正在使用的文件作为 argv[1] 内容:

5g

附: FILE *fp 是指向每个字符/数字的实际指针,它在扫描文件时是否用作占位符?这就是我们需要rewind(fp) 到达文件末尾的原因吗?

【问题讨论】:

  • 您从未检查过fscanf 的结果,这会告诉您只有一个值被成功解析。由于您从未初始化 test,它的值是不确定的,您的输出也应该是。 fscanf() 的行为方式可以阅读 here 或直接访问源代码并阅读 C 标准。
  • 我很困惑。那么 fscanf 是否在 g 或空格中扫描到 test 中?它适用于'blah'......为什么它不适用于'test'?我看了那个页面,我还是不明白为什么。请详细说明。谢谢
  • 我无法比 cppreference 的作者(他们是 C/C++ 社区中非常口语良好的成员)更好地描述它。该链接是关于 scanf 系列函数如何工作的罗塞塔石碑,值得您花 5 分钟以上的时间。

标签: c file input output


【解决方案1】:

运算符 %d 查找整数,而不是字符。因为 g 是一个字符,而不是一个整数,所以 %d 会变得混乱,并且输出并不总是 5 47。47 可以是任何东西。它可能是 5 7、5 23 等。这是因为 fscanf 没有读取第二个数字,因此没有为测试分配值。因此,测试保持在程序启动时位于该内存块中的值。

要解决此问题,请将 %d 替换为 %c 并将 blah 和 test 的类型更改为 int。此外,正如 WhozCraig 所说,检查 fscanf 的返回值以检查是否找到了两个值是一种很好的做法。这样,您就可以确定您要查找的所有内容都已找到。

【讨论】:

    【解决方案2】:

    请注意,scanf() 系列函数在遇到格式字符串不期望的字符时会停止读取。意外字符留在输入中以供下一个输入操作处理。

    如果你想读取两个整数,它们肯定被一个不是整数的“单词”分隔,那么你需要跳过这个单词。如果您事先不知道该词是什么,则需要使用赋值抑制(有关大量信息,请参阅 POSIX scanf() 页面)。

    因此,您的代码从包含的输入中读取两个整数

    5 hello 6 ben jerry
    

    应该是:

    if (fscanf(fp, "%d %*s %d", &blah, &test) != 2)
        …Oops; format error?…
    

    请注意,代码测试它得到了预期的结果。但是,如果您不知道两个数字之间是否存在单词,则最好使用fgets()sscanf(),因为您可以尝试对同一行进行不同的解析:

    char buffer[4096];
    
    while (fgets(buffer, sizeof(buffer), fp) != 0)
    {
        if (sscanf(buffer, "%d %*s %d", &blah, &test) == 2)
            …got two numbers with a word — let's go!
        else if (sscanf(buffer, "%d %d", &blah, &test) == 2)
            …got two numbers but no word — let's go!
        else
            …didn't recognize the format…
    }
    

    这样做的主要优点之一是您可以根据完整的输入行报告错误,而不仅仅是fscanf() 无法处理的部分。

    关于FILE *,您的最后一个问题不是指向文件中每个字符的指针。它是一个句柄,允许您调用以文件指针参数读取或写入关联文件的函数。但是,您不能使用基于文件指针的索引(因此fp[1024] 确实 not 识别文件中偏移量 1024 处的字符或类似的任何有用的东西)。如果你想要这种行为,你需要一个内存映射文件(mmap() 用于 POSIX 系统)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-10
      • 1970-01-01
      • 2018-07-06
      • 2012-11-15
      • 1970-01-01
      相关资源
      最近更新 更多