将结构从main()传递给worker函数时的Segfault

时间:2016-10-17 19:32:31

标签: c struct segmentation-fault pass-by-value pass-by-pointer

我正在尝试用C编写一个简单的游戏,我得到了一个SEGFAULT并且不知道为什么!

以下是该计划的代码:

#include <stdio.h>
#include <string.h>

#define MAX_PLYS_PER_GAME (1024)
#define MAX_LEN (100)

typedef struct {
   char positionHistory[MAX_PLYS_PER_GAME][MAX_LEN];
} Game;

void getInitialGame(Game * game) {
    memset(game->positionHistory, 0, MAX_PLYS_PER_GAME*MAX_LEN*sizeof(char));
}

void printGame(Game game) {
    printf("Game -> %p (%d)\n", &game, sizeof(game));
    fflush(stdout);
}

int hasGameEnded(Game game) {
    printGame(game);
    return 0;
}

int main(int argc, char *argv[]) {
    Game game;
    getInitialGame(&game);

    if (hasGameEnded(game))
        return -1;

    return 0;
}

我尝试使用gdb进行调试,但结果并没有让我走得太远:

C:\Users\test>gdb test.exe
GNU gdb 5.1.1 (mingw experimental)
<snip>
This GDB was configured as "mingw32"...
(gdb) run
Starting program: C:\Users\test/test.exe

Program received signal SIGSEGV, Segmentation fault.
0x00401368 in main (argc=1, argv=0x341c88) at fast-chess-bug.c:29
29              if (hasGameEnded(game))
(gdb) bt
#0  0x00401368 in main (argc=1, argv=0x341c88) at fast-chess-bug.c:29

2 个答案:

答案 0 :(得分:5)

可能是堆栈溢出(真的!),虽然我不确定。

  1. 您在Game game;中声明main()。这意味着所有102400字节的game都在堆栈上。
  2. printGamehasGameEnded都需要Game game,而不是Game * game。也就是说,他们正在获取Game副本,而不是现有Game指针。因此,无论何时调用其中一个,都会在堆栈上转储另外102400个字节。
  3. 我猜这个对printGame的调用正在以一种导致hasGameEnded调用问题的方式破坏堆栈。

    我所知道的最简单的修复(没有进入动态内存分配,这可能是更好的长期)是:

    1. Game game;移到main()之外,例如移至int main(...)上方的行。这样它就会在数据段中,而不是在堆栈上。
    2. 更改printGamehasGameEndedGame *

      void printGame(Game * game) {
          printf("Game -> %p (%d)\n", game, sizeof(Game));
          fflush(stdout);
      }
      
      int hasGameEnded(Game * game) {
          printGame(game);
          return 0;
      }
      
    3. 这应该让你前进。

答案 1 :(得分:2)

你可能用完了堆栈空间。

C是按值传递。所以这段代码

int hasGameEnded(Game game)

创建整个struct {} Game副本,很可能是在堆栈上。

如果以下代码有效,则用完了堆栈空间:

...

void printGame(Game *game) {
    printf("Game -> %p (%zu)\n", game, sizeof(*game));
    fflush(stdout);
}

int hasGameEnded(Game *game) {
    printGame(game);
    return 0;
}

int main(int argc, char *argv[]) {
    Game game;
    getInitialGame(&game);

    if (hasGameEnded(&game))
        return -1;

    return 0;
}

请仔细注意更改。它现在只传递结构的地址,而不是将整个结构传递给hasGameEnded。该更改沿着调用堆栈向下流动,最终更改为printGame()

另请注意,proper format specifier for sizeof includes a z modifier.我冒昧地将u设为无符号,因为大小不能为负。