C 将结构从main()传递给辅助函数时发生SEGFULT

C 将结构从main()传递给辅助函数时发生SEGFULT,c,struct,segmentation-fault,pass-by-value,pass-by-pointer,C,Struct,Segmentation Fault,Pass By Value,Pass By Pointer,我正试图用C写一个简单的游戏,但我遇到了一个错误,不知道为什么 以下是该程序的代码: #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(

我正试图用C写一个简单的游戏,但我遇到了一个错误,不知道为什么

以下是该程序的代码:

#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;
}
#包括
#包括
#定义每个游戏的最大游戏数(1024)
#定义最大长度(100)
类型定义结构{
char positionHistory[MAX_PLYS_PER_GAME][MAX_LEN];
}游戏;
无效getInitialGame(游戏*游戏){
memset(游戏->位置历史,0,每个游戏的最大值*最大值*大小(字符));
}
无效打印游戏(游戏){
printf(“游戏->%p(%d)\n)”,&Game,sizeof(游戏));
fflush(stdout);
}
int hasGameEnded(游戏){
印刷游戏(游戏);
返回0;
}
int main(int argc,char*argv[]){
游戏;
getInitialGame(&game);
如果(游戏结束(游戏))
返回-1;
返回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
C:\Users\test>gdb test.exe
GNU gdb 5.1.1(mingw实验)
此GDB已配置为“mingw32”。。。
(gdb)运行
启动程序:C:\Users\test/test.exe
程序接收信号SIGSEGV,分段故障。
快速国际象棋错误处的主代码0x00401368(argc=1,argv=0x341c88)。c:29
29如果(游戏结束(游戏))
(gdb)英国电信
#快速国际象棋错误处的0 0x00401368主(argc=1,argv=0x341c88)。c:29

这可能是堆栈溢出(真的!),尽管我不确定

  • 您正在声明
    游戏
    main()
    中。这意味着所有102400字节的
    game
    都在堆栈中
  • printGame
    hasGameEnded
    都要玩
    Game游戏
    ,而不是
    Game*游戏
    。也就是说,他们得到的是
    游戏的副本,而不是指向现有
    游戏的指针。因此,无论何时调用其中一个,都会在堆栈上转储另外102400个字节
    我猜对
    printGame
    的调用正在以某种方式破坏堆栈,从而导致
    hasGameEnded
    调用出现问题

    据我所知,最简单的修复方法(不涉及动态内存分配,长期而言可能更好)是:

  • 移动
    游戏
    main()
    之外,例如,在
    int main(…)
    正上方的行。这样,它将位于数据段中,而不是堆栈上
  • printGame
    hasGameEnded
    更改为使用
    Game*

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

  • 这应该会让您继续前进。

    您可能会耗尽堆栈空间

    C是传递值。所以这个代码

    int hasGameEnded(Game game)
    
    创建整个
    struct{}游戏的副本
    ,很可能在堆栈上

    如果以下代码正常工作,则堆栈空间不足:

    ...
    
    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()


    还要注意的是,由于大小不能为负数,所以我和随意将它设为unsigned的
    u

    我无法复制它。为了有效调用函数,printGame和HasGameEnd应该使用指向游戏的指针(如getInitialGame)。您应该将
    printGame()
    函数中的打印说明符从
    %d
    更改为
    %lu
    。欢迎!谢谢你在你的问题中加入细节——不是每个人都这样做。查看更多有关社区工作方式的信息,并享受您的住宿!谢谢你们的反馈,伙计们!好的,您的程序编译和运行没有任何问题(只是一个警告,关于对
    sizeof(game)
    使用
    %d
    格式而不是
    %ld
    。除了按值将完整结构传递给
    hasGameEnded()
    printGame()之外
    functions,我看不到您的代码中有任何不规则的地方(您正在复制堆栈上的100Kb结构以将其传递给任何一个函数)堆栈溢出中的第一个post实际上是堆栈溢出!哦,讽刺的是…谢谢您的帮助!:)