Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C Dereference void* pointer

I am new to C and for my first project I need to implement an array based queue.

I want my queue to be able to hold any kind of object so I created a QueueElement structure to hold a void pointer to an object of any type. I think all is working except I am unable to read the 'position' and 'value' fields from my QueueElement struct. I get the following error when I try to compile.

Error:

Runnable.c: In function `main':
Runnable.c:10: error: dereferencing pointer to incomplete type
Runnable.c:11: error: dereferencing pointer to incomplete type

I'm pretty sure I'm just not casting properly. Any help is appreciated.

Thanks again, Pooch

Runnable.c

   #include <stdio.h>
    #include "Queue.h"
    
    int main(void) {
            int i = 9;
            Queue q = CreateQueue();
            QueueElement e = CreateQueueElement(&i);
            Enqueue(q, e);
            QueueElement f = Dequeue(q);


            /* PROBLEM IS HERE */
            printf("position: %d", f->position);
            printf("value: %d", (int *)(f->value));
            DestroyQueue(q);
            return 0;
    }

Queue.h

#ifndef QUEUE_H
#define QUEUE_H

#include "QueueElement.h"

typedef struct QueueStruct *Queue;

Queue CreateQueue(void);

void DestroyQueue(Queue q);

void Enqueue(Queue q, QueueElement e);

QueueElement Dequeue(Queue q);

#endif

Queue.c

#include "QueueElement.h"
#include "Queue.h"

#define QUEUE_SIZE 10

struct QueueStruct {
        QueueElement contents[QUEUE_SIZE];
        int size;
};

Queue CreateQueue(void) {
        Queue q = malloc(sizeof(struct QueueStruct));
        q->size = 0;
        return q;
}

void DestroyQueue(Queue q) {
        int i;
        for(i = 0; i < q->size; i++) {
                free(q->contents[i]);
        }
        free(q);
}

void Enqueue(Queue q, QueueElement e) {
        if (q->size < QUEUE_SIZE) {
                q->contents[q->size++] = e;
        }
}

QueueElement Dequeue(Queue q) {
        if (q->size > 0) {
                return q->contents[--q->size];
        }
        return;
}

QueueElement.h

#ifndef QUEUE_ELEMENT_H
#define QUEUE_ELEMENT_H

typedef struct QueueElementStruct *QueueElement;

QueueElement CreateQueueElement(void *v);

void DestroyQueueElement(QueueElement e);

int GetPosition(QueueElement e);

#endif

QueueElement.c

#include <stdio.h>
#include "QueueElement.h"

struct QueueElementStruct {
        int position;
        void *value;
};

QueueElement CreateQueueElement(void *v) {
        QueueElement e = malloc(sizeof(struct QueueElementStruct));
        e->position = 0;
        e->value = v;
        return e;
}

void DestroyQueueElement(QueueElement e) {
        free(e);
}

int GetPosition(QueueElement e) {
        return e->position;
}
like image 798
Pooch Avatar asked Jan 30 '11 02:01

Pooch


2 Answers

The definition of QueueElementStruct has to be visible in Runnable.c to be able to access fields of it. You can put QueueElementStruct into a header that you can include in Runnable.c and QueueElement.c. Alternatively, you can use your GetPosition function and add a GetValue function and use those from Runnable.c instead of direct field access.

like image 148
Logan Capaldo Avatar answered Sep 26 '22 02:09

Logan Capaldo


You have to cast the void * back to point at the "real" type before you can dereference it. e.g., if you start with an int, you can take its address, and put it in the queue. To look at the int, you'll have to cast it back to int *. Keeping track of the real type can be (usually is) non-trivial (e.g., creating an enumeration of all types you want to be able to put in the collection and associating one of those with each item in the collection).

There's a reason that C++ (for one example) opts for only putting one type of object into any given collection.

like image 29
Jerry Coffin Avatar answered Sep 26 '22 02:09

Jerry Coffin