-2

I have this example file

example.c

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

typedef struct {
    char *name;
} player;

void
playercreation(player *p, int nr)
{
    p=malloc(sizeof(player));
    char stringtemp[10];
    printf("Create player %d:\nWrite your name (max 10 letters): ", nr);
    scanf("%s", stringtemp);
    p->name=malloc(sizeof(*(p->name))*11);
    strcpy(p->name, stringtemp);
    p->drawnlines=0;
    p->squares=0;
}

void
playercreationMenu(player *p1, player *p2)
{
    playercreation(p1, 1);
    playercreation(p2, 1);
}

void
confirmPlayer(player *p)
{
    printf("player %s created\n", p->name);
}

int
main(void)
{
    player p1, p2;
    playercreationMenu(&p1, &p2);
    confirmPlayer(&p1);
    confirmPlayer(&p2);
}

In my real program this gives me a segmentation fault as im trying to access something in the player structure that does not exist as the player never is created, but in this example its shown by the fact that the players name is (null) although the name was given in the playercreationMenu function. Why is this?

4

4 回答 4

3

count未初始化。垃圾进垃圾出。

于 2012-11-08T18:11:45.080 回答
2

你写

player p1, p2;
playercreationMenu(&p1, &p2);

但是在构造函数中,你有

void playercreation(player *p, int nr)
{
    p = malloc(sizeof(player));

    ...
}

因此,您正在malloc()为包含已分配(在堆栈上!)结构的地址的局部变量分配一个 ated 内存块......放下调用malloc(),你会没事的。

您还在count初始化变量或为其赋值之前使用该变量:

int count;
...
p->name = malloc(sizeof(char) * (count + 1));

因此,第一,这是未定义的行为,第二,您将获得相当随机的内存量(这使得写入超出其界限 -> 另一个未定义的行为成为可能),或者如果这会导致分配过多的内存,则为 NULL 指针(第三个未定义的行为)。

一行中的三个 UB -确实希望它崩溃。

于 2012-11-08T18:13:21.160 回答
2

您的代码在这两行中存在问题:

p=malloc(sizeof(player));
int count;

malloc 不是必需的,因为当您在 main() 中声明它们时,您已经在堆栈上为播放器结构分配空间。

您没有初始化计数,这意味着它具有垃圾值。当您使用 count 调用 malloc 时,您可能会请求任意大量的内存。

于 2012-11-08T18:15:52.617 回答
1

一方面,count正如其他一些人所指出的那样,您永远不会初始化。这意味着它是一个任意值,因此您不知道要传递给malloc.

您也可能不应该使用scanf,因为如果有人键入超过 10 个字符,您将溢出缓冲区。我会推荐fgets

此外,您首先在堆栈中声明您的玩家,并将指向他们的指针传递到playercreationMenu. 那也行。然后你将它们传递给playercreation,这也很好。在playercreation中,您然后用从 中返回的指针覆盖指向播放器的指针mallocplayer因此,您实际上永远不会对您在堆栈中分配的原始 s 执行任何操作main

正如 Basile 所建议的那样,编译-Wall以获得更多编译器警告并密切关注它们是一个好主意。其实,我更喜欢-Wall -Wextra -Werror; -Wall实际上并没有给你所有的警告,所以-Wextra打开一些更有用的警告,-Werror把警告变成错误,这样你就不能忽略它们。

于 2012-11-08T18:21:56.790 回答