Fwrite / Fread динамически объявленная структура ** - PullRequest
0 голосов
/ 07 октября 2019

Я бы хотел 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;

Я выделяю память карты следующим образом:

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, я не смог бы выделить надлежащее пространство памяти. Поэтому я решил сначала написать высоту и ширину, затем выделить память, а затем прочитать карту. Но я не могу найти, как правильно написать или прочитать мою карту. Я попытался:

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);
    }
}

Но это не работает, иначе я не знаю, как мне написать / прочитать мою карту.

Все, что я пробовал, не возвращает мнекарта, которую я написал, или она просто вылетает, говоря мне: процесс завершен с кодом выхода -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);

}

Ответы [ 2 ]

2 голосов
/ 07 октября 2019

Вы смешиваете текстовые данные и двоичные данные в своем файле данных.

Когда вы пишете имя, высоту и ширину:

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);

Спецификатор формата %s для fscanf читает символы, пока не встретит пробел. Первые 7 символов считываются правильно, но сразу после этого это двоичные данные для height, так где же он перестает читать? В результате вы, скорее всего, прочитали больше байтов, чем отступили, и теперь остальные чтения не находятся в правильном месте.

Это можно исправить, покончив с fprintf и fscanf с помощьюзапись всего поля name с fwrite:

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] - это не адрес выделенной памяти, а адрес указателя , на который он указывает . Таким образом, вместо чтения / записи памяти, выделенной для каждого ряда ячеек, вы читаете / записываете память, используемую для ряда указателей для каждой ячейки. Когда вы это сделаете, вы закончите чтение / запись за концом выделенной памяти.

Избавьтесь от оператора address-of, чтобы передать указатель на фактическую память, которую вы читаете / записываете:

fwrite(maze.map[x], sizeof(Cell), maze.height, file);
...
fread(maze.map[x], sizeof(Cell), maze.height, file);
0 голосов
/ 07 октября 2019

Поскольку элементы в каждом элементе лабиринта (maze.map [X]) являются непрерывными и предварительно выделены, вы можете записать каждый элемент «лабиринта» с помощью одного вызова fwrite:

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

Выбрав этот маршрут, вы можете использовать fread вместо fwrite для чтения элементов.

Примечание: Обычно лучше использовать calloc (count, sizeof (...)), а не malloc (count * sizeof) -он инициализирует выделенную память нулями.

...