【问题标题】:fscanf is crashing programfscanf 正在崩溃程序
【发布时间】:2013-02-14 21:59:37
【问题描述】:

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

PLAYER_FILE_PATH -- "player.txt"

sprite=yoshi.bmp
width=64
height=64
frames=8
alignment=1
animate=1

程序

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

【问题讨论】:

  • 你能显示一个“player_entity”的定义吗?
  • 确保player_entity.entity_sprite.imgloc 被正确分配(一个缓冲区的生命周期与player_entity 的生命周期相关联,或者通过调用malloc 动态分配)。
  • 专业提示:Select Isn't Broken正在使程序崩溃。

标签: c sdl


【解决方案1】:

我们需要查看您对 player_entity 的定义才能确定。您可能没有正确定义“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 其余部分。

【讨论】:

  • 我会使用 fgets 但它会读取整行,而不仅仅是我需要的部分
  • @OliverSikes 如何限制fscanf 将用于字符串的字符数:fscanf(pfile, "%99s", stuff.imgloc)
  • @Daniel Fischer:看起来带有“%99s”的 fscanf 确实可以工作。确保字符串缓冲区有一个额外的字节来保存终止的 NULL。 (例如,“%99s”需要 char buf[100]。)然后我会检查是否存在缓冲区溢出,例如 if (strlen(buf) == 99) ...。如果满足此条件,我将使用错误消息中止程序,而不是尝试恢复,但这取决于应用程序。试图恢复可能会很棘手。
  • 是的。我使用 99 是因为您的答案中有 char imgloc[100]; :-) 选择中止、重试、忽略中的哪一个取决于,但对于这个我也认为中止是最有可能的候选者。
【解决方案2】:

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

【讨论】:

  • 谢谢。我的意思是指向调用链中某个函数中堆栈上缓冲区的指针。为清晰起见进行了编辑。
【解决方案3】:

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

这样,您可以从一开始就确保您的程序不会泄漏内存(稍后调试的噩梦),并且您可以检测到对您不必访问的内存的读取或写入(这会导致段错误,导致程序崩溃)。

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

虽然如果您不知道 char* 不分配任何内存(除了保留指针的大小),这不会解决问题,但它可以让您更好地了解在哪里开始寻找。当然,现在你知道你需要保留内存,所以当你再次看到问题时,你会立即应用这些知识。

【讨论】:

    猜你喜欢
    • 2016-10-16
    • 1970-01-01
    • 1970-01-01
    • 2016-04-13
    • 2014-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多