【问题标题】:Problems with fread and fwrite saving a float matrix from .dat file to array in memoryfread 和 fwrite 将浮点矩阵从 .dat 文件保存到内存中的数组的问题
【发布时间】:2021-03-13 00:59:49
【问题描述】:

目标

我需要:

1. 使用 fwrite 将 N*N 矩阵写入二进制文件。矩阵在内存中连续存储,在一个 N * N 个元素的数组中。

2. 分配另一个 N*N 数组并使用 fread 从先前创建的文件中读取矩阵,并将其逐个元素地保存在新创建的数组中。

3.在标准输出上打印新数组。

第一个数组是float*,第二个数组也必须是float*

我的代码

这是我的代码,它似乎在二进制文件中打印了正确的矩阵,但是当我用fread 读取它并将其保存到一个新数组中时,当我打印新数组时它只打印0.0 0.0 0.0 ecc

void fileBinPrintMat(float* a, int dim, FILE* output){
    float x;
    for(int i = 0; i < dim; i++){
          x = a[i];
          fwrite(&x, sizeof(float), 1, output);
    }
 }
   

     
#define DIM 512

//PART 1, PRINT THE MATRIX IN .dat FILE
int main(int argc, char** argv){
    .
    .
    .
    float* M1 = calloc(n*n, sizeof(float));
        CHECK_MEMORY(M1, "CALLOC"); //MACRO for checking allocation memory
        for(size_t i = 0; i < (n); i++)
            for(size_t j = 0; j < n; j++)
                M1[(i*n)+j] = (i+j)/2.0;
    FILE* ofpbin = fopen("mat_dump.dat", "wb");
    CHECK_OPEN_FILE(ofpbin, "mat_dump.dat");
    fileBinPrintMat(M1, n*n, ofpbin); //Function that print matrix in file.dat
    free(M1);
    fclose(ofpbin);

//PART 2, SAVE THE MATRIX PRINTED IN .dat FILE IN N*N ARRAY
    FILE* ifpbin = fopen("mat_dump.dat", "rb");
    CHECK_OPEN_FILE(ifpbin, "mat_dump.dat");
    char* buffer = calloc(DIM, sizeof(char));
    CHECK_MEMORY(buffer, "CALLOC");
    float* M2 = calloc(n*n, sizeof(float));
    CHECK_MEMORY(M2, "CALLOC"); 
//READ MATRIX FROM FILE AND WRITE IT IN ARRAY M2
    int i = 0;
    float elemBuffer;
    while(fgets(buffer, DIM, ifpbin) != NULL){
        fread(&elemBuffer, sizeof(float), 1, ifpbin);
        M2[i] = elemBuffer;
        i++;   
    }
    

附:我知道我必须检查 fread ecc 的所有返回值...我会稍后再做

期望的输出

假设n = 4,最终输出矩阵必须是:

  0.0   0.5   1.0   1.5
  0.5   1.0   1.5   2.0
  1.0   1.5   2.0   2.5
  1.5   2.0   2.5   3.0

在二进制文件中是这样的:

 ? ? �? �?
 ? �? �? @
 �? �? @  @
 �? @  @ @@

而且我认为没关系,它必须从 .dat 保存到数组 float* M2 像这样:

0.0   0.5   1.0   1.5   0.5   1.0   1.5   2.0   1.0   1.5   2.0   2.5   1.5   2.0   2.5   3.0
 

我的输出

  0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0
  0.0   0.0   0.0   0.0

重要提示:

这是一个大学作业,我可以使用 fread 和 fwrite 来处理二进制文件 i/o 和 strtok 来标记文件中元素之间的空间。

【问题讨论】:

  • 如果您正在读取和写入二进制数据,您应该使用的仅有的两个函数是freadfwrite。为什么要写反斜杠和空格?破坏了二进制文件的全部目的。宏只会使您的代码更难阅读,尤其是在这里您通常希望使您的 minimal reproducible example 尽可能简单易懂。
  • 你对宏是正确的。我会编辑它。关于反斜杠和空格,我如何在二进制文件中写一个空格来标记保存在其中的每个不同的数字?
  • 您不需要在二进制文件中标记它们。每个 float 将占用 4 个字节,因此它们之间不需要任何类型的分隔符。
  • 好的,我不能像经典的 N*N 矩阵一样将文件格式化成列吗?
  • 二进制文件一般不会被视为文本文件。所以不需要格式化。如果您想打开该文件并希望看到一个格式整齐的矩阵,那么您可以使用文本文件。

标签: c c99 fwrite fread strtok


【解决方案1】:

处理二进制文件时,经验法则是从文件中读取的代码和写入文件的代码应该相同,但功能相反。

我的意思是,在您的情况下,您有一个简单的循环,将float 值的连续数组写入文件。

这意味着,您的读取代码必须执行相同的操作 - 从文件中读取一个连续的浮点数组。

向读取循环添加额外的逻辑会使您的代码以错误的方式解析数据,这就是您无法取回值的原因。

所以这里是你应该如何阅读它们:

void fileBinReadMat(float* a, int dim, FILE* input){
    float x;
    for(int i = 0; i < dim; i++){
          fread(&x, sizeof(float), 1, input);
          a[i] = x;
    }
}

严格来说,您不需要 x 中间变量来读取或写入,但我将它留在那里以保持代码相同且更易于理解。

【讨论】:

  • 好的,它可以工作,所以如果我理解得很好,fread 从文件中读取 4 个字节,而不是改进 4 个字节的指针?所以我不需要使用 fgets 吗?我也可以写成:void fileBinReadMat(float* a, int dim, FILE* input){ for(int i = 0; i &lt; dim; i++){ fread(&amp;a[i], sizeof(float), 1, input); } }
  • @ClaudioDeLise fgets 用于读取字符串(可打印字符),而不是用于读取以二进制形式存储的float,所以不,您不需要它也不能使用它。我不知道您所说的“改进指针”是什么意思,但fread 将做的是从文件中获取 4 个字节并将它们放入内存中,您给它的指针指向该内存。你可以直接给它数组单元的地址fread(&amp;a[i], sizeof(float), 1, input);,它会正常工作。 fread 不关心将字节放入哪个内存,只要您的程序合法拥有它。阅读前不要忘记callocmalloc 数组!
  • 我试着向你解释我的“改进”。我看到我传递给fread,作为FILE* 文件的最后一个参数;在 for 的第一次迭代中,它需要 4 个字节并将它们复制到第一个参数中指针的内存中,在这种情况下是 a[0]fread 如何在 for 的第二次迭代中复制 a[1] 中的第二个 4 个字节。如果在第二次迭代中我再次传递FILE* 文件,他为什么不再次复制前 4 个字节?
  • @ClaudioDeLise 不要将FILE* 视为常规指针。将其视为“使用文件的黑匣子”。它指向一个管理打开文件的文件对象。它“知道”您从文件中读取了多少字节,并保留要读取的下一个字节的位置。这一切都是自动完成的。它不会读取您已经读取的字节,除非您使用fseek 函数移动位置。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-07
  • 1970-01-01
  • 1970-01-01
  • 2011-11-13
  • 2021-12-15
  • 2020-12-14
  • 2013-11-26
相关资源
最近更新 更多