[英]How to properly free a dynamically allocated array in C
我正在尝试编写一组函数来支持动态分配的数组,其中结构包含数组和其他元数据。 目标是将函数返回给用户,并且可以从函数中调用结构信息。 代码似乎工作得很好,直到我得到从堆中释放内存的函数。 由于我不明白的原因,代码因分段错误而失败,这表明free_vector
函数中的变量vec
未指向正确的地址。 但是,我已经使用打印语句验证它指向正确的地址。 我希望有人可以帮助我理解为什么free_vector
函数不起作用,特别是free
命令。 我的代码和实现如下所示。
typedef struct
{
size_t allocated_length;
size_t active_length;
size_t num_bytes;
char *vector;
} Vector;
void *init_vector(size_t num_indices, size_t num_bytes) {
// Allocate memory for Vector struct
Vector *vec = malloc(sizeof(*vec));
vec->active_length = 0;
vec->num_bytes = num_bytes;
// Allocate heap memory for vector
void *ptr = malloc(num_bytes * num_indices);
if (ptr == NULL) {
printf("WARNING: Unable to allocate memory, exiting!\n");
return &vec->vector;
}
vec->allocated_length = num_indices;
vec->vector = ptr;
return &vec->vector;
}
// --------------------------------------------------------------------------------
int push_vector(void *vec, void *elements, size_t num_indices) {
Vector *a = get_vector_data(vec);
if(a->active_length + num_indices > a->allocated_length) {
printf("TRUE\n");
size_t size = (a->allocated_length + num_indices) * 2;
void *ptr = realloc(a->vector, size * a->num_bytes);
if (ptr == NULL) {
printf("WARNING: Unable to allocate memory, exiting!\n");
return 0;
}
a->vector = ptr;
a->allocated_length = size;
}
memcpy((char *)vec + a->active_length * a->num_bytes, elements,
num_indices * a->num_bytes);
a->active_length += num_indices;
return 1;
}
// --------------------------------------------------------------------------------
Vector *get_vector_data(void *vec) {
// - The Vector struct has three size_t variables that proceed the vector
// variable. These variables consume 24 bytes of daya. THe code below
// points backwards in memory by 24 bytes to the beginning of the Struct.
char *a = (char *)vec - 24;
return (Vector *)a;
}
// --------------------------------------------------------------------------------
void free_vector(void *vec) {
// Free all Vector struct elements
Vector *a = get_vector_data(vec);
// - This print statement shows that the variable is pointing to the
// correct data.
printf("%d\n" ((int *)vec)[2]);
// The function fails on the next line and I do not know why
free(a->vector);
a->vector = NULL;
a->allocated_length = 0;
a->active_length = 0;
a->num_bytes = 0;
}
int main() {
int *a = init_vector(3, sizeof(int));
int b[3] = {1, 2, 3};
push_vector(a, b, 3);
// The code begins to fails here
free_vector(a);
}
该程序存在未定义行为。
init_vector
的返回值是char **
类型,一个指针到指针到字符,
return &vec->vector;
转换为void *
。
在main
中,此值转换为int *
int *a = init_vector(3, sizeof(int));
然后,当传递给push_vector
时,此值会转换回void *
。
在push_vector
中,该值被强制转换为char *
以执行指针运算
memcpy((char *)vec + a->active_length * a->num_bytes, elements,
num_indices * a->num_bytes);
此操作会覆盖vector
成员中包含的malloc
返回的原始指针。
在我的系统上,这会尝试从Vector
结构中vector
成员的位置开始将 12 个字节(三个int
)写入内存。
Vector *vec
| &vec->vector
| |
v v
+------+------+------+------+-----+
|size_t|size_t|size_t|char *|?????|
+------+------+------+------+-----+
这会溢出,因为我的系统上的sizeof (char *)
是8
。
这是写入数据的错误位置。 写入数据的正确位置是*(char **) vec
- 或者只是a->vector
。
如果写入没有直接使程序崩溃( UB ),这肯定会导致free
被传递一个不是由malloc
、 calloc
或realloc
返回的指针值,或者指针值NULL
。
另外:在free_vector
中,这个值也被转换为一个int *
printf("%d\n", ((int *)vec)[2]); /* added a missing semi-colon. */
此外,还不清楚free_vector
是应该释放原始分配,还是只释放vector
成员。 您确实竭尽全力将此处的结构归零。
尽管如此,您仍然存在内存泄漏 - 尽管很小。
void free_vector(void *vec) {
Vector *a = get_vector_data(vec);
/* ... */
free(a); /* This has to happen at some point. */
}
请注意,您应该使用offsetof
来计算结构中成员的位置。 24
的静态偏移量假设有两件事可能不成立:
sizeof (size_t)
始终为8
(实际最小sizeof (size_t)
为2
),并且 您在评论中链接的源使用灵活的数组成员,而不是指针成员,这意味着整个数据(分配大小和向量)都存储在连续的内存中。 这就是&
运算符在此实现中产生将数据复制到的有效位置的原因。
(除此之外:链接的实现似乎被破坏了,因为它有效地使用sizeof
从指向灵活数组成员的指针(例如, &((vector_container *) pointer_to_flexible_member)[-1]
)中获取容器结构的基础,这不会考虑到尾随填充的可能性,这将导致比预期更大的偏移量。 )
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.