И така, изучавайки указатели в 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 с отместване.