C fprintf 和 fscanf 保存游戏状态



我在使用fscanf和fprintf时遇到问题,我已经将我的游戏状态保存到文件中,然后尝试从同一文件加载回来(下次打开程序时(

我有功能:

bool savegame(saved save) {
FILE* fptr;
fptr = fopen("savegame.txt", "w+");
if (fptr == NULL)
return 0;
fprintf(fptr, "beeseed= %dn", save.beeseed);
for (int i = 0; i < 5; i++)
{
fprintf(fptr, "car %d pos x= %d y=%dn", i, save.cars[i].pos.x, save.cars[i].pos.y);
fprintf(fptr, "car %d speed= %dn", i, save.cars[i].rand);
fprintf(fptr, "obstacle %d pos x= %d y=%dn", i, save.obstacles[i].pos.x, save.obstacles[i].pos.y);
fprintf(fptr, "obstacle %d speed= %dn", i, save.obstacles[i].rand);
fprintf(fptr, "frogend %d= %dn", i, save.frogend[i]);
}
fprintf(fptr, "health= %dn", save.health);
fprintf(fptr, "worldTime= %fn", save.worldTime);
fprintf(fptr, "frog pos x= %d y=%dn", save.frog.x, save.frog.y);
fprintf(fptr, "lost frog pos x= %d y= %d rand= %dn", save.lostfrog.pos.x, save.lostfrog.pos.y, save.lostfrog.rand);
fprintf(fptr, "score bee= %d score end= %dn", save.score.bee, save.score.end);
fprintf(fptr, "score flag= %d score frog= %dn", save.score.flag, save.score.frog);
fprintf(fptr, "score pos= %d score total= %dn", save.score.pos, save.score.total);
fclose(fptr);
return 1;
}

这个效果很好,我的意思是 - 我的文件正确填充了值。 现在我尝试扫描此文件:

bool loadgame(saved* save) {
FILE* fptr;
fptr = fopen("savegame.txt", "r");
if (fptr == NULL)
return 0;
fscanf(fptr, "beeseed= %d", &save->beeseed);
for (int i = 0; i < 5; i++)
{
fscanf(fptr, "car %d pos x= %d y=%d", i, &save->cars[i].pos.x, &save->cars[i].pos.y);
fscanf(fptr, "car %d speed= %d", i, &save->cars[i].rand);
fscanf(fptr, "obstacle %d pos x= %d y=%d", i, &save->obstacles[i].pos.x, &save->obstacles[i].pos.y);
fscanf(fptr, "obstacle %d speed= %d", i, &save->obstacles[i].rand);
fscanf(fptr, "frogend %d= %d", i, &save->frogend[i]);
}
fscanf(fptr, "health= %d", &save->health);
fscanf(fptr, "worldTime= %lf", &save->worldTime);
fscanf(fptr, "frog pos x= %d y=%d", &save->frog.x, &save->frog.y);
fscanf(fptr, "lost frog pos x= %d y= %d rand= %d", &save->lostfrog.pos.x, &save->lostfrog.pos.y, &save->lostfrog.rand);
fscanf(fptr, "score bee= %d score end= %d", &save->score.bee, &save->score.end);
fscanf(fptr, "score flag= %d score frog= %d", &save->score.flag, &save->score.frog);
fscanf(fptr, "score pos= %d score total= %d", &save->score.pos, &save->score.total);
fclose(fptr);
return 1;
}

它仅适用于文件的第一行(即 beeseed= 3(,其他根本不有效

我知道我可能不太了解 fscanf,但我在谷歌上检查了很多问题,我不知道如何使其正确 - 对我来说最重要的是 - 易于理解和可读(我可能可以在一个 fscanf 中完成所有内容,其中包含整个 .txt 文件和变量作为 %d, 但它看起来会很乱(

我还尝试在每个 fscanf 的末尾给出"",但它带来了库错误

还有我的savegame.txt文件:

beeseed= 8
car 0 pos x= 952 y=427
car 0 speed= 9
obstacle 0 pos x= 1028 y=217
obstacle 0 speed= 10
frogend 0= 0
car 1 pos x= 647 y=392
car 1 speed= 8
obstacle 1 pos x= 1131 y=182
obstacle 1 speed= 5
frogend 1= 1
car 2 pos x= 604 y=357
car 2 speed= 5
obstacle 2 pos x= -71 y=147
obstacle 2 speed= 5
frogend 2= 0
car 3 pos x= 437 y=322
car 3 speed= 6
obstacle 3 pos x= 320 y=112
obstacle 3 speed= 7
frogend 3= 0
car 4 pos x= 142 y=287
car 4 speed= 5
obstacle 4 pos x= 7 y=77
obstacle 4 speed= 7
frogend 4= 0
health= 5
worldTime= 4.892000
frog pos x= 320 y=462
lost frog pos x= 376 y= 182 rand= 188
score bee= 200 score end= 476
score flag= 0 score frog= 0
score pos= 0 score total= 120

问题可能是我的结构包含布尔save.frogend[i]是布尔形式并且需要 %d(也是 1/0(?

typedef struct {
int x;
int y;
}pos;
typedef struct {
short int pos;
short int end;
short int frog;
short int bee;
short int total;
short int flag;
} score;
typedef struct {
bool frogend[5];
score score;
pos frog;
struct {
pos pos;
int rand;
}lostfrog;
struct {
pos pos;
int rand;
}obstacles[5];
struct {
pos pos;
int rand;
}cars[5];
short int beeseed;
double worldTime;
int health;
}saved;

您不会跳过fscanf()格式字符串中的换行符。所以第二个fscanf()会失败,因为它希望在最后一个y=%d之后立即找到单词car,但它们之间有一个换行符。

在每个格式字符串的开头放置一个空格。这将使它跳过任何前导空格。

此外,参数中的所有i都应&i。但是你真的不想重新分配i,因为它是由for循环头控制的。因此,您应该跳过将这些字段分配给任何变量;您可以使用%*d.

bool loadgame(saved* save) {
FILE* fptr;
fptr = fopen("savegame.txt", "r");
if (fptr == NULL)
return 0;
fscanf(fptr, "beeseed= %d", &save->beeseed);
for (int i = 0; i < 5; i++)
{
fscanf(fptr, " car %*d pos x= %d y=%d", &save->cars[i].pos.x, &save->cars[i].pos.y);
fscanf(fptr, " car %*d speed= %d", &save->cars[i].rand);
fscanf(fptr, " obstacle %*d pos x= %d y=%d", &save->obstacles[i].pos.x, &save->obstacles[i].pos.y);
fscanf(fptr, " obstacle %*d speed= %d", &save->obstacles[i].rand);
fscanf(fptr, " frogend %*d= %d", &save->frogend[i]);
}
fscanf(fptr, " health= %d", &save->health);
fscanf(fptr, " worldTime= %lf", &save->worldTime);
fscanf(fptr, " frog pos x= %d y=%d", &save->frog.x, &save->frog.y);
fscanf(fptr, " lost frog pos x= %d y= %d rand= %d", &save->lostfrog.pos.x, &save->lostfrog.pos.y, &save->lostfrog.rand);
fscanf(fptr, " score bee= %d score end= %d", &save->score.bee, &save->score.end);
fscanf(fptr, " score flag= %d score frog= %d", &save->score.flag, &save->score.frog);
fscanf(fptr, " score pos= %d score total= %d", &save->score.pos, &save->score.total);
fclose(fptr);
return 1;
}

另一种选择是使用fgets()读取每一行,然后使用sscanf()从中提取值。

  1. 句柄fscanf返回值。处理错误。
  2. 您无法扫描到i。启用编译器警告并修复它们。
  3. 与另一个答案一样,扫描换行符。
  4. short int的格式说明符是%hd

至于第 2 点,执行fscanf(fptr, "%d", i)是无效的,i不是变量的有效地址。 使用%*d您可以扫描一个整数而不保存结果:

for (int i = 0; i < 5; i++)
{
int e = fscanf(fptr, " car %*d pos x= %d y=%d", &save->cars[i].pos.x, &save->cars[i].pos.y); 
if (e != 2) abort();
...
}

但我会尽可能实现悬垂的错误处理:

for (int i = 0; i < 5; i++)
{
int read_i = 0;
int e = fscanf(fptr, " car %d pos x= %d y=%d", &read_i, &save->cars[i].pos.x, &save->cars[i].pos.y); 
if (e != 3) abort(); // handle error
if (i != read_i) abort(); // handle error
...
}

可能是我的结构包含布尔保存.frogend[i] 是布尔形式

例如,如果save.frongend[i]的类型是bool,则需要扫描到具有正确类型的临时变量以匹配scanf说明符。例如,您可以将%dint一起使用。然后检查值是否在适当的范围内。例如:

int temp = 0;
int e = fscanf(fptr, "frogend %*d= %d", &temp);
if (e != 1) abort();
if (temp != 0 && temp != 1) abort();
save->frogend[i] = temp;

我想把它们放在一起:

bool loadgame(saved* save) {
FILE* fptr;
fptr = fopen("savegame.txt", "r");
if (fptr == NULL)
return 0;
int e = 0;
e = fscanf(fptr, "beeseed= %hd", &save->beeseed);
if (e != 1) return 0;
for (int i = 0; i < 5; i++) {
int i2 = 0;
e = fscanf(fptr, " car %d pos x= %d y=%d", &i2, &save->cars[i].pos.x, &save->cars[i].pos.y);
if (e != 3) return 0;
if (i2 != i) return 0;
e = fscanf(fptr, " car %d speed= %d", &i2, &save->cars[i].rand);
if (e != 2) return 0;
if (i2 != i) return 0;
e = fscanf(fptr, " obstacle %d pos x= %d y=%d", &i2, &save->obstacles[i].pos.x, &save->obstacles[i].pos.y);
if (e != 3) return 0;
if (i2 != i) return 0;
e = fscanf(fptr, " obstacle %d speed= %d", &i2, &save->obstacles[i].rand);
if (e != 2) return 0;
if (i2 != i) return 0;
int temp = 0;
e = fscanf(fptr, "frogend %d= %d", &i2, &temp);
if (e != 2) return 0;
if (i2 != i) return 0;
if (temp != 0 && temp != 1) return 0;
save->frogend[i] = temp;
}
e = fscanf(fptr, " health= %d", &save->health);
if (e != 1) return 0;
e = fscanf(fptr, " worldTime= %lf", &save->worldTime);
if (e != 1) return 0;
e = fscanf(fptr, " frog pos x= %d y=%d", &save->frog.x, &save->frog.y);
if (e != 2) return 0;
e = fscanf(fptr, " lost frog pos x= %d y= %d rand= %d", &save->lostfrog.pos.x, &save->lostfrog.pos.y, &save->lostfrog.rand);
if (e != 3) return 0;
e = fscanf(fptr, " score bee= %hd score end= %hd", &save->score.bee, &save->score.end);
if (e != 2) return 0;
e = fscanf(fptr, " score flag= %hd score frog= %hd", &save->score.flag, &save->score.frog);
if (e != 2) return 0;
e = fscanf(fptr, " score pos= %hd score total= %hd", &save->score.pos, &save->score.total);
if (e != 2) return 0;
fclose(fptr);
return 1;
}

最新更新