如何复制C中包含指针的结构?

如何复制C中包含指针的结构?,c,C,我有一个向量类型,定义如下: typedef struct vector { void **items; unsigned int capacity; unsigned int size; } vector_st; typedef vector_st *vector_t; vector_t vector_init(unsigned int capacity) { vector_t v = (vector_t)calloc(1, sizeof(vector_st

我有一个向量类型,定义如下:

typedef struct vector {
    void **items;
    unsigned int capacity;
    unsigned int size;
} vector_st;

typedef vector_st *vector_t;
vector_t vector_init(unsigned int capacity)
{
    vector_t v = (vector_t)calloc(1, sizeof(vector_st));
    v->capacity = capacity;
    v->size = 0;
    v->items = malloc(sizeof(void *) * v->capacity);
    return v;
}

void vector_free(vector_t v)
{
    if (v) {
        free(v->items);
        v->capacity = 0;
        v->size = 0;
        free(v);
        v = NULL;
    }
}
我按如下方式分配和释放它:

typedef struct vector {
    void **items;
    unsigned int capacity;
    unsigned int size;
} vector_st;

typedef vector_st *vector_t;
vector_t vector_init(unsigned int capacity)
{
    vector_t v = (vector_t)calloc(1, sizeof(vector_st));
    v->capacity = capacity;
    v->size = 0;
    v->items = malloc(sizeof(void *) * v->capacity);
    return v;
}

void vector_free(vector_t v)
{
    if (v) {
        free(v->items);
        v->capacity = 0;
        v->size = 0;
        free(v);
        v = NULL;
    }
}
现在,重点是我想把一个向量复制到另一个向量,这意味着包括它的所有内容。因此,我尝试定义一个如下函数:

void vector_copy(vector_t to, vector_t from)
{
    memcpy(to, from, sizeof(vector_st));
}
vector_t vec = vector_init(3);
vector_add(vec, 1);
vector_add(vec, 2);
vector_add(vec, 3);

unsigned int i;
for (i = 0; i < vec->size; i++) {
    printf("%d\n", (int)vector_get(vec, i));
}

vector_t copied = vector_init(3);
vector_copy(copied, vec);
vector_free(vec);

for (i = 0; i < copied->size; i++) {
    printf("%d\n", (int)vector_get(copied, i));
}
void vector_copy(vector_t to, vector_t from, size_t element_size) {
    // NOTE: robust code would check for memory allocation failures.  This code does not.
    void **temp_items;

    to->capacity = from->capacity;
    to->size = from->size;

    // evaluates to NULL if allocation fails:
    temp_items = realloc(to->items, from->capacity * sizeof(*to->items));
    to->items = temp_items;

    for (int i = 0; i < from->size; i++) {
        to->items[i] = malloc(element_size);  // evaluates to NULL if allocation fails
        memcpy(to->items[i], from->items[i], element_size);
    }
}
但是,这似乎并不完全正确,因为当我做这样的事情时:

void vector_copy(vector_t to, vector_t from)
{
    memcpy(to, from, sizeof(vector_st));
}
vector_t vec = vector_init(3);
vector_add(vec, 1);
vector_add(vec, 2);
vector_add(vec, 3);

unsigned int i;
for (i = 0; i < vec->size; i++) {
    printf("%d\n", (int)vector_get(vec, i));
}

vector_t copied = vector_init(3);
vector_copy(copied, vec);
vector_free(vec);

for (i = 0; i < copied->size; i++) {
    printf("%d\n", (int)vector_get(copied, i));
}
void vector_copy(vector_t to, vector_t from, size_t element_size) {
    // NOTE: robust code would check for memory allocation failures.  This code does not.
    void **temp_items;

    to->capacity = from->capacity;
    to->size = from->size;

    // evaluates to NULL if allocation fails:
    temp_items = realloc(to->items, from->capacity * sizeof(*to->items));
    to->items = temp_items;

    for (int i = 0; i < from->size; i++) {
        to->items[i] = malloc(element_size);  // evaluates to NULL if allocation fails
        memcpy(to->items[i], from->items[i], element_size);
    }
}
所以,基本上我认为它只是复制了内存地址,而不是实际的内容

是的,因为在这条线上

memcpy(to, from, sizeof(vector_st));
您只需将分配给
的内存丢弃到
,这样
复制的
所持有的内存就会泄漏;在
vector\u free(vec)
复制后
现在持有一个对已释放内存的悬空引用

要将vector的内容复制到另一个,那么,复制它:

memcpy(to->items, from->items, sizeof(void *) * from->size);
(或效率较低)

int i;
for(i = 0; i < from->size; ++i) to->items[i] = from->items[i];
所以,基本上我认为它只是复制了内存地址,而不是实际的内容

是的,因为在这条线上

memcpy(to, from, sizeof(vector_st));
您只需将分配给
的任何内存丢弃到
,这样
复制的
所持有的内存就会泄漏;在
无向量(vec)
复制的
之后,现在会持有对已释放内存的悬空引用

要将vector的内容复制到另一个,那么,复制它:

memcpy(to->items, from->items, sizeof(void *) * from->size);
(或效率较低)

int i;
for(i = 0; i < from->size; ++i) to->items[i] = from->items[i];
这是错误的,因为
向量
拥有其
对象。因此,您需要在
向量_copy
中执行四项操作:

1) 释放目标向量中现有的
对象,使其不会泄漏。
2) 复制
容量
大小

3) 为目标向量分配全新的
项目

