В дни, предшествующие C++ и vector/lists, как они расширяли размер массивов, когда им нужно было хранить больше данных?Как копировать вектор в c?
ответ
Типичный код C выглядит следующим образом:
void* newMem = realloc(oldMem, newSize);
if(!newMem)
{
// handle error
}
oldMem = newMem;
Обратите внимание, что если перераспределить терпит неудачу, то возвращается ноль, но старая память остается в силе, это типичное использование вызывает утечку памяти:
oldMem = realloc(oldMem, newSize);
if(!oldMem)
{
// handle error
}
К сожалению это очень распространено;
Также обратите внимание, что в C++ vector/list нет ничего особенного. Подобные структуры могут быть реализованы в C, только синтаксис (и обработка ошибок) выглядят по-разному. Например, см. LodePNG's аналог std :: vector для C.
Многие проекты C в конечном итоге реализуют векторный API. Динамические массивы - такая общая потребность, что приятно абстрагировать управление памятью как можно больше. Типичная реализация C может выглядеть примерно так:
typedef struct dynamic_array_struct
{
int* data;
size_t capacity; /* total capacity */
size_t size; /* number of elements in vector */
} 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 */
}
Тогда, конечно, вам нужна функция для push_back
, insert
, resize
, и т. д., который будет звонить realloc
, если size
превышает capacity
.
vector_resize(vector* v, size_t new_size);
vector_push_back(vector* v, int element);
Обычно, когда перераспределение необходимо, capacity
удваивается, чтобы избежать перераспределить все время. Обычно это одна и та же стратегия, используемая внутренне: std::vector
, за исключением, как правило, std::vector
не будет звонить realloc
из-за конструкции/уничтожения объекта C++. Скорее, std::vector
может выделить новый буфер, а затем скопировать конструкцию/перемещение объектов (используя размещение new
) в новый буфер.
Фактическая реализация вектора в C может использовать void*
указатели в качестве элементов, а не int
, поэтому код более общий. Во всяком случае, такого рода вещи реализуются во многих проектах C. См. http://codingrecipes.com/implementation-of-a-vector-data-structure-in-c для примера реализации вектора в C.
Здесь вы, похоже, создаете указатель для переменной данных своей структуры, но для многих других векторных реализаций в сети. Я видел, что переменная данных структуры была сохранена двойным указателем. В чем разница между этими двумя способами? – Kai
Ссылка не работает, см. Https://gist.github.com/EmilHernvall/953968/0fef1b1f826a8c3d8cfb74b2915f17d2944ec1d0 за то, что кажется популярной реализацией –
Они начнут с сокрытия определения структуры, которая будет содержать элементы, необходимые для реализации. Затем предоставляем группу функций, которые будут манипулировать содержимым структуры.
Что-то вроде этого:
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);
}
В дополнение к этому они достигли бы инкапсуляцию с использованием пустот * в месте VEC * для группы функций, а на самом деле скрыть определение структуры от пользователя, определяя его в модуль C, содержащий группу функций, а не заголовок. Также они скроют функции, которые вы считаете приватными, оставив их вне заголовка и просто прототипируя их только в модуле C.
Написал это через 30 минут, без гарантии. –
Вы можете увидеть реализацию 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;
}
Чтобы использовать его:
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);
- 1. Копировать карту в вектор
- 2. Копировать вектор в Octave
- 3. Копировать вектор <char> в char *
- 4. Копировать элемент матрицы в вектор MATLAB
- 5. C вектор в символьном *** вектор
- 6. станд :: копировать и станд :: вектор проблема
- 7. Фильтр/копировать вектор на основе элементов в другом векторе
- 8. Копировать конструктор в C++?
- 9. Как инициализировать вектор в C++
- 10. Как разделить вектор в C++
- 11. Как реализован вектор в C++
- 12. Как изменить вектор C++?
- 13. Как удалить вектор? C++
- 14. Вектор как параметр C
- 15. Как работает вектор C++
- 16. C# Normalize (как вектор)
- 17. Доступ вектор C++ в вектор векторов, не копируя его
- 18. может вектор взять другой вектор в C++
- 19. Как оттолкнуть вектор из 3 элементов в вектор в C++?
- 20. C как копировать по значению?
- 21. Вектор множеств в C++
- 22. Итерация вектор в C++
- 23. C++ вектор в классе
- 24. C++ вектор в строку
- 25. Вектор буферов в C++
- 26. Как копировать/копировать JfreeChart?
- 27. Вектор полиморфизма в C++
- 28. вектор декларации в C++
- 29. Как копировать java-шифрование в C#
- 30. Как копировать уникальные элементы структур в C
вау круто, так, Что C++ эквивалент? например malloc = new, free = delete, realloc =? – Kaije
@user: Ваши эквиваленты ошибочны. Это: malloc = vector :: vector, free = vector :: clear, realloc = vector :: resize. – ybungalobill
@ybungalobill, um ... 'vector :: clear()' на самом деле не совсем аналог «free». –