将结构从 main() 传递给工作函数时的段错误

Posted

技术标签:

【中文标题】将结构从 main() 传递给工作函数时的段错误【英文标题】:Segfault when passing structure from main() to worker functions 【发布时间】:2017-02-26 21:37:58 【问题描述】:

我正在尝试用 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

【问题讨论】:

我无法复制它。对于高效的函数调用,printGame 和 hasGameEnded 应该采用指向游戏的指针(如 getInitialGame)。 您应该将printGame() 函数中的打印说明符从%d 更改为%lu 欢迎您!感谢您在您的问题中提供详细信息——不是每个人都这样做。查看tour 了解有关社区运作方式的更多信息,并享受您的逗留! 感谢您的反馈,伙计们! 好吧,你的程序编译和运行没有任何问题(只是一个关于使用%d格式而不是%ld的警告sizeof(game)。除了按值传递完整结构的事实到hasGameEnded()printGame() 函数,我在你的代码中看不到任何不规则的东西(你在堆栈上复制一个100Kb 的结构以将它传递给任何一个函数) 【参考方案1】:

您可能会用完堆栈空间。

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 设为无符号,因为大小不能为负数。

【讨论】:

【参考方案2】:

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

    您在main() 中声明Game game;。这意味着 game 的所有 102400 字节都在堆栈中。 printGamehasGameEnded 都采用 Game game,而不是 Game * game。也就是说,他们得到的是Game副本,而不是指向现有Game指针。因此,无论何时调用任何一个,您都会在堆栈上转储另外 102400 个字节。

我猜测对printGame 的调用正在破坏堆栈,从而导致hasGameEnded 调用出现问题。

我知道的最简单的解决方法(不涉及动态内存分配,从长远来看可能更好)是:

    Game game; 移到main() 之外,例如,移到int main(...) 正上方的行。这样它将在数据段中,而不是在堆栈中。

    printGamehasGameEnded改为Game *

    void printGame(Game * game) 
        printf("Game -> %p (%d)\n", game, sizeof(Game));
        fflush(stdout);
    
    
    int hasGameEnded(Game * game) 
        printGame(game);
        return 0;
    
    

这应该会让你继续前进。

【讨论】:

堆栈溢出的第一篇文章实际上是堆栈溢出!哦,具有讽刺意味的是......感谢您的帮助! :)

以上是关于将结构从 main() 传递给工作函数时的段错误的主要内容,如果未能解决你的问题,请参考以下文章

将一个指针分配给另一个时的段错误

GCC 生成的程序集 - C 函数调用时的段错误

在struct中访问函数时的段错误

未指定 lambda 函数的返回类型时的段错误

使用 CUDA 流时的段错误

推送到成员向量时的段错误