【问题标题】:Segmentation fault occurs when I'm accessing a struct's member当我访问结构的成员时发生分段错误
【发布时间】:2019-01-15 20:59:03
【问题描述】:

当我想在 C 编程语言中访问或修改结构成员的值时,会出现 segmentation fault

我其实用C语言写了一个战舰联网游戏(这是一个学生项目)。我有一个名为Player的结构:

enum state{PLAYING = 0, WINNER = 1, LOOSER = 2};
enum action{ATTACK = 1, WAIT = 0, NOTHING = -1};
typedef struct Player Player;
struct Player
{
    enum action action;
    enum state state;
    char name[25];
    int isFirstPlayer;
    Client* client;
    Server* server;
    Boards* boards;
};

主要功能。

int main(int argc, char *argv[])
{
    if(argc < 2)
    {
        errorUsage();
    }

    // Initialise player
    Player player = newPlayer();
    // I removed the network initialization here.

    // play game
    play_game(&player);
}

segmentation fault 出现在函数play_game(Player* p) 中:

void attack(Player* p)
{
    char msg[2];
    bzero(msg, strlen(msg));
    printf("Where do you want to fire?");
    scanf("%s", msg);

    while(verifyEntryAttack(msg) != 1)
    {
        printf("ERROR Entry:\nFormat = A4, C9, ...\nColumns = A B C D E F G H I J\nRows = 0 1 2 3 4 5 6 7 8 9\n");
        printf("please try again: ");
        scanf("%s", msg);
    }
    sendData(p, msg);
    Box my_attack_box;
    my_attack_box.abs = msg[0];
    my_attack_box.ord = msg[1]-'0';
    updateMarkBoard(p, my_attack_box);
}

void receiveAttack(Player* p)
{
    char received_attack[2];
    receiveData(p, received_attack);
    printf("I have received the attack: %s\n", received_attack);
    Box my_attack_box;
    my_attack_box.abs = received_attack[0];
    my_attack_box.ord = received_attack[1]-'0';
    endureAttack(my_attack_box, p);
}

void play_game(Player* p)
{
    while(p->state == PLAYING){
        printPlayer(p); //print the game boards.
        if(p->action == ATTACK){
            printf("Your turn to attack.\n");
            attack(p); //attack the ennemy
            printf("end of attack turn.\n");
        } else if(p->action == WAIT){
            printf("wait for an attack...\n");
            receiveAttack(p); //receive the attack from the ennemy.
            printf("end of waiting turn.\n");
        }

        if(p->action == WAIT){
            p->action = ATTACK;
        } 
        else{
            p->action = WAIT;
        }
    }
}

在 while 循环中转了一圈后,程序说“分段错误”。我的测试表明问题出在p-&gt;action

请参阅下面显示问题的程序输出:outputs screenshot。 完整代码可在此处获得:GitLab repo link。 这就像我的程序无法访问我的播放器的action 成员。

有人有什么想法吗?

【问题讨论】:

  • attack()receiveAttack()printPlayer()newPlayer()的来源是什么? seg 失败发生在哪 exactly 行?您甚至可以使用 printf.... 获取该信息。
  • 顺便说一下,这是LOSER,不是LOOSER
  • 请尝试创建一个minimal reproducible example 向我们展示,包括功能(或它们的简化版本,不要忘记newPlayer)。也请尝试debug your program,至少尝试定位崩溃发生的时间和地点(并告诉我们)。最后请阅读how to ask good questions,以及this question checklist
  • 我的测试表明这是 p->action”,这意味着 p 包含无效地址。查看 valgrind 以找到您的问题
  • p-&gt;action == NOTHING 执行时:else{ p-&gt;action = WAIT;} 那么struct 是否为这种状态更改正确设置?

标签: c segmentation-fault


【解决方案1】:
char msg[2];
bzero(msg, strlen(msg));

好的,所以在这里您尝试计算未初始化字符串的长度,这是页面错误(和内核漏洞)的典型来源。 strlen 不知道你的数组的大小,它只是寻找一个零字符,很可能很快就会离开你的页面。即使程序此时没有崩溃,bzero 也会解决问题,因为它可能会写入你无法触及的内存。

请注意,通常用至少两个字符(“C4”左右)来描述一个单元格,因此scanf 将在msg 末尾写入终止零字符(同样,这甚至可能超出您的有效内存)。增加msg 的大小,使其至少可以容纳有效输入(至少三个字符,越多越好)。而且你不需要在这里打电话给strlen;如果你想预先清除你的数组,最简单的方法是正确初始化它:char msg[256] = {'\0'};

接下来,您没有显示您的NewPlayer() 的代码,但是您的结构包含三个指针字段,请仔细检查它们是否已正确分配和初始化。

【讨论】:

  • msg[] 声明为只有两个字符宽只是自找麻烦,尤其是因为它在堆栈上。如果必须使用scanf(),至少声明它是更安全的东西,例如msg[80+1]
  • 好的,我替换了我的bzero,它可以工作了!谢谢!但我还有一个问题:什么时候使用bzero
  • @LouisSinger 这只是一个没有严格触发器的设计选择。
猜你喜欢
  • 1970-01-01
  • 2019-04-22
  • 2020-05-14
  • 1970-01-01
  • 2020-02-06
  • 1970-01-01
  • 2014-05-31
  • 2016-10-22
相关资源
最近更新 更多