【问题标题】:Reading an array of floats from a file in C从 C 中的文件中读取浮点数数组
【发布时间】:2021-10-19 21:20:51
【问题描述】:

如何从 C 中的文件中检索浮点值数组?这是我到目前为止使用的代码,但我遇到了分段错误(在我的代码中标记)。如果您看到一种不那么痛苦的方法,那也会有所帮助。

值存储在文件中,每个值后面都有一个空格,如下所示:

-667.0897114275529 544.6798599456312 -148.0586015260273 -323.4504101541069 .

// open file
  FILE *fp;
  fp = fopen(sig_file, "r");
  if (fp == NULL){
    printf("File opened incorrectly or is empty");
    return 1;
  } 

// find file size
  fseek(fp, 0L, SEEK_END);
  long sz = ftell(fp);
  fseek(fp, 0L, SEEK_SET);

 // store file contents to f_contents
  char *f_contents = 0;
  f_contents = malloc(sz);
  if (f_contents){
    fread(f_contents, 1, sz, fp);
  } 
  fclose(fp);
  if (f_contents){

// find how many points are in the file
    long pt_count = 0;
    int i;
    for (i=0; i<sz; i++){
      if (f_contents[i] == ' '){
        pt_count++; 
      } 
    } 

// store points to a float array
    double signal[pt_count];
    char *pt;
    pt = strtok(f_contents, " ");
// seg fault 11:
    if (pt == NULL){
      printf("error with pt");
      return 1;
    }
    signal[0] = atof(pt);
//
    for (i=1; i<pt_count; i++){
      pt = strtok(NULL, " ");
      signal[i] = atof(pt);
    } 
  }
  free(f_contents);

【问题讨论】:

  • 既然你算了有多少分,你不想float signal[pt_count];for (i=1; i&lt;pt_count; i++){吗?每次使用前还需要检查strtok返回的指针是否不是NULL
  • 请注意,示例输入包含的数字比float 类型可以表示的精度高得多。你确定不想要doubles 吗?
  • 为什么不用fscanf() 而不是自己用strtok()atof() 解析文件?
  • 小提示,不要小看return的力量。 if (!f_contents){ fclose(fp); printf("failed to malloc\n"); return; } 此后无需进一步检查 f_contents 是否有效。

标签: arrays c string file segmentation-fault


【解决方案1】:

如果您发现一种不那么痛苦的方法,那也会有所帮助。

我没有对您的代码进行足够的研究来确定段错误的来源,因为无论如何它都应该被重写。我可能更倾向于做这样的事情:

  // open file
  FILE *fp = fopen(sig_file, "r");

  if (fp == NULL){
    perror("fopen");
    return 1;
  }

  size_t sz = 0;

  for (int c = getc(fp); c != EOF; c = getc(fp)) {
      if (c == ' ') sz++;
  }

  rewind(fp);

  double signal[sz];
  for (size_t i = 0; i < sz; i++) {
    if (fscanf(fp, "%lf", &signal[i]) != 1) {
        fclose(fp);
        fputs("I/O error, malformed input, or premature EOF\n", stderr);
        return 1;
    }
  }

  fclose(fp);

如果文件很长,那么一次读取所有文件可能是值得的,而不是先计算元素(尤其是不要将整个文件放入内存中)。您可以通过将值存储在更灵活的数据结构中来实现这种一次性读取:某种链表或动态分配(并根据需要重新分配)数组。

链表需要后处理为数组形式,但您可以按原样使用动态分配的数组。您将需要使用动态分配的数组或足够大的固定大小数组和不支持可变长度数组的 C 实现,例如 MS Visual Studio。

【讨论】:

  • 应该明确的是,如果条目列表太大,这个例子会导致堆栈溢出,因为它正在为signal使用本地堆栈分配,在这种情况下使用malloc会更合适。建议使用动态重新分配/链接列表是一个好主意。
  • @Geoffrey,VLA 的使用是在模仿 OP 的代码。另外,因为我忍不住有点迂腐:C 语言规范不需要 C 实现来通过堆栈分配实现 VLA。甚至根本不使用堆栈。
  • 非常正确,但对于 C 的新手来说,OP cleary 似乎是,这是他们可能不知道的事情,因此最好通知他们防止简单的复制和粘贴这段代码。
【解决方案2】:

strtok() 的第一个参数必须是一个以 null 结尾的字符串。 fread() 没有添加空终止符,即使添加了,您也没有为 f_contents 分配足够的空间来容纳它。

所以用这个代码分配和填写f_contents

  f_contents = malloc(sz+1);
  if (f_contents){
    fread(f_contents, 1, sz, fp);
    f_contents[sz] = '\0';
  } 
  fclose(fp);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-24
    • 2011-02-15
    • 2012-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多