【问题标题】:How to read values from an unspecified file size and store them dynamically in a vector in C?如何从未指定的文件大小中读取值并将它们动态存储在 C 中的向量中?
【发布时间】:2016-07-24 17:31:49
【问题描述】:

说我有一个numbers.txt 文件,其大小未指定double 数字。

我需要将这些值动态存储在double *note 指针中以供以后使用。

我尝试了以下代码,但它给出了核心转储:

FILE *ifile = fopen("numbers.txt", "r");
double *note;
int i = 1; 

note = (double *) malloc( i * sizeof( double));
fscanf( ifile, "%lf", &note[0]); 

while ( !feof( ifile)) {
      i++;
      note = (double *) realloc( note, i * sizeof( double));
      fscanf( ifile, "%lf", &note[i]);
}       

for (n=0; n < i; n++) {
     printf( "%lf\n", note[i]);
}

【问题讨论】:

  • 您没有为 note[1] 分配任何值。
  • @SergeBallesta 练习指定不要使用大小有限的向量。
  • @SergeBallesta "不相关,但重新分配每个新值是一种反模式。"在编码犯罪领域,为每次循环迭代调用realloc() 是尽可能轻微的冒犯。而且我什至不确定它是否应该被视为一个反模式——这样的代码比realloc() 的大块代码更简单、更容易编写和维护。它只是更慢。也许吧。

标签: c algorithm file pointers vector


【解决方案1】:

每次使用 note[i] 时,您的代码都会越界访问数组。

在 (wrong) while 循环中,它总是超过最后一个元素(例如,在第一次迭代中,i 变为 2,为两个 doubles 分配了足够的空间,但您访问 note[2]是第三个)。

在打印时,您使用n 作为递增循环索引,但始终打印note[i] 而不是note[n]

检查所有使用的库函数的返回值也是一个好习惯,例如opennewreallocscanf

这些问题的快速修复可能是以下 sn-p。请注意,我(每次)都使用与您相同的重新分配策略,但正如@Serge Ballesta 指出的那样,这可能效率低下。例如,查看@Jean-François Fabre 答案中显示的替代方案。

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

int main() {
    double value,
           *note = NULL,
           *newptr = NULL;

    int i,
        size = 0;

    char file_name[] = "numbers.txt";
    FILE *ifile = fopen(file_name, "r");
    if ( !ifile ) {
        fprintf(stderr, "Error while opening file %s.\n", file_name);
        exit(EXIT_FAILURE);
    }

    while ( fscanf(ifile, "%lf", &value) == 1 ) {
        size++;
        newptr = realloc(note, size * sizeof(double));
        if ( !newptr ) {
            fprintf(stderr, "Error while reallocating memory.\n");
            free(note);
            exit(EXIT_FAILURE);
        }
        note = newptr;
        note[size - 1] = value;
    }       

    for (i=0; i < size; i++) {
        printf( "%lf\n", note[i]);
    }

    free(note);     // <-- don't leak memory!
    fclose(ifile);
    return EXIT_SUCCESS;
}

【讨论】:

    【解决方案2】:

    您的 i 从 0 传递到 2,并且您的索引永久超出您的边界:您分配 2 个双精度数,并写入索引 2,即第三个。 也不要忘记关闭您的文件。 并且最终的打印在应该使用 n 的地方使用 i。把常用的字母混在一起不好(i代表循环索引,n代表限制),最后大家都会糊涂。

    最好按照以下方式简化/分解您的代码,这样可以避免该错误:

    作为奖励,我添加了一个避免每次重新分配的机制,这在性能方面不是很好。

    以下代码已经过测试并且可以运行

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    FILE *ifile = fopen("numbers.txt", "r");
    double v,*note=NULL;
    int i = 0,n; 
    int alloc_step = 10;
    int note_size = 0;
    
    while ( !feof( ifile)) {
          fscanf( ifile, "%lf", &v);
          if ((i % alloc_step)==0)
          {
              note_size += alloc_step;
              note = (double *) realloc( note, note_size * sizeof( double));
          }
          note[i++] = v;
    
    }       
    
    for (n=0; n < i; n++) {
         printf( "%lf\n", note[n]);
    }
    fclose(ifile);
    }
    

    【讨论】:

    • 我更改了代码,但它不起作用。它使核心转储。我验证了所有内容,但似乎无法正常工作。
    猜你喜欢
    • 1970-01-01
    • 2021-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多