Итак, изучая указатели в C, я подумал, что в качестве упражнения я мог бы сделать какой-то общий массив, и я заставил его работать при использовании void **, например так:
struct array{
void **data;
size_t size, capacity;
};
вставка таких элементов:
void array_append(array *a, void *element){
if(a->size == a->capacity){
a->capacity += ARRAY_GROW_CONSTANT;
a->data = realloc(a->data, sizeof(void*)*a->capacity);
}
a->data[a->size++] = element;
}
Но это не очень хорошо. Массив хранит указатели на элементы, поэтому, когда область действия элемента заканчивается, он становится недействительным, а также заставляет содержимое массива разбрасываться по всей памяти. Я думаю, что это можно решить, выделив сами элементы, поэтому вместо этого
a->data[a->size++] = element;
я бы сделал что-то вроде
a->data[a->size] = malloc(inserted_element_size);
memcpy(a->data[a->size], &element, inserted_element_size);
size++;
но я думал, что смогу получить ту же функциональность при использовании простого void* вместо void**
struct array{
void *start;
size_t element_size, size;
};
и вставка таких элементов, как
void array_append(array *a, void *element){
a->size += 1;
a->data = realloc(a->data, (a->size*a->element_size));
memcpy(a->data + (a->size - 1)*a->element_size, &element, a->element_size);
}
но это приводит к segfault, и я не знаю, почему. Насколько я понимаю (очевидно, нет), указатели - это адреса в памяти, поэтому, если у меня есть непрерывный блок памяти, я могу хранить в нем переменную любого типа со смещением.
Редактировать: Спасибо за объяснение, это действительно помогло.
Чем инициализируется a->data?
Я использовал функцию для инициализации массива, и a->data
был инициализирован до element_size.
вызывающий должен будет преобразовать результат в элемент *
Я думал, что могу использовать макрос, чтобы сделать ввод короче (я думаю, это плохо?), но я не знаю о производительности приведения типов от void*
до struct*
.
Создание динамического массива элементов напрямую кажется мне более практичным.
Но это не позволит мне использовать массив как универсальный? Я хотел определить общий массив, который я мог бы использовать для хранения любого типа, например
array *a1 = create_array(sizeof(int)); // array of int
array *a2 = create_array(sizeof(double)); // array of double
etc...
почему вы хотите, чтобы ваши данные хранились в непрерывном блоке?
Потому что я думал, что вам нужен непрерывный блок памяти, чтобы использовать memcpy со смещением.