C 中 fwrite 和 struct 的奇怪错误

strange error with fwrite and struct in C

大家好,我是 c 语言的新手,这是我在 Whosebugs.com 上的第一个回答,请大家多多关照 :),

我真的不明白这种行为。

这是我的代码:

#include <stdio.h>

typedef struct record{
  char nome[20];
  enter code herechar cognome[30];
} rec ;

void main(){
  rec p={"mario","rossi"};
  FILE* f;
  f=fopen("x.dat","w");
  fwrite(&p,sizeof(rec),2,f);// i write 2 times mario rossi
  fclose(f);
  f=fopen("x.dat","r");
  rec d[2];
  fread(d,sizeof(rec),1,f);// pt1    
  fread(d,sizeof(rec),1,f);
  printf("%s %s\n",d[0].nome,d[0].cognome);
  printf("%s %s\n",d[1].nome,d[1].cognome);
  fclose(f);


  f=fopen("x.dat","r");
  d[2];
  fread(d,sizeof(rec),1,f);// pt2
  fread(d+sizeof(rec),sizeof(rec),1,f); //pt3
  printf("%s %s\n",d[0].nome,d[0].cognome);
  printf("%s %s\n",d[1].nome,d[1].cognome);
  fclose(f);

}

我想从一个文件中写入和读取 2 个结构,并将它们重定向到一个数组中 所以问题是:

  1. 为什么 pt1 行中的 2 fread 无法将结构存储在数组中??

  2. 对我来说是个谜:为什么 pt2 行的指令相同 不要失败?? pt3 行失败 ???

  3. 在 pt3 行中我发明了 d+sizeof(rec) 因为我认为指针算法 我不知道这是否合法,但输出与 pt1 行相同 这段代码是错误的吗???

非常感谢你的帮助:)

初学者:

fwrite(&p,sizeof(rec),2,f);// i write 2 times mario rossi

不行,这一行写一次。

对于第二条记录,它写入垃圾,从 "somewhere" 读取,即不属于对象 p 的内存,来自 p 之外。

从 "somewhere" 读取会引发未定义的行为,从这一刻起任何事情都可能发生。

您所有的阅读都有效,但您没有阅读您认为正在阅读的内容,也没有将您阅读的内容存储在您认为存储它的地方。

你传给fwrite的数字不是说写入数据多少次,而是指针指向多少条记录。
(即指针被认为是指向数组中的第一个元素和数组包含多少个元素的数字。)

或多或少地逐行检查您的代码,跳过最不感兴趣的部分:

fwrite(&p,sizeof(rec),2,f);

这会写入 "mario rossi record" 任何 sizeof(rec) 字节恰好存储在它之后。
该数据可能看起来像随机垃圾。

rec d[2];

此数组的元素未初始化,可能包含任何内容。
在这个阶段读取它的元素是未定义的。

fread(d,sizeof(rec),1,f);// pt1 

这会将 "mario rossi record" 读入 d 的第一个元素。

fread(d,sizeof(rec),1,f);

这会将 "random garbage record" 读入 d 的第一个元素,替换 "mario rossi record"。

第二个元素仍然包含未初始化的数据。

printf("%s %s\n",d[0].nome,d[0].cognome);

这会打印您之前写的 "random garbage record"。

printf("%s %s\n",d[1].nome,d[1].cognome);

这会打印您从未替换过的未初始化数据。

d[2];

这一行什么也没做。

fread(d,sizeof(rec),1,f);// pt2

这会将 "mario rossi record" 读入 d 的第一个元素。

fread(d+sizeof(rec),sizeof(rec),1,f); //pt3

这会将 "random garbage record" 读入 d 的第二个元素。

printf("%s %s\n",d[0].nome,d[0].cognome);

这是您唯一一次输出任何有效数据,这就是它看起来有效的原因。

如果要将"mario rossi record"写两次,就写两次:

fwrite(&p,sizeof(rec),1,f);
fwrite(&p,sizeof(rec),1,f);