我对这个小程序有疑问:
更新(根据某些要求,我已将所有内容都包含在此处,以便明确我正在做的事情。抱歉它太长了): 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)?或者还有别的我做错了吗?请帮忙!
答案 0 :(得分:2)
问题是,当您完成Student
或StudentList
并且不再需要它时,您会怎么做?这就是你应该为该结构中所有分配的东西调用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)
当您不再需要使用已分配的对象时,应释放内存。
什么是StudentList
和Student
?在我看来,你的数据结构是不正确构建的。为什么您的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名学生插入列表,然后尝试打印列表。