在C中释放内存

时间:2009-04-15 17:46:24

标签: c pointers memory-leaks

我对这个小程序有疑问:

更新(根据某些要求,我已将所有内容都包含在此处,以便明确我正在做的事情。抱歉它太长了): Student.h文件:

typedef struct Student {
  char *name;
  int age;
  char *major;
    char *toString;
} *Student;

extern Student newStudent(char *name, int age, char *major);

Student.c文件: ç

har *studentToString(Student s);
static void error(char *s) {
  fprintf(stderr,"%s:%d %s\n",__FILE__,__LINE__,s);
  exit(1);
}

extern Student newStudent(char *name, int age, char *major) {
  Student s;
    if (!(s=(Student)malloc(sizeof(*s)))){
    error("out of memory");
    }
  s->name=name;
  s->age=age;
  s->major=major;
    s->toString = studentToString(s);
  return s;
}

char *studentToString(Student s) {
  const int size=3;
  char age[size+1];
  snprintf(age,size,"%d",s->age);

  char *line=newString();
  line=catString(line,"<");
  line=catString(line,s->name);
  line=catString(line," ");
  line=catString(line,age);
  line=catString(line," ");
  line=catString(line,s->major);
  line=catString(line,">");
  return line;
}

Students.c文件:

static void error(char *s) {
  fprintf(stderr,"%s:%d %s\n",__FILE__,__LINE__,s);
  exit(1);
}

static StudentList alloc(StudentList students, Student student) {

  StudentList p;
    if (!(p=(StudentList)malloc(sizeof(*p)))){
    error("out of memory");}
  p->student=student;
  p->students=students;
  return p;
}

extern Students newStudents() {
  Students p;
    if (!(p=(Students)malloc(sizeof(*p)))){
    error("out of memory");
    }
  p->cursor=0;
  p->students=0;
  return p;
}

extern void addStudent(Students students, Student student) {
  StudentList p=students->students;
  if (!p) {
    students->students=alloc(0,student);

    return;
  }
while (p->students)
     p=p->students;
  p->students=alloc(0,student); 
    }    

extern void initStudent(Students students) {
  students->cursor=students->students;
}

extern Student currStudent(Students students) {
  StudentList cursor=students->cursor;
  if (!cursor)
    return 0;
  return cursor->student;
}

extern void nextStudent(Students students) {
  students->cursor=students->cursor->students;
}

我的主要方法:

int main() {
  Students students=newStudents();
  addStudent(students,newStudent("Julie",22,"CS"));
  addStudent(students,newStudent("Trevor",32,"EE"));

  for (initStudent(students);
       currStudent(students);
       nextStudent(students)) {
      char *line=currStudent(students)->toString;
    printf("%s\n",line);
      free(currStudent(students));
    free(line);
  }

    free(students->students);
    free(students);
  return 0;
}

我正在使用valgrind检查内存泄漏,并且弹出以下错误:

8 bytes in 1 blocks are definitely lost in loss record 1 of 1
==9520==    at 0x40054E5: malloc (vg_replace_malloc.c:149)
==9520==    by 0x8048908: alloc (Students.c:13)
==9520==    by 0x80489EB: addStudent (Students.c:42)
==9520==    by 0x804882E: main (StudentList.c:10)

我知道我需要在 alloc 函数中释放为p分配的内存,但是我应该在哪里调用free(p)?或者还有别的我做错了吗?请帮忙!

8 个答案:

答案 0 :(得分:2)

问题是,当您完成StudentStudentList并且不再需要它时,您会怎么做?这就是你应该为该结构中所有分配的东西调用free()

您可能需要一个freeStudents函数来遍历学生列表,并释放其中的所有Student项和所有StudentList项。然后,只要你想要删除学生列表,就可以调用该函数。

答案 1 :(得分:2)

对不起,这很切,但你可以做很多事情来让你的代码更具可读性。

创建一个结构,然后将其类型重新定义为指向它的指针。哎呀,这就是在可维护性方面遇到麻烦。隐藏指针是指针这一事实通常是一个坏主意,因为当人们看到这样的事情时:

Students newStudents()
{
  Students p;
  // ...
  return p;
}

约定迫使我们假设您正在返回在堆栈上分配的结构,这显然是不正确的。 (编辑:不一定“明显不正确”,但浪费的副本。)

