如何释放在双指针结构上分配的内存
How to free memory allocated on double pointer struct
如何释放在此结构中分配的内存
struct image_t {
char type[3];
int **ptr;
int width;
int height;
};
在第一个函数中我做了这些分配:
struct image_t *struktura = (struct image_t *)malloc(sizeof(struct image_t));
int **ptr = (int**)malloc(struktura->height * sizeof(int*));
for (i = 0; i < struktura->height; i++) {
*(ptr + i) = (int *)malloc(struktura->width * sizeof(int));
if (*(ptr + i) == NULL) {
break;
}
}
在第二个函数中,我必须释放分配的内存,所以我尝试像这样释放内存,但它不起作用
void destroy_image(struct image_t **m) {
if (m != NULL) {
if (*m != NULL) {
if ((*m)->ptr != NULL) {
for (int i = 0; i < (*m)->height; i++) {
free(*((*m)->ptr + i));
}
free((*m)->ptr);
free(*m);
}
}
}
}
我无法更改 destroy 函数的声明,因此结构上必须有双指针。
这是不必要的复杂和低效的。看看 .
您可以像这样更改结构:
struct image_t {
char type[3];
int* ptr; // placeholder pointer
int width;
int height;
};
然后像这样 malloc:
struct image_t* s = malloc(sizeof *s);
s->width = width;
s->height = height;
s->ptr = malloc( sizeof(int[width][height]) );
(记得检查每个 malloc 的结果,如果 returns NULL 则停止程序。)
然后像这样使用它:
int (*arr)[s->height] = (void*) s->ptr; // convert to a temporary 2D array pointer
...
arr[i][j] = whatever; // this enables 2D array access syntax
然后像这样释放它:
free(s->ptr);
free(s);
首先...
不要强制转换 malloc
返回的值
不要使用 *(ptr + i)
使用等效但更易读的版本,即 ptr[i]
这样做会将您的分配更改为:
struct image_t *struktura = malloc(sizeof(struct image_t));
int **ptr = malloc(struktura->height * sizeof(int*));
for (i = 0; i < struktura->height; i++) {
ptr[i] = malloc(struktura->width * sizeof(int));
if (ptr[i] == NULL) {
break;
}
}
这是第一个问题...您永远不会将 ptr
分配给任何东西。在代码块的末尾你需要添加:
struktura->ptr = ptr;
另一个问题是struktura->height
和struktura->width
在使用时都没有初始化。它们必须在使用前被赋值。
释放分配的内存:您当前的代码太复杂了。像 free(*((*m)->ptr + i));
这样的语句包含 3 个指针取消引用!!那很难读。我会建议您使用一些局部变量来简化代码。
void destroy_image(struct image_t **m) {
if (m == NULL) return;
if (*m == NULL) return;
struct image_t *t = *m;
int **ptr = t->ptr;
if (ptr != NULL)
{
for (int i = 0; i < t->height; i++)
{
free(ptr[i]);
}
free(ptr);
}
free(t);
*m = NULL; // The only reason to pass a double pointer to this
// function is to be able to change *m. I guess
// the prototype authoe wants the function to set
// *m to NULL
}
通过使用这些局部变量,代码比 free(*((*m)->ptr + i));
这样的东西更容易阅读
而对于分配码中的break
...
有点奇怪(错误?),您在前两个 malloc
之后不检查 NULL 然后在循环中执行。此外,使用 break
有点奇怪,因为它会使其余指针未初始化。
无论如何 - 如果你真的想要在分配代码中 break
,你还需要在释放内存时考虑到这一点。类似于:
void destroy_image(struct image_t **m) {
if (m == NULL) return;
if (*m == NULL) return;
struct image_t *t = *m;
int **ptr = t->ptr;
if (ptr != NULL)
{
for (int i = 0; i < t->height && ptr[i] != NULL; i++)
{
free(ptr[i]);
}
free(ptr);
}
free(t);
*m = NULL;
}
为了使您的销毁函数正常工作,指针数组中的所有指针都必须有效或为空。由 malloc()
编辑的内存 return 未初始化,因此在分配函数中退出循环会使指针数组的其余部分未初始化,因此不应传递给 free()
.
另请注意,您应该测试结构指针和指针数组的分配失败。此外,新分配的结构的 width
和 height
成员未初始化:您应该使用函数参数来初始化它们。
destroy_image
函数可能应该在释放后将 *m
设置为 NULL
,并且必须 free(*m);
即使 (*m)->ptr
是一个空指针。
以下是此问题的解决方案:
- 使用
calloc()
(在所有情况下都是一个好主意)或 分配数组
- 设置
height
为分配成功的指针数
- 显式设置数组中剩余的指针为
NULL
- 分配失败时释放分配的块并且return
NULL
。
这是修改后的版本:
#include <stdlib.h>
struct image_t {
char type[3];
int **ptr;
int width;
int height;
};
struct image_t *allocate_image(int width, int height) {
struct image_t *struktura = calloc(1, sizeof(*struktura));
if (struktura == NULL)
return NULL;
// should initialize struktura->type too
struktura->width = width;
struktura->height = height
struktura->ptr = calloc(height, sizeof(*struktura->ptr));
if (struktura->ptr == NULL) {
free(struktura);
return NULL;
}
for (int i = 0; i < height; i++) {
struktura->ptr[i] = calloc(sizeof(*struktura->ptr[i]), width);
if (struktura->ptr[i] == NULL) {
// Iterate downwards on index values of allocated rows
// (i --> 0) is parsed as (i-- > 0)
// this test works on signed and unsigned index types, unlike (--i >= 0)
while (i --> 0) {
free(struktura->ptr[i]);
}
free(struktura->ptr);
free(struktura);
return NULL;
}
}
return struktura;
}
void destroy_image(struct image_t **m) {
if (m != NULL) {
struct image_t *p = *m;
if (p != NULL) {
if (p->ptr != NULL) {
for (int i = 0; i < p->height; i++) {
free(p->ptr[i]);
}
free(p->ptr);
}
free(p);
*m = NULL;
}
}
}
如何释放在此结构中分配的内存
struct image_t {
char type[3];
int **ptr;
int width;
int height;
};
在第一个函数中我做了这些分配:
struct image_t *struktura = (struct image_t *)malloc(sizeof(struct image_t));
int **ptr = (int**)malloc(struktura->height * sizeof(int*));
for (i = 0; i < struktura->height; i++) {
*(ptr + i) = (int *)malloc(struktura->width * sizeof(int));
if (*(ptr + i) == NULL) {
break;
}
}
在第二个函数中,我必须释放分配的内存,所以我尝试像这样释放内存,但它不起作用
void destroy_image(struct image_t **m) {
if (m != NULL) {
if (*m != NULL) {
if ((*m)->ptr != NULL) {
for (int i = 0; i < (*m)->height; i++) {
free(*((*m)->ptr + i));
}
free((*m)->ptr);
free(*m);
}
}
}
}
我无法更改 destroy 函数的声明,因此结构上必须有双指针。
这是不必要的复杂和低效的。看看
您可以像这样更改结构:
struct image_t {
char type[3];
int* ptr; // placeholder pointer
int width;
int height;
};
然后像这样 malloc:
struct image_t* s = malloc(sizeof *s);
s->width = width;
s->height = height;
s->ptr = malloc( sizeof(int[width][height]) );
(记得检查每个 malloc 的结果,如果 returns NULL 则停止程序。)
然后像这样使用它:
int (*arr)[s->height] = (void*) s->ptr; // convert to a temporary 2D array pointer
...
arr[i][j] = whatever; // this enables 2D array access syntax
然后像这样释放它:
free(s->ptr);
free(s);
首先...
不要强制转换
返回的值malloc
不要使用
*(ptr + i)
使用等效但更易读的版本,即ptr[i]
这样做会将您的分配更改为:
struct image_t *struktura = malloc(sizeof(struct image_t));
int **ptr = malloc(struktura->height * sizeof(int*));
for (i = 0; i < struktura->height; i++) {
ptr[i] = malloc(struktura->width * sizeof(int));
if (ptr[i] == NULL) {
break;
}
}
这是第一个问题...您永远不会将 ptr
分配给任何东西。在代码块的末尾你需要添加:
struktura->ptr = ptr;
另一个问题是struktura->height
和struktura->width
在使用时都没有初始化。它们必须在使用前被赋值。
释放分配的内存:您当前的代码太复杂了。像 free(*((*m)->ptr + i));
这样的语句包含 3 个指针取消引用!!那很难读。我会建议您使用一些局部变量来简化代码。
void destroy_image(struct image_t **m) {
if (m == NULL) return;
if (*m == NULL) return;
struct image_t *t = *m;
int **ptr = t->ptr;
if (ptr != NULL)
{
for (int i = 0; i < t->height; i++)
{
free(ptr[i]);
}
free(ptr);
}
free(t);
*m = NULL; // The only reason to pass a double pointer to this
// function is to be able to change *m. I guess
// the prototype authoe wants the function to set
// *m to NULL
}
通过使用这些局部变量,代码比 free(*((*m)->ptr + i));
而对于分配码中的break
...
有点奇怪(错误?),您在前两个 malloc
之后不检查 NULL 然后在循环中执行。此外,使用 break
有点奇怪,因为它会使其余指针未初始化。
无论如何 - 如果你真的想要在分配代码中 break
,你还需要在释放内存时考虑到这一点。类似于:
void destroy_image(struct image_t **m) {
if (m == NULL) return;
if (*m == NULL) return;
struct image_t *t = *m;
int **ptr = t->ptr;
if (ptr != NULL)
{
for (int i = 0; i < t->height && ptr[i] != NULL; i++)
{
free(ptr[i]);
}
free(ptr);
}
free(t);
*m = NULL;
}
为了使您的销毁函数正常工作,指针数组中的所有指针都必须有效或为空。由 malloc()
编辑的内存 return 未初始化,因此在分配函数中退出循环会使指针数组的其余部分未初始化,因此不应传递给 free()
.
另请注意,您应该测试结构指针和指针数组的分配失败。此外,新分配的结构的 width
和 height
成员未初始化:您应该使用函数参数来初始化它们。
destroy_image
函数可能应该在释放后将 *m
设置为 NULL
,并且必须 free(*m);
即使 (*m)->ptr
是一个空指针。
以下是此问题的解决方案:
- 使用
calloc()
(在所有情况下都是一个好主意)或 分配数组
- 设置
height
为分配成功的指针数 - 显式设置数组中剩余的指针为
NULL
- 分配失败时释放分配的块并且return
NULL
。
这是修改后的版本:
#include <stdlib.h>
struct image_t {
char type[3];
int **ptr;
int width;
int height;
};
struct image_t *allocate_image(int width, int height) {
struct image_t *struktura = calloc(1, sizeof(*struktura));
if (struktura == NULL)
return NULL;
// should initialize struktura->type too
struktura->width = width;
struktura->height = height
struktura->ptr = calloc(height, sizeof(*struktura->ptr));
if (struktura->ptr == NULL) {
free(struktura);
return NULL;
}
for (int i = 0; i < height; i++) {
struktura->ptr[i] = calloc(sizeof(*struktura->ptr[i]), width);
if (struktura->ptr[i] == NULL) {
// Iterate downwards on index values of allocated rows
// (i --> 0) is parsed as (i-- > 0)
// this test works on signed and unsigned index types, unlike (--i >= 0)
while (i --> 0) {
free(struktura->ptr[i]);
}
free(struktura->ptr);
free(struktura);
return NULL;
}
}
return struktura;
}
void destroy_image(struct image_t **m) {
if (m != NULL) {
struct image_t *p = *m;
if (p != NULL) {
if (p->ptr != NULL) {
for (int i = 0; i < p->height; i++) {
free(p->ptr[i]);
}
free(p->ptr);
}
free(p);
*m = NULL;
}
}
}