【问题标题】:Using fscanf to read an input file fails mid-line使用 fscanf 读取输入文件中线失败
【发布时间】:2017-10-22 17:04:16
【问题描述】:

很久了,第一次。我已经对此进行了大量挖掘,但无济于事,所以我会马上解决...

我正在使用 C 语言从事一个物理研究项目。我正在尝试读取输入值文件...每行包含 12 个以空格分隔的 double 类型值,输入文件长 1006 行。由于文件输入是众所周知的,因此我选择使用 fscanf() 来摄取输入,执行重新排序的操作,然后将其输出到另一个更适合 gnuplot 使用的文件中。这是问题行和有问题的问题行之前的行:

2.250000000000000 0.500000000000000 2.668878914693362 0.081121085306632 2.668879345525446 0.081120608880718 0.081120609109235 2.668879508723290 -1.139145600698256 -0.478208465494011 -0.476544273039587 -0.184392862164658
2.250000000000000 0.550000000000000 2.723599351123168 0.076400593002322 2.723599435547186 0.076400582995125 0.076400821024960 2.723599264264542 -0.996035795911154 -0.408011755823990 -0.409827430433329 -0.178196609653836

我目前要做的就是读取文件并在添加更多逻辑之前仅输出我关心的内容,但 fscanf() 存在问题。相关代码如下(包括调试语句):

int readEOF = 0;
double maxThreePhaseParticleCount = 0.0;
double particlesATotal = 0.0;
double particlesBTotal = 0.0;
double rhoA1 = 0;
double rhoA2 = 0;
double rhoA3 = 0;
double rhoB1 = 0;
double rhoB2 = 0;
double rhoB3 = 0;

FILE * two_phase_coords;
char two_phase_coords_name[255];
sprintf(two_phase_coords_name,"~/threePhaseDiagram-densities-twoPhases_tcA%f_tcB%f_aA%f_aAB%f_aB%f.dat", tcA, tcB, aA, aAB, aB);
two_phase_coords = fopen(two_phase_coords_name, "r");

readEOF = fscanf(two_phase_coords, "%lf %lf %lf %lf %lf %lf %lf %lf %*lf %*lf %*lf %*lf", &particlesATotal, &particlesBTotal, &rhoA1, &rhoB1, &rhoA2, &rhoB2, &rhoA3, &rhoB3);
while (readEOF != EOF) {
    readEOF = fscanf(two_phase_coords, "%lf %lf %lf %lf %lf %lf %lf %lf %*lf %*lf %*lf %*lf", &particlesATotal, &particlesBTotal, &rhoA1, &rhoB1, &rhoA2, &rhoB2, &rhoA3, &rhoB3);
    printf("just read %i...\n%.15f %.15f %.15f %.15f %.15f %.15f %.15f %.15f %.15f\n", readEOF, particlesATotal, particlesBTotal, maxThreePhaseParticleCount, rhoA1, rhoB1, rhoA2, rhoB2, rhoA3, rhoB3);
}

问题行的第 6 个字段(1006 行中的第 988 行)是事情发生的地方...不是读出 0.076400582995125,而是读取值 0.000000000000000... readEOF 返回 6 而不是预期的 8 ,并且 fscanf() 在下一次循环迭代中失败/返回 EOF。

我很困惑。我尝试过的事情......

  1. 大量谷歌搜索。
  2. 从 fscanf() 更改为 fgets()/sscanf()...失败发生在完全相同的位置,剩余的 18 行仍未处理。
  3. 正在为问题行之前的行和问题行创建 1000 多个副本的虚拟输入文件...每个文件的处理都已完成且没有错误。
  4. 使用十六进制编辑器检查输入文件...问题行前后的所有内容在我看来都像是标准/预期的 ASCII。
  5. 将每个输入行上的所有 12 个值读取到单独的变量中(即不使用 fscanf() 中的 %*lf 中的忽略字符)。
  6. 大量谷歌搜索。

我将不胜感激任何帮助......自从我成为 C 大师以来已经有很长时间了。由于这是我的第一篇 SO 帖子,如果我不小心践踏了任何社区期望/礼仪,请提前道歉。

感谢大家的帮助!!

【问题讨论】:

  • sprintf(two_phase_coords_name,"~/threePhaseDiagra ... 我不认为 fopen() 理解波浪号扩展。另外:您应该测试从 fopen 获得的结果。并且..不要重复自己...并且:可能在特定位置有一个奇怪的角色。
  • 建议您提供指向确切输入文件的链接。通常,输入应在问题中内联提供。但是由于在这种情况下它很长并且确切的文件很关键,所以应该可以接受例外。另外请提供minimal reproducible example,以便我们可以完全按照所示复制和运行以重现问题。
  • 输入文件会出现故障。因此,除了修复它之外,您无能为力,这可能无法实现,具体取决于数据的来源和损坏方式。
  • 请注意,shell 在文件名中扩展了~,但fopen() 没有。您应该始终测试来自fopen() 的返回值——文件可能发生了一些事情,导致打开失败。

标签: c io scanf


【解决方案1】:

所以我不确定这种情况发生的频率,但在我发布这个问题之后,我自然而然地设法追踪发生了什么......有问题的函数是更大环境的一部分,并且调用这个函数在指向输入文件的文件指针关闭之前发生(未定义的行为)。我想自己投反对票。

感谢大家的参与!

【讨论】:

  • 这表明错误发生在磁盘块边界(通常为 4K)。如果你真的想参与防御性编程,这个程序可能已经计算出它发生的文件偏移量,你会有一个提示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多