【问题标题】:Returning a pointer to a struct using dynamic memory allocation使用动态内存分配返回指向结构的指针
【发布时间】:2014-10-13 04:11:18
【问题描述】:

我正在尝试返回一个指向我创建的新结构的指针,但我遇到了分段错误并且不确定如何以正确的方式执行此操作。

这是我现在正在使用的:

 typedef struct person{
  int age;
  char *name;
 }Person;

 Person *new_person(int age, const char *name){
  Person *x = malloc(sizeof(x));
  x->age = age;
  strcpy(x->name, name);
  return x;
 }

我一直在使用我在网上找到的教程/其他问题中的代码进行调整。但我似乎无法弄清楚我做错了什么,无论是我分配内存的方式还是我返回指针的方式。

我遇到的另一个问题是将任何关联内存与某个人解除分配。假设我想删除一个人,并释放与该人动态关联的内存。我搜索了它,它说我应该使用free 方法。但是我仍然会遇到内存泄漏。我有这样的设置:

void kill_person(Person *x){
    free(x->name);
    free(x);
}

我应该打电话给free(*x)吗?我也应该打电话给free(x->name)吗?

【问题讨论】:

  • 您应该在调用free(x); 之前调用free(x->name);,假设您首先使用单独的分配来分配x->name。对于代码中的每个malloc(),应该有一个匹配的free()。 (使用realloc() 会使事情稍微复杂化,但基本概念仍然有效——对于每个尚未释放的分配,您应该能够指向匹配的free()。)
  • @JonathanLeffler 我将 op 更新为我正在使用的内容,但我仍然遇到内存泄漏并且没有正确释放
  • 泄漏的方法有无数种,我们无法猜出你做了什么。您可以使用valgrind 吗?如果是这样,请使用它(但使用-g 编译代码以获得关于泄漏发生位置的更好报告)。如果您无法获得valgrind,则必须生成一个 MCVE (How to create a Minimal, Complete, and Verifiable Example?) 或 SSCCE (Short, Self-Contained, Correct Example) — 相同基本思想的两个名称和链接 — 更新(而不是覆盖)问题。但如果可以,请使用valgrind
  • @JonathanLeffler 我对你所说的有点困惑。我正在做的是一项任务,我知道我在运行我提供的测试时遇到了内存泄漏。测试运行我的方法并检查我在运行方法后是否正确释放了内存。 (所以我知道问题出在其中一种方法中)
  • 我是说有很多不同的方法来创建泄漏,如果没有看到所有的分配和释放代码,我们不可能猜出你正在使用哪种泄漏方法。这是不幸的,但也是生活中的事实。你不应该在这里向我们展示你所有的代码。但是,如果您创建一个仍然泄漏的 MCVE,您可以证明这一点。但是最好学习valgrind,它会直接告诉您内存泄漏的位置。

标签: c pointers struct segmentation-fault malloc


【解决方案1】:
Person *x = malloc(sizeof(x));

你的意思是写

Person *x = malloc(sizeof(*x));

sizeof x == sizeof(Person*),所以你只为指针分配了足够的内存。你的下一个段错误将(可能)在这一行:

strcpy(x->name, name);

您从未分配过x->name。一个适当的功能是:

Person *new_person(int age, const char *name) {
    Person *x = malloc(sizeof *x);
    x->name = malloc(strlen(name) + 1);
    x->age = age;
    strcpy(x->name, name);
    return x;
} 

【讨论】:

  • 啊,谢谢,我正在学习的帖子从未为名称分配内存,所以我认为这是不必要的。如果你能指出我最有帮助的正确方向,我会更新 OP 并提出另一个关于解除分配的问题
  • 哇由于某种原因在这里发布,试图修复
  • @Ed S. 是否也需要为x->name 分配内存..?而不是,我们可以尝试像x->name= name (在参数中分配没有const 的字符串地址)。有可能吗?
  • Person *x = malloc(sizeof(*x)) 将为指向 Person 的指针分配内存,而不是为 Person 本身分配内存。 op 不想为 Person 分配吗?
  • @RavichandraSutrave:不,不会。它将分配sizeof *x 字节,即sizeof Person。你倒退了。
【解决方案2】:

您需要为 Person 以及它的指针分配空间,即名称。否则,即使 Person 被分配,它的 name 部分也将保持未分配。

选项 1:

typedef struct person{
  int age;
  char *name;
 }Person;

Person *new_person(int age, const char *name){
  Person *x = (Person *) malloc(sizeof(Person));
  if (name != NULL) {
      x->name = (char *) malloc(strlen(name) + 1);
  }
  x->age = age;
  strcpy(x->name, name);
  return x;
 }
void kill_person(Person *x){
    free(x->name);
    free(x);
}
int main() {
  Person *p = new_person(28, "Neel Lohit");
  // code to use p, when done, call kill_person
  kill_person(p);
  return 0;
}

选项 2(具有固定静态分配的名称部分):

#define MAX_SZ 100
typedef struct person{
  int age;
  char name[MAX_SZ+1];
 }Person;

Person *new_person(int age, const char *name){
  Person *x = (Person *) malloc(sizeof(Person));
  x->age = age;
  strcpy(x->name, name);
  return x;
 }
void kill_person(Person *x){
    free(x);
}
int main() {
  Person *p = new_person(28, "Neel Lohit");
  // code to use p, when done, call kill_person
  kill_person(p);
  return 0;
}

【讨论】:

  • 感谢两个不同的例子!如果你能指出我正确的方向,我更新了 OP 关于解除分配的另一个问题
  • 在愉快地使用结果之前,您需要检查每个分配是否有效。在第一个代码中,如果name == NULLstrcpy() 可能会崩溃(它会调用未定义的行为,并且对这种特定未定义行为的通常响应通常是崩溃)。在后面的代码中,可以说您应该确保name 不长于MAX_SZ
  • @Mark,更新了我关于解除分配的答案,接受答案吗?
猜你喜欢
  • 2015-07-04
  • 2013-04-18
  • 2019-07-08
  • 2021-12-26
  • 2018-05-16
  • 1970-01-01
  • 2012-07-16
  • 1970-01-01
  • 2010-09-30
相关资源
最近更新 更多