Существуют две основные проблемы с вашим измененным кодом. Первый в функции mypop
:
void
mypop(void** val) {
puts(collection->items[collection->len]);
*val = collection->items[collection->len--];
}
Когда функция введена, в массиве collection->items
всего collection->len
, а индекс последнего равен collection->len - 1
. Таким образом, collection->items[collection->len]
читает элемент массива, в который еще не записано, и выделенная память имеет неопределенных значений до того, как оно будет записано. Поэтому, когда вы вызываете puts
для этого значения, вы разыменовываете неверный указатель. Это вызывает неопределенное поведение . На вашей машине он печатает «(ноль)», но на моей он вылетает.
Это можно исправить, уменьшив сначала len
:
void
mypop(void** val) {
collection->len--;
puts(collection->items[collection->len]);
*val = collection->items[collection->len];
}
Вторая проблема заключается в том, как вы сохраняете извлеченные значения:
char str1;
mypop((void*)&str1);
puts("Popped bar");
puts(&str1);
char str2;
mypop((void*)&str2);
puts("Popped foo");
puts(&str2);
Функция mypop
ожидает void **
, то есть адрес void *
, но вы передаете адрес char
. Когда mypop
затем присваивает *val
, он пытается записать sizeof(void *)
байтов (скорее всего, 4 или 8 байтов), чтобы присвоить значение, но str1
и str2
имеют размер sizeof(char) == 1
байт. , Таким образом, это означает, что *val = ...
записывает прошлое str1
и str2
в смежную память, которая ему не принадлежит. Это снова вызывает неопределенное поведение.
Поскольку char *
- это то, что хранилось в вашем стеке, это должен быть адрес char *
, который вы передаете mypop
. Так что str1
и str2
указатели на char
:
char *str1;
mypop((void**)&str1);
puts("Popped bar");
puts(str1);
char *str2;
mypop((void**)&str2);
puts("Popped foo");
puts(str2);
Это позволит правильно запустить вашу программу.
Кроме того, вы не освободили выделенную память, поэтому обязательно наберите free(collection)
в конце вашей программы.
Вы также должны использовать #include
вместо #import
для включения заголовочных файлов, так как первый стандартизирован, а последний является расширением.
Относительно вашего malloc:
collection = malloc( sizeof *collection + (sizeof collection->items[0] * 1000) );
Это хорошо. Размер структуры с гибким членом массива не включает размер этого члена. Поэтому, когда пространство для такой структуры выделено, вам нужен размер структуры плюс размер для некоторого числа элементов массива. Это именно то, что вы сделали: выделенное пространство для структуры с гибким элементом массива, способным содержать 1000 элементов.