[英]How to free double pointer array in C?
I am trying to write a function to deallocate/free a double pointer in C. I have a struct that has an allocated char, and a double pointer to another struct I have.我正在尝试编写一个函数来释放/释放 C 中的双指针。我有一个具有已分配字符的结构,以及一个指向我拥有的另一个结构的双指针。 I need to create a function free of that memory.我需要创建一个没有该内存的函数。 The structs I have:我拥有的结构:
typedef struct {
char *name; // allocated
int age;
int height;
} student;
typedef struct {
char *name; // allocated
char *location; // allocated
double area;
int population;
student **students; // fully allocated, NOT a reference array
} school;
I need to dispose the school function, I do have a function already but I'm not sure it's right我需要处理学校功能,我已经有一个功能但我不确定它是否正确
void dispose_school(school *r)
{
free(r->name);
free(r->location);
free(r->students[i]);
free(r);
}
If someone can shine some light, thank you!如果有人可以发光,谢谢!
You will have to iterate through all the elements of students
, free them.您将不得不遍历students
的所有元素,释放它们。 And then after your loop completes, free students
as well.然后在你的循环完成后,免费的students
也是如此。 See this code-请参阅此代码-
for(int i = 0;i < r->population;i++) {
free(r->students[i]->name); // do this if your students[i]->name is dynamically allocated
free(r->students[i]);
}
free(r->students);
Freeing the double pointer is straightforward.释放双指针很简单。 You have the pointers you allocate to hold each student
, you have the struct you allocate to hold each students values ( name
, age
, height
), and finally you have the name
you allocated storage for to hold the student's name.你有你分配来保存每个student
的指针,你有你分配来保存每个学生值的结构( name
, age
, height
),最后你有你分配存储的name
来保存学生的名字。 This specifies the order in which you would have needed to allocate the memory.这指定了分配内存所需的顺序。
To free()
a complex set of allocations, you simply take the order in reverse .要free()
一组复杂的分配,您只需将顺序颠倒过来。 Here you have some number of students (the population
), so you would loop school->population
times freeing:在这里,您有一些学生( population
),因此您将循环school->population
时间释放:
name
;分配用于保存学生name
的内存块;After the loop completes, then you free all of the pointers students
.循环完成后,您将释放所有指针students
。
That will free all the memory you have allocated for students
, but you are not done.这将释放您为students
分配的所有内存,但您还没有完成。 You will have also allocated storage for the school name
, location
and perhaps the school struct itself (unless you declared the base school struct with automatic-storage-duration ).您还将为学校name
、 location
以及学校结构本身分配存储空间(除非您使用自动存储持续时间声明了基础学校结构)。
Presuming you have allocated for the school struct and the rest of the pointers, you can write a free function that takes a pointer to the school and free all memory with something similar to the following (assuming you have used school->population
as the student counter):假设您已为 school 结构和其余指针分配,您可以编写一个 free 函数,该函数接受指向 school 的指针并使用类似于以下内容释放所有内存(假设您已使用school->population
作为学生柜台):
void destroy_school (school *s)
{
/* loop over each student and free storage for (1) name and (2) struct */
while (s->population--) {
free (s->students[s->population]->name);
free (s->students[s->population]);
}
/* free storage for student pointers */
free (s->students);
/* free school name, location and school struct */
free (s->name);
free (s->location);
free (s); /* remove if s has automatic-storage-duration */
}
A Short Example一个简短的例子
Putting the pieces together to allocate and free()
all the needed information, you can write a short program to do so.将这些部分放在一起以分配和free()
所有需要的信息,您可以编写一个简短的程序来执行此操作。 Splitting the code into functions to create_school()
, add_student()
, print_school()
and destroy_school()
keeps the logic straight.将代码拆分为函数create_school()
、 add_student()
、 print_school()
和destroy_school()
保持逻辑清晰。 Using the population
as your student counter, you could do something similar to:使用population
作为你的学生计数器,你可以做类似的事情:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name; // allocated
int age;
int height;
} student;
typedef struct {
char *name; // allocated
char *location; // allocated
double area;
int population;
student **students; // fully allocated, NOT a reference array
} school;
school *create_school (const char *name, const char *loc, double area)
{
school *s = NULL; /* create school ptr init NULL */
size_t len = strlen (name); /* get lenght of name parameter */
if (!(s = malloc (sizeof *s))) { /* allocate/VALIDATE struct school */
perror ("malloc-s"); /* handle error on allocation fail */
return NULL; /* return failure */
}
if (!(s->name = malloc (len + 1))) { /* allocate/VALIDATE for name */
perror ("malloc-s.name"); /* handle error on allocation fail */
free (s); /* clean up previous allocations */
return NULL;
}
memcpy (s->name, name, len + 1); /* copy name to s->name */
len = strlen (loc);
if (!(s->location = malloc (len + 1))) { /* allocate/VALIDATE for loc */
perror ("malloc-s.loc"); /* handle error */
free (s->name); /* clean up prior allocations */
free (s);
return NULL;
}
memcpy (s->location, loc, len + 1); /* copy location to school */
s->area = area; /* set area and pop */
s->population = 0;
s->students = NULL; /* init students ptr NULL */
return s; /* return allocated school struct */
}
int add_student (school *s, const char *name, int age, int height)
{
size_t len = strlen (name); /* length of name */
void *tmp;
/* reallocate/VALIDATE pointer for next student
* ALWAYS realloc() using a temporary pointer so if realloc() fails
* you don't overwrite your original pointer with NULL creating a
* memory leak.
*/
if (!(tmp = realloc (s->students, (s->population + 1) *
sizeof *s->students))) {
fprintf (stderr, "error: realloc student: %d\n", s->population);
return 0;
}
s->students = tmp; /* assign realloc'ed block to students */
/* allocate/VALIDATE storage for struct student */
if (!(s->students[s->population] = malloc (sizeof **s->students))) {
perror ("malloc-s->students[s->population");
return 0;
}
/* allocate/VALIDATE storage for student name */
if (!(s->students[s->population]->name = malloc (len + 1))) {
perror ("malloc-s->students[population]->name");
return 0;
} /* copy name to allocated space */
memcpy (s->students[s->population]->name, name, len + 1);
s->students[s->population]->age = age; /* assign age and height */
s->students[s->population]->height = height;
s->population += 1; /* increment pop count */
return 1; /* return success */
}
void print_school (school *s)
{
printf ("\nSchool : %s\n"
"Location : %s\n"
"Area : %.2f\n"
"N-Students : %d\n\n",
s->name, s->location, s->area, s->population);
for (int i = 0; i < s->population; i++) {
printf (" %02d %-16s %4d %4d\n",
i,
s->students[i]->name,
s->students[i]->age,
s->students[i]->height);
}
}
void destroy_school (school *s)
{
/* loop over each student and free storage for (1) name and (2) struct */
while (s->population--) {
free (s->students[s->population]->name);
free (s->students[s->population]);
}
/* free storage for student pointers */
free (s->students);
/* free school name, location and school struct */
free (s->name);
free (s->location);
free (s);
}
int main (void) {
/* allocate/initialize struct school, population == 0, students == NULL */
school *RidgeMontHigh = create_school ("Ridgemont High",
"Hollywood, CA", 2357.8);
if (!RidgeMontHigh) { /* validate creation of school */
return 1;
}
/* add students to school (can validate each, but population will do) */
add_student (RidgeMontHigh, "Mickey Mouse", 103, 48);
add_student (RidgeMontHigh, "Minnie Mouse", 99, 44);
add_student (RidgeMontHigh, "Pluto (the dog)", 97, 47);
add_student (RidgeMontHigh, "Daffy Duck", 102, 46);
if (RidgeMontHigh->population == 0) { /* validate non-zero student pop */
return 1;
}
print_school (RidgeMontHigh); /* print school followed by students */
destroy_school (RidgeMontHigh); /* free all memory involved */
}
Example Use/Output示例使用/输出
Compiling and running the code will produce the following:编译并运行代码将产生以下结果:
./bin/schoolpop
School : Ridgemont High
Location : Hollywood, CA
Area : 2357.80
N-Students : 4
00 Mickey Mouse 103 48
01 Minnie Mouse 99 44
02 Pluto (the dog) 97 47
03 Daffy Duck 102 46
Memory Use/Error Check内存使用/错误检查
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您有 2 个责任:(1)始终保留指向内存块起始地址的指针,(2)它可以在它不存在时被释放更需要。
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.您必须使用内存错误检查程序,以确保您不会尝试访问内存或写入超出/超出分配块的范围,尝试读取或基于未初始化值的条件跳转,最后确认释放所有分配的内存。
For Linux valgrind
is the normal choice.对于 Linux valgrind
是正常的选择。 There are similar memory checkers for every platform.每个平台都有类似的内存检查器。 They are all simple to use, just run your program through it.它们都易于使用,只需通过它运行您的程序即可。
$ valgrind ./bin/schoolpop
==18986== Memcheck, a memory error detector
==18986== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==18986== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==18986== Command: ./bin/schoolpop
==18986==
School : Ridgemont High
Location : Hollywood, CA
Area : 2357.80
N-Students : 4
00 Mickey Mouse 103 48
01 Minnie Mouse 99 44
02 Pluto (the dog) 97 47
03 Daffy Duck 102 46
==18986==
==18986== HEAP SUMMARY:
==18986== in use at exit: 0 bytes in 0 blocks
==18986== total heap usage: 16 allocs, 16 frees, 1,290 bytes allocated
==18986==
==18986== All heap blocks were freed -- no leaks are possible
==18986==
==18986== For lists of detected and suppressed errors, rerun with: -s
==18986== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.始终确认您已释放所有已分配的内存并且没有内存错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.