fscanf正在使程序崩溃

fscanf正在使程序崩溃,c,sdl,C,Sdl,我正在做一个小项目,我想知道为什么这段代码会导致我的程序崩溃 播放器文件路径--“PLAYER.txt” 节目 FILE *pfile = fopen(PLAYER_FILE_PATH, "r"); if (!pfile) { debug_printf("could not open player file for reading!\n"); return; } fscanf(pfile, "sprite=%s\n\ width=%d\n

我正在做一个小项目,我想知道为什么这段代码会导致我的程序崩溃

播放器文件路径--“PLAYER.txt”

节目

      FILE *pfile = fopen(PLAYER_FILE_PATH, "r");
if (!pfile)
{
    debug_printf("could not open player file for reading!\n");
    return;
}
fscanf(pfile, "sprite=%s\n\
               width=%d\n\
               height=%d\n\
               frames=%d\n\
               alignment=%d\n\
               animate=%d",
               player_entity.entity_sprite.imgloc,
               &player_entity.entity_sprite.width,
               &player_entity.entity_sprite.height,
               &player_entity.entity_sprite.frames,
               &player_entity.entity_sprite.oscdir,
               &player_entity.entity_sprite.osc);
fclose(pfile);

我的猜测是您没有使用malloc或堆栈创建缓冲区来保存imgloc的值。

我的猜测是您没有使用malloc或堆栈创建缓冲区来保存imgloc的值。

我们需要查看您对player_实体的定义才能确定。您可能没有正确定义“imgloc”,它需要指向一些安全分配的内存。例如,除非正确初始化imgloc,否则以下定义将进行堆芯转储:

struct {
  struct {
    char *imgloc;
    int width;
    int height;
    int frames;
    int oscdir;
    int osc;
  } entity_sprite;
} player_entity;
如果您将上面的imgloc行替换为以下内容,则可以避免此堆芯转储

char imgloc[100];

但是,我会非常小心地使用fscanf读取字符串,因为如果字符串太长,它将溢出给定的缓冲区。也许可以试着用fgets代替字符串部分,用fscanf代替其余部分。

我们需要查看您对player\u实体的定义才能确定。您可能没有正确定义“imgloc”,它需要指向一些安全分配的内存。例如,除非正确初始化imgloc,否则以下定义将进行堆芯转储:

struct {
  struct {
    char *imgloc;
    int width;
    int height;
    int frames;
    int oscdir;
    int osc;
  } entity_sprite;
} player_entity;
如果您将上面的imgloc行替换为以下内容,则可以避免此堆芯转储

char imgloc[100];

但是,我会非常小心地使用fscanf读取字符串,因为如果字符串太长,它将溢出给定的缓冲区。也许只针对字符串部分尝试fgets,其余部分尝试fscanf。

一般来说,一个好主意是在开发应用程序时使用内存调试器(如valgrind)

这样,您就可以从一开始就确保程序不会泄漏内存(以后调试时会遇到一个噩梦),并且可以检测到不需要访问的内存的读取或写入(这会导致segfault,导致程序崩溃)

在您的特定情况下,Valgrind会提醒您正在写入您无权访问的内存地址X(可能使用未初始化的内存),如果您使用调试信息(-g)编译,则会提供文件名和行号。在这种情况下,它会将您指向fscanf,因此您会仔细查看它。如果您无法通过查看该行来发现问题,您可以将其拆分为逐个读取参数,直到它(大概)将您指向指定字符串的行


如果您不知道char*不分配任何内存(除了保留指针的大小),那么这并不能解决问题,但它可以让您更好地了解从何处开始查找。当然,现在您知道您需要保留内存,因此当您再次看到问题时,可以立即应用这些知识。

一般来说,一个好主意是在开发应用程序时使用内存调试器(如valgrind)

这样,您就可以从一开始就确保程序不会泄漏内存(以后调试时会遇到一个噩梦),并且可以检测到不需要访问的内存的读取或写入(这会导致segfault,导致程序崩溃)

在您的特定情况下,Valgrind会提醒您正在写入您无权访问的内存地址X(可能使用未初始化的内存),如果您使用调试信息(-g)编译,则会提供文件名和行号。在这种情况下,它会将您指向fscanf,因此您会仔细查看它。如果您无法通过查看该行来发现问题,您可以将其拆分为逐个读取参数,直到它(大概)将您指向指定字符串的行


如果您不知道char*不分配任何内存(除了保留指针的大小),那么这并不能解决问题,但它可以让您更好地了解从何处开始查找。当然,现在您知道您需要保留内存,因此当您再次看到问题时,您可以立即应用这些知识。

您可以显示“玩家实体”定义吗?请确保
player\u entity.entity\u sprite.imgloc
已正确分配(生命周期与
player\u entity
的生命周期绑定的缓冲区,或通过调用
malloc
动态分配的缓冲区)。Pro提示:。您正在使程序崩溃。能否显示“player\u entity”定义?请确保已正确分配
player\u entity.entity\u sprite.imgloc
(一个缓冲区,其生存期与
player\u实体的生存期绑定,或者通过调用
malloc
动态分配).Pro提示:。您正在使程序崩溃。谢谢。我指的是指向调用链早期某个函数堆栈上缓冲区的指针。为清晰起见进行了编辑。谢谢。我指的是指向调用链早期某个函数堆栈上缓冲区的指针。为清晰起见进行了编辑。我会使用fgets,但它会读取整行内容,而不仅仅是por我需要它to@OliverSikes如何限制字符串所需的字符数:
fscanf(pfile,“%99s”,stuff.imgloc)
?@Daniel Fischer:看起来带“%99s”的fscanf确实可以工作。确保字符串缓冲区有一个额外的字节来保存终止的NULL。(例如,“%99s”需要char buf[100])。然后我会检查是否存在缓冲区溢出,例如
if(strlen(buf)==99)…
。如果满足此条件,我会以错误消息中止程序,而不是尝试恢复,但这取决于应用程序。尝试恢复可能会变得棘手。是的。我使用99,因为您的答案中有
字符imgloc[100];
:-)选择中止、重试、忽略哪一项取决于具体情况,但对于这一项,我也认为中止是最有可能的选择。我会使用fgets,但它读取整行内容,而不仅仅是我需要的部分to@OliverSikes限制价格怎么样