Двоичные файлы в C - PullRequest
0 голосов
/ 24 мая 2018

Я должен сделать игру в университете в C.

У меня есть реальные проблемы с чтением и записью в двоичных файлах.

Я уже спрашивал мониторы, прочитал главу обинарные файлы в книге, и я попытался найти в Google что-нибудь, что могло бы помочь мне лучше понять мою проблему, но ни один из них не работал должным образом.

В игре есть структура со всемиИнформация, которую мы должны сохранить игроку, перезапускает игру, когда ему нравится.Мы должны сохранить все разные игры в одном двоичном файле, используя имя для выражения.Итак, я сделал алгоритм, который читает двоичный файл, если он существует, и если он находит игру с тем же именем игрока, он перезаписывает ее новой игрой, если он не существует, он напишет в концефайла.

Мы также должны выполнить чтение файла для загрузки предыдущей игры.

Я сделал небольшую программу, чтобы проверить идею со структурой, имеющей только имя игрока,но у меня проблема: когда я сохраняю, кажется, что он работает неправильно, но когда я пытаюсь загрузить его, он показывает мне дважды или даже три раза имя игрока (я положил команду put с именем вслучай, когда программа находит игру, сохраненную с тем же именем).

Другая вещь, которая меня удивляет, это то, что когда я сохраняю две разные игры с разными именами, когда я пытаюсь загрузить первую, она показывает толькоодин раз.

Я бы очень признателен за любую помощь, которую вы могли бы дать мне, почему это происходит.

Мой код:

int main()
{
GAME game;
GAME jogoTeste;
FILE *saved_game;
int i = 0;
int choice, saved = 0;

gets(game.player.name);

printf("Choose what you want to do:\n");
printf("1 to save, 2 to load\n");
scanf("%d", &choice);

if (choice == 1)
{
    i = 0;
    saved_game = fopen("saved_game.dat", "a+b");
    rewind(saved_game);
    while (!feof(saved_game))
    {
        fread(&testeGame, sizeof(GAME), 1, saved_game);
        if (!strcmp(testGame.player.name, game.player.name))
        {
            int control = fwrite(&game, sizeof(GAME), 1, saved_game);
            if (control != 1)
            {
                printf("An error happened in the wrintting\n");
                printf("Were written %d elements intead of 1.\n", control);
            }
            else
            {
                saved = 1;
                printf("Player updaded!\n");
            }
        }
    }

    if (saved == 0);
    {
        fwrite(&game, sizeof(GAME), 1, saved_game);
        printf("New player saved\n");
    }
    fclose(saved_game);
}

else if (escolha == 2)
{
    i = 0;
    saved_game = fopen("saved_game.dat", "rb");

    while (!feof(saved_game))
    {
        fread(&testGame, sizeof(GAME), 1, saved_game);

        if (strcmp(testGame.player.name, game.player.name) == 0)
        {
            puts(testGame.player.name);
        }
    }
    fclose(saved_game);
}

}

и структура GAME (другоенекоторые из них здесь не так важны):

typedef struct
{
    PLAYER player;
    GUARD guards[5];
    KEY keys[5];
    COORDINATE walls[50];
    COORDINATE tower[50];
    COORDINATE ogre;
} GAME;

Если на португальском языке что-то есть, потому что я его сейчас не видел и просто забыл перевести это здесь.Извините

РЕДАКТИРОВАТЬ: Я пытался некоторые изменения, которые вы упомянули, и ошибка, которая дублировала мою загрузочную игру, ушла, но есть кое-что, что действительно озадачивает мою голову прямо сейчас, мой код, который сохраняет игру правильносейчас:

saved = 0;
    saved_game = fopen("saved_game.dat", "r+b");
    while (fread(&jogoTeste, sizeof(GAME), 1, saved_game))
    {
        if (strcmp(jogoTeste.player.name, game.player.name) == 0)
        {
            fseek(saved_game, currentOffSet, SEEK_SET);

            control = fwrite(&game, sizeof(GAME), 1, saved_game);

            if (control != 1)
            {
                printf("An error happened in the wrintting\n");
                printf("Were written %d elements intead of 1.\n", control);
            }
            else
            {
                saved = 1;
                printf("Player updated!\n");
            }

            fseek(saved_game, 0, SEEK_END);
        }
        currentOffSet = ftell(saved_game);
    }

    if (!saved);
    {
        fwrite(&game, sizeof(GAME), 1, saved_game);
        printf("New player saved\n");
    }
    fclose(saved_game);

Но когда я его выполняю, на экране появляется сообщение: «Игрок обновлен!»И "Новый игрок сохранен", как это может быть?Когда он обновляет проигрыватель, он также изменяет сохраненную переменную на 1, и для этого есть перед оператором «Новый игрок сохранен».Как это может быть выполнение двух частей, которые не должны быть?

Ответы [ 2 ]

0 голосов
/ 24 мая 2018

В вашем коде

    fread(&testeGame, sizeof(GAME), 1, saved_game);
    if (!strcmp(testGame.player.name, game.player.name))
    {
        int control = fwrite(&game, sizeof(GAME), 1, saved_game);

После того, как вы перечитаете, указатель файла переместился вперед, затем вы напишете после того, как был перечитан.Вам нужно переместить указатель файла назад, чтобы перезаписать старую запись, т. Е. Использовать ftell, чтобы получить то, где вы находитесь, затем перейти к fseek, чтобы вернуться к этому месту, или, альтернативно, использовать fseek, чтобы переместиться относительно текущей позиции в файле назад sizeof (GAME) байтов.

например

    currentOffset = ftell(saved_game);
    fread(&testeGame, sizeof(GAME), 1, saved_game);
    if (!strcmp(testGame.player.name, game.player.name))
    { 
        fseek(saved_game, currentOffset, SEEK_SET);
        int control = fwrite(&game, sizeof(GAME), 1, saved_game);
0 голосов
/ 24 мая 2018

Основной проблемой является конструкция while(!feof(...)){}.Это выполняет случайное количество добавлений из-за состояния гонки.Простое решение состоит в том, чтобы полностью удалить петлю.Ряд других проблем с кодом, вероятно, не повлияет на его работу, хотя должен быть исправлен с точки зрения надлежащей практики (использование getc, излишнее rewind и т. Д., См. Комментарии).

РЕДАКТИРОВАТЬ: ОП изменил код после некоторого обсуждения, поэтому удаление цикла, как предложено выше, не будет работать.Правильное решение состоит в том, чтобы отделить чтение файла, чтобы найти имя проигрывателя, возможно, установив логический флаг, а затем выполнить добавление, если логическое значение установлено.

...