当你添加malloc时,事情变得更加毛茸茸......

Students p;
if (!(p=(Students)malloc(sizeof(*p))))
{
  error("out of memory");
}

首先,如上所述,人们认为没有*,学生是一个完整的结构。这将使任何看到“sizeof(* p)”的人做双重拍摄。你正在做什么并不明显。

虽然将赋值和比较压缩成一个if语句是完全有效的C和C ++,但它通常不是最易读的解决方案。很多改进:

Students* newStudents ()
{
  Students* p = (Students*) malloc (sizeof (Students));
  if (p == NULL)
  {
     // ...
  }
  // ...
  return p;
}

人们喜欢指出在C语言中不需要转换malloc的返回值,但它是在C ++中。

至于你的泄漏,嗯... valgrind没有报告你的catString用法,但是由于你隐藏了内存使用情况,它仍然很粗略。使用snprintf是一种更好,更惯用的方式来创建你想要的字符串。

泄密valgrind正在报告:看起来你只是在释放列表中的第一个“学生”节点。你需要遍历它并释放它们,可能是这样的:

Students p = students;
while (p)
{
  Students next = p->students;
  free (p);
  p = next;
}

答案 2 :(得分:1)

我认为你在alloc中遇到了问题。

如果你想要一个指针,它应该是

StudentList *p;
p = (StudentList*)malloc(sizeof(StudentList));

答案 3 :(得分:0)

如果我使用malloc(),我不会将sizeof与变量一起使用。您应该使用malloc(n * sizeof(StudentList))。随着那说......

你有一些重大问题。首先,您没有告诉我们学生和学生列表是专门定义的。在某些情况下,当我认为你的意思是NULL时,你传递0 - 当你的意思是NULL时,永远不要使用0。如果malloc()失败 - 意思是,它返回NULL - 那么你不会在结果上调用free()。从不,永远免费NULL。

你应该只释放一个(a)成功分配的内存块,以及(b)当你不再需要它时。这似乎没有在这里输入您的代码。

还有其他问题(你假设在初始化p时addStudent中的学生是非NULL的),但它们并没有完全解决你关于free()的使用的问题。

答案 4 :(得分:0)

这是做什么的:

if (!(p=(StudentList)malloc(sizeof(*p)))){
    free(p);

那么,如果无法分配p,请将其释放吗?

答案 5 :(得分:0)

我假设StudentList是typedefined,是某种类型的指向Student的指针。在这种情况下,你的alloc函数中的这一行是个问题。 p=(StudentList)malloc(sizeof(*p))

您正在尝试在指针分配之前取消引用该指针,但这并不好。

答案 6 :(得分:0)

当您不再需要使用已分配的对象时,应释放内存。

什么是StudentListStudent?在我看来,你的数据结构是不正确构建的。为什么您的StudentList存储指向另一个StudentList的指针?您可能应该使用StudentList创建malloc并使用您的newStudents函数返回指向该addStudent的指针,而不是在{{1}中返回带有旧版本的新StudentList结构,只需修改您最初创建的结构。

所以它会是这样的:

StudentList *newStudentList() {
    //malloc a new StudentList and return the pointer
}
void freeStudentList(StudentList *list) {
    //free the list pointer and all its child resources (i.e. the students in the list)
}
Student *newStudent(const char *name, etc) {
    //malloc a new Student and return the pointer
}
void addStudentToList(StudentList *list, Student *student) {
    //modify the StudentList which has been passed in by adding the student to it.
}

如果您不打算单独使用它们,可以将newStudent合并到addStudent中,如果您打算单独从freeStudentList执行这些操作,则可能需要freeStudent和removeStudentFromList函数。您应该在Google上查看C中动态数据结构的示例(here是Google上的第一个结果,但还有很多其他结果)。

答案 7 :(得分:0)

您确实需要定义您的类型。您可以编辑帖子以包含学生学生列表学生的定义吗?

此外,

StudentList p;
p = (StudentList) malloc(sizeof(*p);

除非 StudentList 是指针的typedef,否则我不确定它是如何编译的。

我们也有这条线:

StudentList p=students->students

将p定义为学生。那么学生也必须是指针的typedef。


另外,我认为最终的问题是,当您尝试在链接列表中插入学生时,最终会丢失任何现有列表。您尝试的有趣之处是将3名学生插入列表,然后尝试打印列表。