0
votes

I'm lacking understanding of pointers here. foo1 is a pointer of type foo. In dequeue, there are a list of items of type foo that are dynamically allocated passed in by queueList. My mission is to get foo1 to point to the head of the queue, however, accessing the foo1 pointer that was passed into dequeue() with *data causes a segfault. Here is where I lack understanding. Is *data not referring to the foo1 pointer?

struct foo
{
//Properties Here
};

int main()
{
    struct foo* foo1;
    dequeue(myQueueList, (void*) foo1);
}

void dequeue(struct queue* queueList, void **data)
{
    *data = NULL; //Causes Seg fault if I do this too
    *data = queueList->head->data; //Seg fault if I do this as well
    return;
}

My queue is defined as:

struct queue
{
    node * head;
    //other stuff
};

struct node
{
    void * data;
    //other stuff
};

Edit: foo1 is not initialized in main. I want to initialize it in dequeue by setting it equal to a different struct foo* pointer that's been enqueued.

Edit2: queue holds a list of struct foo* pointers.

Edit3: Thanks to wildplasser, it's fixed with (void*)foo1 -> (void*)&foo1. But why do I have to use &foo1 and not (void*)?

1
dequeue(myQueueList, (void*) foo1); -->> dequeue(myQueueList, &foo1); Also: your *foo1 pointer is pointing nowhere; there is no foo object that it points to, and it is not NULL. - wildplasser
@wildplasser why is NULL needed for foo1 when foo1 gets initialized in dequeue? What I want is foo1 to point to another foo type in heap. Or am I thinking of this the wrong way? I want the equivalent of: struct foo* foo1 = queueList->head->data; where data is a void* type. - Tommy Saechao
is queueList->head->data a struct foo* type masquerading as a void*? - yano
In this case it would not be needed. But the dequeue routine could do things differently (such as deallocate, or not allocate at all) when not NULL. Uninitialised data is (generally) just a bad habit. Ald returning the pointer as a return value would not need any pointer to pointer at all. - wildplasser
data is an uninitialized pointer, so you can't dereference it. Duh. - user253751

1 Answers

2
votes

In this code:

struct foo* foo1;
dequeue(myQueueList, (void*) foo1);

the expression (void *)foo1 causes undefined behaviour, because you use the value of an uninitialized pointer.

The concept of what you wanted to do was to pass the address of foo1 to the function, so that the function can modify foo1. You need the & operator to find the address of things.

However the function does not know anything about a struct foo *. void ** is not a generic pointer type; it is a pointer to exactly a void * and nothing else. So to make this code work without changing the definition of dequeue, you need to make a void * variable:

void *vfoo;
dequeue(myQueueList, &vfoo);
struct foo *foo1 = vfoo;

It would be easier to use dequeue if you could change its design; in particular, have it return void *. Then you could write struct foo *foo1 = dequeue(myQueueList);.

Note: In comments it was suggested to use dequeue(myQueueList, (void **)&vfoo);, however this will cause undefined behaviour due to a strict aliasing violation. Object of type struct foo * cannot be accessed via an lvalue of type void *.