第二个printf,与我的第一个printf相同,会导致程序崩溃

时间:2012-09-06 19:48:48

标签: c malloc printf

我显然不是在这里责备printf,我可能搞砸了我的内存分配和访问但我无法理解我做错了什么。程序崩溃在主要的第二个printf。如果我评论第二个,它也会在第三个崩溃。实际上,只要我在第一次打印后访问p,它就会崩溃!

有人能解释我的错误吗?

非常感谢。

typedef struct 
{
    char * firstname;
    char * lastname;
    int age;
} person;

person * new_person(char * firstname, char * lastname, int age)
{
    person p;
    int lf = strlen(firstname);
    int ll = strlen(lastname);
    p.firstname = (char *)malloc(++lf * sizeof(char));
    p.lastname = (char *)malloc(++ll * sizeof(char));
    strcpy(p.firstname, firstname);
    strcpy(p.lastname, lastname);
    p.age = age;

    return &p;
}    

int main()
{
    person * p = new_person("firstname", "last", 28);

    printf("nom : %s ; prenom : %s ; age : %d\n", p->lastname, p->firstname, p->age);
    printf("nom : %s ; prenom : %s ; age : %d\n", p->lastname, p->firstname, p->age);

    printf("nom : %s ; prenom : %s ; age : %d\n", (*p).lastname, (*p).firstname,(*p).age);

    return 0;
}

4 个答案:

答案 0 :(得分:5)

您将返回本地变量的地址。

您可以修改new_person以获取参数(指向某个人的指针),也可以malloc在函数内部操作并操纵它。

当函数返回时,函数中声明的人超出了范围。之后发生的一切都是未定义的。它可能巧合地保持其价值一段时间,但你不应该依赖于此。当你打电话给printf时,堆栈会增长,并用新东西覆盖你人的旧位置。

答案 1 :(得分:3)

我认为问题出在这一行:

return &p;

请注意,您正在返回指向局部变量的指针。这会导致未定义的行为,因为只要函数返回,局部变量p就不再存在。因此,读取或写入该指针将读取或写入垃圾数据。

这不会立即崩溃的事实是编译器如何生成代码的工件。很有可能,当你第一次打电话给printf时,它会重复使用之前用于p的空间,这种方式纯粹巧合。但是,在函数返回后,其堆栈帧已经破坏了p的旧内存。因此,对printf的第二次调用是读取调用printf后留下的垃圾数据,因此崩溃。

(具体来说:当你传递参数时,它会将指向字符串的指针复制到堆栈中,所以当printf运行时,它可能会破坏原始指针,但是使用副本。第二次调用然后加载垃圾来自过期printf堆栈框架的指针,因为它位于p过去居住的同一地址。)

要解决此问题,请考虑将p更改为指向person的指针,然后使用malloc进行分配。这样,内存持续超出函数调用,因此崩溃应该消失。

希望这有帮助!

答案 2 :(得分:1)

 person p;

// stuff

return &p

错误。函数返回后,局部变量将离开范围 - 其地址将无效。您必须在堆上分配结构:

person *new_person(char *firstname, char *lastname, int age)
{
    person *p = malloc(sizeof(*p));
    p->firstname = strdup(firstname);
    p->lastname = strdup(lastname);
    p->age = age;

    return p;
}    

答案 3 :(得分:0)

问题出在函数new_person中。您在堆栈上创建人员p并返回其地址。你需要分配人* p =新人(.....