4) 将源
项目
复制到新分配的目标
项目

如果将代码> VCordRoSimult/COD>作为初始化函数,跳过第1步。但是在这种情况下,我强烈建议将名称改为

vector\u init
,这样就可以清楚地看到它创建了一个新的向量

这是错误的,因为
向量
拥有其
对象。因此,您需要在
vector\u copy
中执行四项操作:

1) 释放目标向量中现有的
对象,使其不会泄漏。
2) 复制
容量
大小

3) 为目标向量分配全新的
项目

4) 将源
项目
复制到新分配的目标
项目

如果将代码> VCordRoSimult/COD>作为初始化函数,跳过第1步。但是在这种情况下,我强烈建议将名称改为

vector\u init
,这样就可以清楚地看到它创建了一个新的向量

现在,重点是我想把一个向量复制到另一个向量,这意味着包括它的所有内容

您似乎想要执行的操作称为“深度复制”。这意味着不仅要递归地复制数据,还要复制指向数据的任何附加数据。您已经正确地判断出结构本身的
memcpy()
不会这样做;向量元素由结构中的指针指向,但它们本身位于其他位置,因此不会被复制

更糟糕的是,在复制指向的数据时存在一个基本问题:复制函数不知道指向的元素有多大。没有这些知识,就不可能复制它们。此外,如果元素本身包含指针,那么要执行真正的深度复制,您需要关于这些成员以及它们指向的对象有多大的信息。等等

因此,基本上不可能(用任何语言)编写通用的深度副本。执行深度复制需要在每个级别上提供有关您正在复制的内容的信息。然而,为了给您一点味道,如果您可以依赖于向量元素具有在调用时已知的一致大小,那么您可以复制更深一层。可能看起来像这样:

void vector_copy(vector_t to, vector_t from)
{
    memcpy(to, from, sizeof(vector_st));
}
vector_t vec = vector_init(3);
vector_add(vec, 1);
vector_add(vec, 2);
vector_add(vec, 3);

unsigned int i;
for (i = 0; i < vec->size; i++) {
    printf("%d\n", (int)vector_get(vec, i));
}

vector_t copied = vector_init(3);
vector_copy(copied, vec);
vector_free(vec);

for (i = 0; i < copied->size; i++) {
    printf("%d\n", (int)vector_get(copied, i));
}
void vector_copy(vector_t to, vector_t from, size_t element_size) {
    // NOTE: robust code would check for memory allocation failures.  This code does not.
    void **temp_items;

    to->capacity = from->capacity;
    to->size = from->size;

    // evaluates to NULL if allocation fails:
    temp_items = realloc(to->items, from->capacity * sizeof(*to->items));
    to->items = temp_items;

    for (int i = 0; i < from->size; i++) {
        to->items[i] = malloc(element_size);  // evaluates to NULL if allocation fails
        memcpy(to->items[i], from->items[i], element_size);
    }
}
void vector\u copy(vector\u t to,vector\u t from,size\u t element\u size){
//注意:健壮代码将检查内存分配失败。此代码不会。
作废**临时项目;
到->容量=从->容量;
到->大小=从->大小;
//如果分配失败,则计算为NULL:
temp_items=realloc(to->items,from->capacity*sizeof(*to->items));
至->项目=临时项目;
对于(int i=0;isize;i++){
to->items[i]=malloc(元素大小);//如果分配失败,则计算结果为NULL
memcpy(to->items[i],from->items[i],元素大小);
}
}
您可以通过使元素成为向量结构的成员来避免传递元素大小

注意,这假设向量
已经初始化,并且不需要释放指向当前在其中的单个项(如果有)的指针(即向量不拥有这些项,因此不负责管理它们的内存)

现在,重点是我想把一个向量复制到另一个向量,这意味着包括它的所有内容

您似乎想要执行的操作称为“深度复制”。这意味着不仅要递归地复制数据,还要复制指向数据的任何附加数据。您已经正确地判断出结构本身的
memcpy()
不会这样做;向量元素由结构中的指针指向,但它们本身位于其他位置,因此不会被复制

更糟糕的是,在复制指向的数据时存在一个基本问题:复制函数不知道指向的元素有多大。没有这些知识,就不可能复制它们。此外,如果元素本身包含指针,那么要执行真正的深度复制,您需要关于这些成员以及它们指向的对象有多大的信息。等等

那么基本上是