【问题标题】:the second printf, identical to my first printf, makes the program crash第二个 printf 与我的第一个 printf 相同,使程序崩溃
【发布时间】:2012-09-06 19:48:47
【问题描述】:

我显然不是在这里责怪 printf,我可能搞砸了我的内存分配和访问,但我不明白我哪里做错了。程序在 main 中的第二个 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;
}

【问题讨论】:

  • 您正在返回一个指向局部变量的指针。
  • 尝试开启编译器警告。你应该得到warning C4172: returning address of local variablewarning: function returns address of local variable(或等效的东西,取决于你使用的编译器)。
  • 另外,mallocing 和 strcpy'ing 应该在实现 strdup 的平台上受到惩罚。

标签: c malloc printf


【解决方案1】:

您正在返回一个局部变量的地址。

您可以修改您的 new_person 以获取参数(指向人的指针),或者您可以在函数中使用 malloc 并对其进行操作。

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

【讨论】:

  • 除非 OP 明白为什么这是一个主要的禁忌,否则这个答案并不能真正解释为什么这样做是一个坏主意。
【解决方案2】:

我认为问题出在这一行:

return &p;

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

这不会立即崩溃的事实是编译器如何生成代码的产物。很有可能,当您第一次调用 printf 时,它会重用以前用于 p 的空间,这种方式纯属巧合,效果很好。然而,在函数返回后,它的堆栈帧已经破坏了p 的旧内存。结果,对printf 的第二次调用正在读取对printf 的调用留下的垃圾数据,因此发生了崩溃。

(具体来说:当您传递参数时,它将指向字符串的指针复制到堆栈上,因此当printf 运行时,它可能会丢弃原始指针,但使用副本。第二次调用然后从过期的printf 堆栈帧,因为它与p 以前的地址相同。)

要解决此问题,请考虑将p 更改为指向person 的指针,然后使用malloc 分配它。这样,内存在函数调用之后仍然存在,所以这个崩溃应该会消失。

希望这会有所帮助!

【讨论】:

  • 你可能会特别提到,在调用 printf 之前,悬空的人的值是不变的。 printf 的参数是在调用之前组装的,因为参数都是指向内存中其他地方的 char 数组的指针,所以 printf 的操作不会破坏这些数组。但是,当 printf 工作时,它会破坏 person 本身,因此第二次尝试从 person 的原始位置加载指针会返回垃圾,并且在尝试取消引用垃圾时程序段会出错。您触及了它,但没有详细说明。
【解决方案3】:
 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;
}    

【讨论】:

    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-06
      • 2014-10-03
      • 1970-01-01
      • 2012-03-12
      • 1970-01-01
      相关资源
      最近更新 更多