C语言 如何在c中复制向量?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4694401/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 07:31:51  来源:igfitidea点击:

How to replicate vector in c?

c

提问by Kaije

In the days before c++ and vector/lists, how did they expand the size of arrays when they needed to store more data?

在 C++ 和 vector/lists 之前的日子里,当他们需要存储更多数据时,他们是如何扩展数组的大小的?

采纳答案by ybungalobill

Typical C code looks like this:

典型的 C 代码如下所示:

void* newMem = realloc(oldMem, newSize);
if(!newMem)
{
    // handle error
}

oldMem = newMem;

Note that if realloc fails then it returns zero but the old memory is still valid, this typical usage causes memory leak:

请注意,如果 realloc 失败,则返回零,但旧内存仍然有效,这种典型用法会导致内存泄漏:

oldMem = realloc(oldMem, newSize);
if(!oldMem)
{
    // handle error
}

Unfortunately it is very common;

不幸的是,它很常见;

Also note that there is nothing special about C++ vector/list. Similar structures can be implemented in C, just the syntax (and error handling) look different. For example see LodePNG'sanalog of std::vector for C.

另请注意,C++ 向量/列表没有什么特别之处。类似的结构可以用 C 实现,只是语法(和错误处理)看起来不同。例如,请参阅LodePNG对 Cstd::vector模拟。

回答by Charles Salvia

A lot of C projects end up implementing a vector-like API. Dynamic arrays are such a common need, that it's nice to abstract away the memory management as much as possible. A typical C implementation might look something like:

许多 C 项目最终实现了类似向量的 API。动态数组是如此普遍的需求,因此尽可能地抽象出内存管理是很好的。典型的 C 实现可能类似于:

typedef struct dynamic_array_struct
{
  int* data;
  size_t capacity; /* total capacity */
  size_t size; /* number of elements in vector */
} vector;

Then they would have various API function calls which operate on the vector:

然后他们会有各种 API 函数调用来操作vector

int vector_init(vector* v, size_t init_capacity)
{
  v->data = malloc(init_capacity * sizeof(int));
  if (!v->data) return -1;

  v->size = 0;
  v->capacity = init_capacity;

  return 0; /* success */
}

Then of course, you need functions for push_back, insert, resize, etc, which would call reallocif sizeexceeds capacity.

那么当然,您需要用于、、 等的函数push_back,如果超过则调用。 insertresizereallocsizecapacity

vector_resize(vector* v, size_t new_size);

vector_push_back(vector* v, int element);

Usually, when a reallocation is needed, capacityis doubled to avoid reallocating all the time. This is usually the same strategy employed internally by std::vector, except typically std::vectorwon't call reallocbecause of C++ object construction/destruction. Rather, std::vectormight allocate a new buffer, and then copy construct/move construct the objects (using placement new) into the new buffer.

通常,当需要重新分配时,capacity会加倍以避免一直重新分配。这通常与 内部采用的策略相同std::vector,但通常std::vector不会realloc因为 C++ 对象构造/销毁而调用。相反,std::vector可能会分配一个新缓冲区,然后将对象(使用放置new)复制构造/移动构造到新缓冲区中。

An actual vector implementation in C might use void*pointers as elements rather than int, so the code is more generic. Anyway, this sort of thing is implemented in a lot of C projects. See http://codingrecipes.com/implementation-of-a-vector-data-structure-in-cfor an example vector implementation in C.

C 中的实际向量实现可能使用void*指针作为元素而不是int,因此代码更通用。无论如何,这种事情在很多C项目中都有实现。请参阅http://codingrecipes.com/implementation-of-a-vector-data-structure-in-c以获取 C 语言中的示例向量实现。

回答by Michael Smith

They would start by hiding the defining a structure that would hold members necessary for the implementation. Then providing a group of functions that would manipulate the contents of the structure.

他们将首先隐藏定义一个结构,该结构将包含实现所需的成员。然后提供一组函数来操作结构的内容。

Something like this:

像这样的东西:

typedef struct vec
{
    unsigned char* _mem;
    unsigned long _elems;
    unsigned long _elemsize;
    unsigned long _capelems;
    unsigned long _reserve;
};

