4
votes

I'm implementing a simple priority queue in C for a kernel and so I can't use any standard libraries. The queue holds a head node and each node points to the next in the queue.

typedef struct node node;
struct node {
    node *next;
    void *data;
};

typedef struct  {
    node *head;
    int n;
} queue;

As you can see, each node holds it data in a void*. I'm having trouble converting this data to lets say an int when I pop the data off the stack.

//push data
int int_data = 100;
push(q, &int_data);
//...
//pop data
node* popped = pop(q);
int *pop_data = popped->data;
printf("pop data (100): %d\n", *pop_data);

Why can't I get the original value here? I seem to be printing a pointer value. Alternatively, is there a better way to handle this?

== edit (sorry should have included these):

void push(queue *q, void *data)
{
    node new;
    new.data = data;
    node *new_ptr = &new;

    if(is_empty(q))
    {
        q->head = new_ptr;
        q->n++;
        return;
    }

    int i;
    node *curr = q->head;
    for(i=0; i<q->n; i++)
    {
        curr = curr->next;
    }
    curr->next = new_ptr;
    q->n++;
}

node* pop(queue *q)
{
    node *curr = q->head;
    q->head = curr->next;
    return curr;
}
4
From what you've provided I don't think we have enough information to answer your question; provided that you set everything up correctly, this should work just fine. What is the program actually printing? Can you provide some more context for how these functions work? - templatetypedef
does it work if you just say printf("...", popped->data); - Scott M.
You are storing the address of a local variable, once it gets popped off the stack your void* data will be pointing to garbage memory. - Marlon

4 Answers

4
votes

Is your code all in one function? If not, int int_data is getting popped off the stack (not your queue, the actual stack) which is probably why you are printing garbage; you are storing the address of a local variable.

I would suggest changing void* data to int data. (If you need to, you can store an address in an int and can cast it back to a pointer later.)

int int_data = 100;
push(q, int_data);

node* n = pop(q);
int num = n->data;

After reviewing your code again, you have the same problem when adding a new node. node new falls out of scope at the end of the function, so basically all of your nodes in your queue are pointing to invalid memory.

3
votes

If the "pop" operation is in a different function:

The problem is likely because you're pushing a local variable into your queue.

When you go to pop, this address is no longer valid (or at least not pointing to an int value), so you're printing something strange. As the data is no longer pointing to your int, it probably looks like a memory address.

1
votes

You can use the glib GPOINTER_TO_INT macro:

#define GPOINTER_TO_INT(p) ((gint)  (glong) (p))

But please, take note with the doc note:

YOU MAY NOT STORE POINTERS IN INTEGERS. THIS IS NOT PORTABLE IN ANY WAY SHAPE OR FORM. These macros ONLY allow storing integers in pointers, and only preserve 32 bits of the integer; values outside the range of a 32-bit integer will be mangled.

0
votes

are you setting data = int_data (i.e. int --> void*) or data = &int_data (i.e. int* --> void *) ? In the former case, you have to write printf("pop data (100): %d\n", pop_data);