I must do a game in university in C.
I'm having real problems with the read and write in binary files.
I already asked the monitors, read a chapter about binary files in the book, and tried to search in Google for anything that could help me understand better the problem that I'm having, but none of these worked properly.
There's a struct in the game with all the informations that we need to save to the player restart the game when he likes. We must save all the different games in a single one binary file, using the name for recongnition. So, I did a algorithm that read the binary file, if it exists, and if it find a game with the same name of the player, it overwrite it with the new game, if it does not exist, it will write in the end of the file.
We must also do the reading of the file for loading a previous game.
I did a little program just to test the idea with the struct having only the player's name, but I'm having a problem: when I save, it appears to be working propperly, but when I try to load it, it shows me twice or even three times the name of the player (i putted the command puts with the name in the case the program finds a game saved with the same name).
Another thing that is puzzling me is that when I save two different games with different names, when I try to load the first one, it shows only one time.
I would really aprecciate any help that you could give me in why this is happening.
My code:
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);
}
}
and the struct GAME is (the other ones are not that important here):
typedef struct
{
PLAYER player;
GUARD guards[5];
KEY keys[5];
COORDINATE walls[50];
COORDINATE tower[50];
COORDINATE ogre;
} GAME;
If there is anyhing in portuguese is because I didn't see it right now and just forget to translate it for here. I'm sorry
EDIT: I tried some alterations that you mentioned and the error that duplicated my loading game are gone, but there is something that is really puzzling my head right now, my code that saves the game right now is:
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);
But when I execute it, it gives me in the screen: "Player updated!" AND "New player saved", how can it be? When it updates the player, it also changes the variable saved to 1, and there is the if before the "New player saved" just for that. How can it be executing two parts that shouldn't be?
The main problem is the while(!feof(...)){}
construct. This performs a random number of appends due to a race condition. The simple fix is to remove the loop altogether. A number of other problems with the code probably will not affect its operation, although should be fixed as a matter of good practice (using getc
, superfluous rewind
, etc., see the comments).
EDIT: the OP changed the code after some discussion so removing the loop as suggested above is not going to work. The proper fix is to separate the reading the file to look for the name of the player, maybe setting a boolean flag, and then perform an append if the boolean is set.