vec* vec_new(unsigned long elemsize)
{
    vec* pvec = (vec*)malloc(sizeof(vec));
    pvec->_reserve = 10;
    pvec->_capelems = pvec->_reserve;
    pvec->_elemsize = elemsize;
    pvec->_elems = 0;
    pvec->_mem = (unsigned char*)malloc(pvec->_capelems * pvec->_elemsize);
    return pvec;
}

void vec_delete(vec* pvec)
{
    free(pvec->_mem);
    free(pvec);
}

void vec_grow(vec* pvec)
{
    unsigned char* mem = (unsigned char*)malloc((pvec->_capelems + pvec->_reserve) * pvec->_elemsize);
    memcpy(mem, pvec->_mem, pvec->_elems * pvec->_elemsize);
    free(pvec->_mem);
    pvec->_mem = mem;
    pvec->_capelems += pvec->_reserve;
}

void vec_push_back(vec* pvec, void* data, unsigned long elemsize)
{
    assert(elemsize == pvec->_elemsize);
    if (pvec->_elems == pvec->_capelems) {
        vec_grow(pvec);
    }
    memcpy(pvec->_mem + (pvec->_elems * pvec->_elemsize), (unsigned char*)data, pvec->_elemsize);
    pvec->_elems++;    
}

unsigned long vec_length(vec* pvec)
{
    return pvec->_elems;
}

void* vec_get(vec* pvec, unsigned long index)
{
    assert(index < pvec->_elems);
    return (void*)(pvec->_mem + (index * pvec->_elemsize));
}

void vec_copy_item(vec* pvec, void* dest, unsigned long index)
{
    memcpy(dest, vec_get(pvec, index), pvec->_elemsize);
}

void playwithvec()
{
    vec* pvec = vec_new(sizeof(int));

    for (int val = 0; val < 1000; val += 10) {
        vec_push_back(pvec, &val, sizeof(val));
    }

    for (unsigned long index = (int)vec_length(pvec) - 1; (int)index >= 0; index--) {
        int val;
        vec_copy_item(pvec, &val, index);
        printf("vec(%d) = %d\n", index, val);
    }

    vec_delete(pvec);
}

Further to this they would achieve encapsulation by using void* in the place of vec* for the function group, and actually hide the structure definition from the user by defining it within the C module containing the group of functions rather than the header. Also they would hide the functions that you would consider to be private, by leaving them out from the header and simply prototyping them only in the C module.

此外,他们将通过在函数组中使用 void* 代替 vec* 来实现封装,并且通过在包含函数组而不是头文件的 C 模块中定义结构定义,实际上对用户隐藏了结构定义。此外,它们会隐藏您认为是私有的函数,方法是将它们从头文件中删除并仅在 C 模块中简单地对它们进行原型设计。

回答by farcost

You can see implementation vc_vector:

你可以看到实现vc_vector

struct vc_vector {
  size_t count;
  size_t element_size;
  size_t reserved_size;
  char* data;
  vc_vector_deleter* deleter;
};

...

vc_vector* vc_vector_create_copy(const vc_vector* vector) {
  vc_vector* new_vector = vc_vector_create(vector->reserved_size / vector->count,
                                           vector->element_size,
                                           vector->deleter);
  if (unlikely(!new_vector)) {
    return new_vector;
  }

  if (memcpy(vector->data,
             new_vector->data,
             new_vector->element_size * vector->count) == NULL) {
    vc_vector_release(new_vector);
    new_vector = NULL;
    return new_vector;
  }

  new_vector->count = vector->count;
  return new_vector;
}

To use it:

要使用它:

vc_vector* v1 = vc_vector_create(0, sizeof(int), NULL);
for (int i = 0; i < 10; ++i) {
  vc_vector_push_back(v1, &i);
}

// v1 = 0 1 2 3 4 5 6 7 8 9

vc_vector* v2 = vc_vector_create_copy(v1);

// v2 = 0 1 2 3 4 5 6 7 8 9 (copy of v1)

// to get pointer to int:

const int* v2_data = vc_vector_data(v1);

回答by GPlayer

https://github.com/jakubgorny47/baku-code/tree/master/c_vector

https://github.com/jakubgorny47/baku-code/tree/master/c_vector

Here's my implementation. It's basicaly a struct containing pointer to the data, size (in elements), overall allocated space and a size of the type that's being stored in vector to allow use of void pointer.

这是我的实现。它基本上是一个包含指向数据的指针、大小(以元素为单位)、总分配空间和存储在向量中的类型大小的结构,以允许使用 void 指针。