0

Lately I've been writing code in C for a generic stack using an array of void pointers. After doing some tests everything seemed to be fine, until this last test:

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

As you can see I'm passing an i as an argument into the push_pila function. This is the code for the push_pila function in the stack:

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;
    }
}

Here is where the problem is, because my stack is an array of void* containing the values of the address of val. When I pass the value of i I'm passing the address of it. The problem in this case is that all the values inside the stack will contain the same address therefore all the value in the stack will be the same, so when I pop the stack using the pop function I will return the same value which is the last value of i, in my case 9.

Is there any solution to this problem?. Or is just that this is not the best way to push elements in the array?

Armali
  • 18,255
  • 14
  • 57
  • 171
mayhem
  • 39
  • 3
  • 9

2 Answers2

1

If you want to pass in memory values, you need to make each entry have a distinct memory value, rather than incrementing the same address over and over again and passing the same address. You need to allocate memory from the heap with malloc, set that memory to whatever integer value you want (1-9 in this case), and then push that pointer onto the stack.

Something like this:

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

Later, when you're done with the stack, you will need to pop off each pointer and free it.

Nick
  • 659
  • 4
  • 8
  • 1
    In C it is an unnecessary complication to cast the result of `malloc`. Void pointers are assignable to lvals of any pointer type. – Gene Jul 03 '12 at 01:45
  • @Nick Is there anyway in wich i can do this inside the `push_pila`function?. Perhaps i can define a `void* tmp` as global inside the header file and every time i call to the `push_pila`function i do what you suggest. – mayhem Jul 03 '12 at 02:06
  • You would need to know the size of the data pointed to by *val in order to allocate memory and copy it inside push_pila(). You could pass a function pointer of a copy routine into push_pila() so you could do a deep copy if needed. – SpacedMonkey Jul 03 '12 at 02:13
  • @SpacedMonkey I understand the part about having a function pointer to a copy routine, but why do you think that the best is to pass it into `push_pila()`?, isn't better to have a function pointer inside the struct and do something like `my_struct.cpy_func`? – mayhem Jul 03 '12 at 07:36
  • @Mayhem but then push_pila() would need to know about the contents of the struct and each struct would be slightly bigger. Also, you might not want to do a copy if copying from one struct to another, so being able to specify the copy function is more flexible. This will also be true for deleting/freeing the struct. – SpacedMonkey Jul 03 '12 at 09:02
  • @SpacedMonkey i catch your point. So basically what you are saying is that the user of the ADT should make his own implementation of how to treat the data structure that he wants to put into the stack and the pass to me as a function pointer? – mayhem Jul 04 '12 at 00:38
  • Sorry, I was thinking of a specific implementation. You could pass all the function pointers you need to the initialisation routine for PILA and store them in that structure. – SpacedMonkey Jul 04 '12 at 09:46
0

You must allocate fresh storage to hold each integer:

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

Note safe_malloc just calls malloc and handles allocation failure gracefully.

Gene
  • 46,253
  • 4
  • 58
  • 96