【问题标题】:Plain C reading from a data file从数据文件读取纯 C
【发布时间】:2014-07-21 22:45:31
【问题描述】:

我在 Ubuntu 12.04.4 LTS 32 位上使用编译器 gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3,使用 fscanf 函数从文件中读取有点问题.格式说明符 %f 无法读入代码中声明为双精度的变量,但 %lf 有效。这种差异背后的原因是什么?我在下面提供了一个代码 sn-p 和一个数据文件:

编辑:我在使用以下代码 sn-p 的较大代码中遇到分段错误。我已经尝试删除前两行并摆脱 char 和两个 fgets 调用,但它不起作用。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
#include <fftw3.h>
#define N 3500
int main(void)
{
    FILE * data = fopen("data_1657.dta", "r"), * fft = fopen("fftq3.dat", "w+");
    if(!data) // Checking if the file opened succesfully
        return 1;
    fftw_complex *in, *out;
    fftw_plan forward;
    forward = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
    double *t, *ft, *err;
    int i = 0;
    t = (double *) malloc(sizeof(double) * N);
    ft = (double *) malloc(sizeof(double) * N);
    err = (double *) malloc(sizeof(double) * N);
    char str [100];
    fgets(str, 100, data);
    fgets(str, 100, data);
    while (fscanf(data, "%lf    %lf     %lf", &t[i], &ft[i], &err[i]) == 3)
    {
        printf("%lf \t %lf \n", t[i], ft[i]);
        i++;
    }


    fftw_execute(forward);
    fclose(data);
    fclose(fft);
    fftw_destroy_plan(forward);
    fftw_free(in);
    fftw_free(out);
    free(t);
    free(ft);
    return 0;
}

编辑:更正循环

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

int main(void)
{
    FILE * data = fopen("data_1657.dta", "r");
    double t, count, err;
while (fscanf(data, "%lf %lf %lf", &t, &count, &err) == 3)
{
    printf("%f \t %f \t %f \n", t, count, err);
}   


    return 0;
}




  time in seconds       count rate(c/s)  error
   ---------------------    --------      -------
    281.3251281976699829     115.639      21.228
    281.8250962048768997     149.639      22.774
    282.3250641971826553     111.639      21.039
    282.8250322043895721     155.639      23.036
    283.3250001966953278     141.639      22.420
    283.8249682039022446     107.639      20.848
    284.3249361962080002     135.639      22.151
    284.8249042034149170     151.639      22.861
    285.3248721957206726     127.639      21.786
    285.8248402029275894     143.639      22.509
    286.3248081952333450     129.639      21.878
    286.8247760981321335     123.639      21.602
    287.3247441053390503      93.639      20.166
    287.8247120976448059      95.639      20.264
    288.3246801048517227     131.639      21.969
    288.8246480971574783     127.639      21.786
    289.3246161043643951     107.639      20.848
    289.8245840966701508      91.639      20.066
    290.3245521038770676      77.639      19.356
    290.8245200961828232     115.639      21.228
    291.3244881033897400     109.639      20.944
    291.8244560956954956     125.639      21.694
    292.3244241029024124     107.639      20.848
    292.8243920952081680     105.639      20.752
    293.3243599981069565     133.639      22.060
    293.8243280053138733     183.639      24.221
    294.3242959976196289     161.639      23.295
    294.8242640048265457     141.639      22.420

顺便说一句,在不删除数据文件中的两个标题行的情况下,是否可以从数据文件的第三行开始读取?

提前致谢

【问题讨论】:

  • 您可以使用 fgets() 读取一行文本。对前两行执行两次,使用之后丢弃的缓冲区。或者,您可以只读取字符,直到您点击两次 '\n'
  • 我一点也不知道为什么%lf 为你工作而%f 不是,但从长远来看,如果你用@ 一次阅读整行,你会更快乐987654321@(不是标准的,但本系统应该存在),然后使用strtod解析行并将字符串转换为浮点数。 strtod 加上列上的内部循环是解析此输入格式所需的全部内容。您将跳过外部 getline 循环中的前两行。
  • @Zack 我可以试试,谢谢你的建议。
  • 您的代码只保存(打印)奇数行(第 1、3、5 ...)。
  • 您的 do { fscanf(…); printf(…); } while (fscanf(…) != 3); 循环是错误的,因为它为每个打印的一个数字读取两组数字,并且因为它不检查第一个 fscanf() 的状态。一般来说,您应该警惕do … while 循环; I/O 更是如此。你需要while (fscanf(…) == 3) { printf(…); }——在顶部测试循环并明确检查每个输入操作。

标签: c gcc file-io scanf


【解决方案1】:

(f)scanf() 看到%lf 时,它需要一个指向double 的指针(通常是64 位) 而不是%f,它只需要一个指向float 的指针(通常是 32 位)。

scanf: %f — float; %lf — double; %Lf — long double

【讨论】:

  • 双精度和浮点数的大小取决于实现,即使在具有相同编译器的同一系统上使用编译器标志也可能会发生变化。
  • 好吧,但假设它遵循 IEE754 - 这会使尺寸始终固定吗?
  • @PeterSchneider 这是真的,但无关紧要; %f 总是与float 一起使用,%lfdouble 一起使用,%Lflong double 一起使用。 (我自己应该记得的。)
  • 我只想看到句子“当 (f)scanf() 看到 %lf 它期望一个指向 64 位变量的指针”消失,因为它完全错误(作为一般性陈述)。 IEEE浮点数可能是真的,我没查。
  • 一个更好的表达方式(但我已经做出了重大改变)是:%lf,它需要一个指向 double 的指针(通常是指向一个 64 位变量),而不是 %f,它只需要一个指向 float 的指针(通常是一个指向 32 位变量的指针)。 '通常'的使用涵盖了正常情况但允许古怪。
【解决方案2】:

如果您正在读取双变量,则需要%lf。 scanf 不是类型安全的;您必须通过仔细匹配格式说明符与变量类型来帮助该功能。 %ld 等也一样。

【讨论】:

    猜你喜欢
    • 2015-11-24
    • 2013-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多