【问题标题】:Can't get txt file to print correctly无法正确打印 txt 文件
【发布时间】:2014-03-09 19:50:20
【问题描述】:

这是我的 C 编程课的家庭作业。

给我一​​个文本文件,有两个数据列;第一列是age;第二列是avgprice。我能够很好地读取和打印这些值。但是,由于某种原因,ageavgprice 在输出中被翻转。我不知道为什么。

这里是代码

#include "stdafx.h"
#include <stdio.h>

int main() {

double age, avgprice; //age = 1st column, avgprice = 2nd column
FILE *corolla; //ptr for file
char eof; //needed for end of file check

corolla = fopen("C:/Users/Nate/Downloads/DataFiles/corolla.txt", "r");
if (corolla == NULL) { //makes sure the file exists
    printf("File does not exist!\n");
    return 0; //prevents crashing
}
else {
    printf("Age \t\t Average Price\n"); //header for data when printed
    /*prints values until we're at the end of the file*/
    while (fscanf(corolla, "%c", &eof) != EOF) {
        fscanf(corolla, "%lf %lf", &age, &avgprice); //scans in data from file
        printf("%.1f \t\t $%.2f\n", age, avgprice); //prints data from file
    }
}
fclose(corolla); //closes file
return 0;
}

这是输出的样子

这让我很困惑,因为我已经使用这种确切的格式对其他数据文件做同样的事情——没有问题。由于某种原因,这个文件有困难。

这是我应该阅读的数据文件。我已将它上传到我的 Dropbox,这样您就可以在必要时检查格式。 Corolla.txt

【问题讨论】:

  • 诚实地说这是家庭作业并且您已发布代码,因此您会获得 +1。
  • 你的第一个fscanf 吞下了“1”。之后,您的输入是错误的,因为fscanf 不知道换行符。 (嗯,确实如此,但它像对待任何其他空间一样对待它们。)
  • 参见例如关于如何使用 fscanf stackoverflow.com/a/3351926/297323

标签: c file while-loop


【解决方案1】:

这一行:

while (fscanf(corolla, "%c", &eof) != EOF)

从文件中读取一个字符。文件中的第一个字符是1,因此它将1 读入eof

你的下一行是:

fscanf(corolla, "%lf %lf", &age, &avgprice); 

它按顺序从文件中读取接下来的两个条目,它们是139902。所以第一个年龄是13990,第一个平均价格是2

之后,文件指针现在指向2 之后的空白区域。去的时候:

fscanf(corolla, "%c", &eof)

它将一个空格读入eof

然后当你到达:

fscanf(corolla, "%lf %lf", &age, &avgprice); 

它读取接下来的两个值,分别是 13495 和 3。以此类推。

要解决此问题,您应该停止使用fscanf(corolla, "%c", &amp;eof)。我不知道你期望这会做什么,但它不会测试你是否在文件的末尾。相反,它读取一个字符,忽略该字符,并检查 fscanf 的返回值。

修复您的代码:

while (2 == fscanf(corolla, "%lf %lf", &age, &avgprice))
{
    printf("%.1f \t\t $%.2f\n", age, avgprice); //prints data from file
}

fscanf 的返回值是成功读取的项目数(如果成功)。当它返回 2 以外的内容时,您知道您一定已经到达文件末尾。

【讨论】:

  • 注意。正如 M Oehm 指出的那样,这种读取文件的方法无法检测到您是否有一行包含许多不是 2 的项目,并且它不能跳过输入文件中的错误等。如果你想处理更多种类的输入,那么您将需要做一些更复杂的事情,例如他建议的方法。
  • 我明白了,这更有意义。我没有得到的是我能够使用这个代码:Code,并且它很好地打印了这个数据:Data
【解决方案2】:

您的输入文件使用基于行的格式。 fscanf 逐块读取输入块。块通常是由空格分隔的东西,可以是空格、制表符甚至换行符。因此fscanf 不适合读取基于行的格式。

在我看来,最好分两步读取输入:首先,用fgets 读取一行,然后用sscanf 从该行读取数据。例如:

#include <stdlib.h>
#include <stdio.h>

int main()
{
    FILE *f;
    int line = 0;

    f = fopen("kk", "r");
    if (f == NULL) {
        printf("File does not exist!\n");
        return 0;
    }
    printf("%20s%20s\n", "age", "avg. price ($)");

    for (;;) {
        char buffer[80];
        int age, price;

        if (fgets(buffer, sizeof(buffer), f) == NULL) break;
        line++;

        if (sscanf(buffer, "%d %d", &age, &price) < 2) {
            printf("(Skipping bad input in line %d).\n", line);
        } else {
            printf("%20d%20d\n", age, price);
        }
    }
    fclose(f);

    return 0;
}

这也为您提供了一种低级错误报告。

另外,通常不需要对EOF 进行额外检查。到达文件末尾时,文件输入函数返回一个特殊值。 fscanfgetc 返回 EOF; fgets 返回NULL。通常最好根据这些返回值停止阅读。

在您的情况下,fscanf("%c", &amp;oef) 吃掉了文件中的第一个字符,即数字 1。幸运的是,之后它只以换行符为食,因此您的输入不会更糟。 (但是将您的扫描格式更改为"%lf %lf " 以大幅降低价格。)

【讨论】:

  • 我会考虑使用 sizeof buffer 而不是 100 ,这将有助于避免缓冲区溢出...:) 此外,如果 fgets 不消耗整行,那么代码应该在进入下一个循环迭代之前丢弃该行的其余部分。
  • @MOehm,尽管我很想这样做——这不是我的教授希望我们使用的。他希望我们使用fscanf 来完成这项任务。我们还没有开始学习数组和缓冲区。
  • @MattMcNabb:对于 80 的缓冲区大小来说,100 是一个错误的估计吗? (修正了这个问题,有点脸红。)关于超长线被视为几行也是正确的。为了简单起见,我暂时保留它。
  • @Nate:好吧,不知道。无论如何,Matt McNabb 有一个答案给你。
  • 我很感激你的回答!抱歉,我没有在 OP 中澄清。
猜你喜欢
  • 2017-03-23
  • 1970-01-01
  • 1970-01-01
  • 2013-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-01
  • 1970-01-01
相关资源
最近更新 更多