Как поместить элементы в стек, используя массив void* в качестве структуры данных?

В последнее время я пишу код на C для универсального стека, используя массив указателей void. После выполнения некоторых тестов все было в порядке, до последнего теста:

while(i < 9) {
    push_pila(mi_pila,(int*)&i);
    i++;
}

Как видите, я передаю i в качестве аргумента функции push_pila. Это код функции push_pila в стеке:

typedef struct {
        void **vec;
        int tope;
        int16_t max_elementos;
    }PILA;

int push_pila(PILA *mi_pila,void *val) {
    if(pila_llena(mi_pila)) {
        return -1;
    }
    else {
        mi_pila->tope = mi_pila->tope + 1;
        mi_pila->vec[mi_pila->tope] = val;
        return 0;
    }
}

Вот где проблема, потому что мой стек представляет собой массив void*, содержащий значения адреса val. Когда я передаю значение i, я передаю его адрес. Проблема в этом случае заключается в том, что все значения внутри стека будут содержать один и тот же адрес, поэтому все значения в стеке будут одинаковыми, поэтому, когда я выталкиваю стек с помощью функции pop, я возвращаю то же самое значение, которое является последним значение i, в моем случае 9.

Есть ли решение этой проблемы? Или просто это не лучший способ вставлять элементы в массив?


person mayhem    schedule 03.07.2012    source источник


Ответы (2)


Если вы хотите передать значения памяти, вам нужно сделать так, чтобы каждая запись имела отдельное значение памяти, а не увеличивать один и тот же адрес снова и снова и передавать один и тот же адрес. Вам нужно выделить память из кучи с помощью malloc, установить для этой памяти любое целочисленное значение, которое вы хотите (в данном случае 1-9), а затем поместить этот указатель в стек.

Что-то вроде этого:

while(i < 9) {
    int* int_ptr = (int*) malloc(sizeof(int));
    *int_ptr = i;
    push_pila(mi_pila, int_ptr);
    i++;
}

Позже, когда вы закончите со стеком, вам нужно будет извлечь каждый указатель и free его.

person Nick    schedule 03.07.2012
comment
В C это ненужное усложнение для приведения результата malloc. Указатели Void можно назначать для lvals любого типа указателя. - person Gene; 03.07.2012
comment
@Nick Могу ли я сделать это внутри функции push_pila? Возможно, я могу определить void* tmp как глобальный внутри файла заголовка, и каждый раз, когда я вызываю функцию push_pila, я делаю то, что вы предлагаете. - person mayhem; 03.07.2012
comment
Вам нужно знать размер данных, на которые указывает *val, чтобы выделить память и скопировать ее внутри push_pila(). Вы можете передать указатель функции процедуры копирования в push_pila(), чтобы при необходимости можно было выполнить глубокую копию. - person SpacedMonkey; 03.07.2012
comment
@SpacedMonkey Я понимаю часть о наличии указателя функции на процедуру копирования, но почему вы думаете, что лучше всего передать его в push_pila()? Не лучше ли иметь указатель функции внутри структуры и делать что-то вроде my_struct.cpy_func? - person mayhem; 03.07.2012
comment
@Mayhem, но тогда push_pila() нужно будет знать о содержимом структуры, и каждая структура будет немного больше. Кроме того, вы можете не захотеть делать копию при копировании из одной структуры в другую, поэтому возможность указать функцию копирования более гибкая. Это также будет верно для удаления/освобождения структуры. - person SpacedMonkey; 03.07.2012
comment
@SpacedMonkey, я понимаю твою точку зрения. Итак, в основном вы говорите, что пользователь АТД должен сделать свою собственную реализацию того, как обрабатывать структуру данных, которую он хочет поместить в стек, и передать мне как указатель на функцию? - person mayhem; 04.07.2012
comment
Извините, я имел в виду конкретную реализацию. Вы можете передать все указатели функций, которые вам нужны, в процедуру инициализации для PILA и сохранить их в этой структуре. - person SpacedMonkey; 04.07.2012

Вы должны выделить новую память для хранения каждого целого числа:

while(i < 9) {
    int *i_boxed = safe_malloc(sizeof(int));
    *i_boxed = i; 
    push_pila(mi_pila, i_boxed); 
    i++; 
} 

Обратите внимание, что safe_malloc просто вызывает malloc и изящно обрабатывает ошибку выделения.

person Gene    schedule 03.07.2012