c - Fwrite/Fread 动态声明的结构 **

标签 c gcc clion

我想 fwrite() 然后 fread() 以下 struct ** 其内存已动态分配。 该结构声明如下:

typedef struct {
   int num;
   char type;
   Entity entity;
}Cell;

我声明一个单元格映射如下:

typedef struct {
  char name[MAX_STRING];
  int width;
  int height;
  Cell** map;
}Maze;

我分配 map 的内存如下:

maze.map = (Cell **)malloc( width*sizeof( Cell* ));

for (int  x = 0; x < width; x++ )
{
    maze.map[x] = (Cell *)malloc(sizeof( Cell )*height);
}

问题是我不能像这样fwrite()/fread() 我的结构因为一旦我想fread() struct,我将无法分配适当的内存空间。 所以我决定先写高度和宽度然后分配内存然后读取 map 。 但是我找不到如何正确地书写或阅读我的 map 。 我试过了:

for (int x = 0; x < maze.width; ++x) {
    for (int y = 0; y < maze.height; ++y) {
        fwrite(&maze.map[x][y], sizeof(Cell), 1, file);
    }
}

但它不起作用,否则我不知道我应该如何写/读我的 map 。

我尝试的一切都没有给我写的 map ,或者它只是崩溃并告诉我:进程已完成,退出代码为 -1073741819 (0xC0000005)

下面是写和读两个函数:

void SaveMaze(Maze maze){
   FILE *file;
   char file_name[MAX_STRING];

   strcpy(file_name, maze.name);
   strcat(file_name,".save");

   file = fopen(file_name, "w");

   if(file == NULL)
   {
       perror("Error Fopen : ");
       return ;
   }
   fwrite(maze.name,sizeof(maze.name), 1, file);
   fwrite(&maze.height,sizeof(maze.height), 1, file);
   fwrite(&maze.width,sizeof(maze.width), 1, file);

   for (int x = 0; x < maze.width; ++x) {
       fwrite(&maze.map[x], sizeof(Cell), maze.height, file);
   }

   // Close the file
   fclose(file);
}


Maze LoadMaze(char * name){
   FILE *file;
   Maze maze;
   char file_name[MAX_STRING];

   strcpy(file_name, name);
   strcat(file_name,".save");

   file = fopen(file_name, "r");

   if(file == NULL) {
       perror("Error Fopen : ");
       return maze;
   }

   fread(maze.name,sizeof(maze.name), 1, file);
   fread(&maze.height,sizeof(maze.height), 1, file);
   fread(&maze.width,sizeof(maze.width), 1, file);

   maze.map = (Cell **)malloc( maze.width*sizeof( Cell* ));

   for (int  x = 0; x < maze.width; x++ )
   {
      maze.map[x] = (Cell *)malloc(sizeof( Cell )*maze.height);
   }
   for (int x = 0; x < maze.width; ++x) {
       fread(&maze.map[x], sizeof(Cell), maze.height, file);
   }
   printf("%c",maze.map[0][0].num);

   fclose (file);
   return maze;
}
int main() {
   int choice;
   int width,height;
   char name[MAX_STRING],file_name[MAX_STRING];
   Maze maze;

   do{
       printf("1. Generate a new Maze\n");
       printf("2. Load an existing maze\n");
       printf("3. Play\n");
       printf("4. Exit\n");

       scanf("%d",&choice);
       fflush(stdin);

       if(choice == 1){
           do {
               printf("What is the width of your maze (Odd number only)\n");
               scanf("%d", &width);
               fflush(stdin);
           } while (width%2 == 0);

           do {
               printf("What is the height of your maze (Odd number only)\n");
               scanf("%d", &height);
               fflush(stdin);
           } while (height%2 == 0);

           printf("What is the name of the maze\n");
           fgets(name,sizeof(name),stdin);
           // Remove the \n from the name
           name[strcspn(name, "\n")] = 0;
           fflush(stdin);

           maze = CreateMaze(width,height,name);
           InitialyzeMaze(&maze);
           BuildMaze(&maze);
           fflush(stdin);

           SaveMaze(maze);

       }else if(choice == 2){
           //system("clear");
           //system("ls *.{save}");

           printf("What is the name of the maze you want to load ?\n");

           fgets(file_name,sizeof(file_name),stdin);
           // Remove the \n from the filename
           file_name[strcspn(file_name, "\n")] = 0;
           fflush(stdin);

           maze = LoadMaze(file_name);

       }else if(choice == 3){
           Play(&maze);
       }
   }while(choice != 4);

最佳答案

您在数据文件中混合了文本数据和二进制数据。

当你写名字、高度和宽度时:

fprintf(file,"%s",maze.name);
fwrite(&maze.height,sizeof(maze.height), 1, file);
fwrite(&maze.width,sizeof(maze.width), 1, file);

这会输出一系列名称字符(比如“my_maze”),紧接着是 sizeof(int) 字节的高度和 sizeof(int) 字节对于宽度。 所以名称有 7 个字节,高度有 4 个字节(假设 int 是 4 个字节),宽度有 4 个字节。

现在当你回读时:

fscanf(file,"%s",maze.name);
fread(&maze.height,sizeof(maze.height), 1, file);
fread(&maze.width,sizeof(maze.width), 1, file);

fscanf%s 格式说明符读取字符,直到遇到空格。前 7 个字符被正确读取,但紧随其后的是 height 的二进制数据,那么它在哪里停止读取?结果是您读取的字节很可能比缩进的多,现在您读取的其余部分不在正确的位置。

您可以通过使用 fwrite 编写整个 name 字段来消除 fprintffscanf 来解决此问题:

fwrite(maze.name,sizeof(maze.name), 1, file);

并使用 fread 读取它:

fread(maze.name,sizeof(maze.name), 1, file);

你这里也有问题:

fwrite(&maze.map[x], sizeof(Cell), maze.height, file);

在这里:

fread(&maze.map[x], sizeof(Cell), maze.height, file);

&maze.map[x] 不是你分配的内存地址,而是它指向的指针的地址。因此,不是读取/写入为每行单元格预留的内存,而是读取/写入用于每个单元格的指针行的内存。执行此操作时,您最终会读取/写入已分配内存的末尾。

去掉此处的寻址运算符,将指针传递给您正在读/写的实际内存:

fwrite(maze.map[x], sizeof(Cell), maze.height, file);
...
fread(maze.map[x], sizeof(Cell), maze.height, file);

关于c - Fwrite/Fread 动态声明的结构 **,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58273944/

相关文章:

将 char 元素从数组转换为 int

c - ALSA中period的含义

C - 使用二维数组绘制条形图 - 不会绘制负值

c++ - 大整数隐式截断为无符号类型 [-Woverflow]

cmake - 在 Clion 中导入代码时不覆盖 CMakeLists 有什么影响?

c - 这个程序如何创建僵尸进程?

c - 在C中初始化指向NULL的指针

c - ELF 的符号解析

c++ - make_heap和pop_heap可以,但是push_heap不能

cuda - 在 Clion 中启用 Cuda 代码索引