当分配给另一个变量时,C 中结构中的 malloced 数据会发生什么情况?
What happens to malloced data in a struct in C when it is assigned to another variable?
假设我有一个名为“example”的结构,它有一个名为 data 的成员,用于存储在堆上分配的数据:
typedef struct _EXAMPLE
{
signed char *data;
size_t size;
} example_t;
example_t *example_alloc(size_t size)
{
example_t *ret = malloc(sizeof *ret);
ret->size = size;
ret->data = calloc(size, sizeof *ret->data);
return ret;
}
example_t *a = example_alloc(10), b = *a;
b.data
中的值是存放在栈中还是堆中?是否指向a
中的数据?
指针只是值。
与 b.size
只是 a->size
的副本相同,b.data
是 a->data
持有的相同指针值的副本。
它指向同一个位置,无论它在哪里。
必须小心,因为 free
ing a->data
会使 b.data
无效,反之亦然,如果访问可能会导致 Undefined Behavior。
结构 b
是一个局部变量,它的所有成员都存储在本地堆栈中(请不要迂腐地评论说 C 没有指定有一个堆栈——它需要一些东西就像一个堆栈)。
因为 b.data
是 b
的成员,它存储在堆栈中。但是它指向的数据和a->data
指向的是一样的,就是函数中用calloc()
分配的堆内存
正在关注 b = *a
、a->data == b.data
。也就是说,它们都引用相同的已分配内存。这被称为“浅拷贝”。要在 C 中实现 “深度复制” 需要额外的代码。例如:
example_t* example_copy( example_t* b, const example_t* a )
{
*b = *a ; // shallow copy all members
// Allocate new block and copy content
size_t sizeof_block = b->size * sizeof(*b->data)
b->data = malloc( sizeof_block ) ;
memcpy( b->data, a->data, sizeof_block ) ;
return b ;
}
然后
example_t *a = example_alloc(10) ;
example_t b ;
example_copy( &b, a ) ;
请注意,此类代码极易发生内存泄漏。例如,如果 b
在 b.data
成为 free
之前超出范围,您将无法访问该内存。任何在没有 free
的情况下分配内存和 returns 的函数都使它成为调用者的责任,而根本没有使它必然可见或明显(您的命名约定 _alloc
是某种程度的也许缓解)。你至少也应该实现相应的功能来方便对象的clean-up。我很欣赏这是一个 off-topic 点,但 C++ 提供了一个解决方案来解决这个问题,即当对象超出范围时调用析构函数。此外,复制构造函数和赋值运算符重载可用于自动调用 deep-copy 语义。
假设我有一个名为“example”的结构,它有一个名为 data 的成员,用于存储在堆上分配的数据:
typedef struct _EXAMPLE
{
signed char *data;
size_t size;
} example_t;
example_t *example_alloc(size_t size)
{
example_t *ret = malloc(sizeof *ret);
ret->size = size;
ret->data = calloc(size, sizeof *ret->data);
return ret;
}
example_t *a = example_alloc(10), b = *a;
b.data
中的值是存放在栈中还是堆中?是否指向a
中的数据?
指针只是值。
与 b.size
只是 a->size
的副本相同,b.data
是 a->data
持有的相同指针值的副本。
它指向同一个位置,无论它在哪里。
必须小心,因为 free
ing a->data
会使 b.data
无效,反之亦然,如果访问可能会导致 Undefined Behavior。
结构 b
是一个局部变量,它的所有成员都存储在本地堆栈中(请不要迂腐地评论说 C 没有指定有一个堆栈——它需要一些东西就像一个堆栈)。
因为 b.data
是 b
的成员,它存储在堆栈中。但是它指向的数据和a->data
指向的是一样的,就是函数中用calloc()
分配的堆内存
正在关注 b = *a
、a->data == b.data
。也就是说,它们都引用相同的已分配内存。这被称为“浅拷贝”。要在 C 中实现 “深度复制” 需要额外的代码。例如:
example_t* example_copy( example_t* b, const example_t* a )
{
*b = *a ; // shallow copy all members
// Allocate new block and copy content
size_t sizeof_block = b->size * sizeof(*b->data)
b->data = malloc( sizeof_block ) ;
memcpy( b->data, a->data, sizeof_block ) ;
return b ;
}
然后
example_t *a = example_alloc(10) ;
example_t b ;
example_copy( &b, a ) ;
请注意,此类代码极易发生内存泄漏。例如,如果 b
在 b.data
成为 free
之前超出范围,您将无法访问该内存。任何在没有 free
的情况下分配内存和 returns 的函数都使它成为调用者的责任,而根本没有使它必然可见或明显(您的命名约定 _alloc
是某种程度的也许缓解)。你至少也应该实现相应的功能来方便对象的clean-up。我很欣赏这是一个 off-topic 点,但 C++ 提供了一个解决方案来解决这个问题,即当对象超出范围时调用析构函数。此外,复制构造函数和赋值运算符重载可用于自动调用 deep-copy 语义。