jdepypere
jdepypere

Reputation: 3553

C Issues with pointers and a queue

I am using a self-written queue library with the following structure:

#ifndef MYQUEUE_
#define MYQUEUE_

#ifndef SET_QUEUE_SIZE
    #define SET_QUEUE_SIZE 10
#endif

typedef struct queue Queue;

/*
**  Creates and initializes the queue and prepares it for usage
**  Return a pointer to the newly created queue
*/
Queue* QueueCreate();

/*  
**  Add an element of a generic type to the queue
*/
void Enqueue(Queue* queue, void* element);

/*
**  Delete the queue from memory; set queue to NULL
**  The queue can no longer be used unless QueueCreate is called again
*/
void QueueDestroy(Queue** queue);


/*
**  Return the number of elements in the queue
*/
int QueueSize(Queue* queue);

/*
**  Return a pointer to the top element in the queue
*/
void* QueueTop(Queue* queue);

/*
**  Remove the top element from the queue
*/
void Dequeue(Queue* queue);


#endif //MYQUEUE_

Now, I'm having issues with putting it in and receiving it out from the circular queue. The queue itself has been tested and shouldn't give any issues.

Running the code below (it's an extract of the total program) my two prints don't print the same values. Where am I pointing wrong?

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#include "libs/myqueue.h"

struct package{
    unsigned sensorId:12;
    unsigned sequence:4;
    unsigned flag:2;
    unsigned sign:1;
    unsigned value:12;
    unsigned parity:1;
};

typedef struct package packs;

struct sensor_time{
    packs myPack;
    time_t time;
};

typedef struct sensor_time Sensor_Time;

Queue* queue = NULL;

int main(void){
    queue = QueueCreate();
    if(queue == NULL){
        printf("Error creating circular buffer.\n");
        exit(EXIT_FAILURE);
    }

    Sensor_Time * myData = malloc(sizeof(Sensor_Time));
    myData->myPack.sensorId = 1;
    myData->myPack.value = 20;
    myData->time = time(NULL);
    printf("Enqueued: id: %d, value: %d, time: %lu\n", myData->myPack.sensorId, myData->myPack.value, myData->time);

    Enqueue(queue, (void *)myData);

    Sensor_Time * mySens = (Sensor_Time *)QueueTop(queue);
    printf("Data read: id: %d, value: %d time: %lu", mySens->myPack.sensorId, mySens->myPack.value, mySens->time);

    return 1;
}

What gets printed:

enter image description here

For completeness, here the queue implementation:

/*----- Include Files -----*/

#include <stdlib.h>
#include <stdio.h>

#include "myqueue.h"

/*-----   Variables   -----*/

typedef void * DATATYPE;

struct queue{
    DATATYPE elements[SET_QUEUE_SIZE];
    size_t count;
    int front;
    int rear;
};
typedef struct queue Queue;
typedef Queue *myQueue;

/*----- QueueCreate   -----*/

Queue* QueueCreate(void){
    #ifdef DEBUG
        printf("QueueCreate called.\n");
    #endif

    Queue* qu = malloc(sizeof(Queue));
    qu->count = 0;
    qu->front = 0;
    qu->rear = 0;
    return qu;
}

/*----- QueueCreate    -----*/

void Enqueue(Queue* queue, DATATYPE element){
    #ifdef DEBUG
        printf("Enqueue called,  on queue %p.", queue);
        int location = queue->rear;
    #endif

    if(queue->count == SET_QUEUE_SIZE){
        printf("Queue is full.\n");
    }else{
        queue->elements[queue->rear] = element;
        queue->count++;
        queue->rear++;
        if(queue->rear == SET_QUEUE_SIZE - 1){
            queue->rear = 0;
        }
    }

    #ifdef DEBUG
        printf(" Element added on location %d.\n", location);
    #endif
}

/*----- QueueDestroy   -----*/

void QueueDestroy(Queue** queue){
    #ifdef DEBUG
        printf("QueueDestroy called on %p\n", queue);
    #endif

    free(*queue);
    *queue = NULL;
}

/*----- QueueSize   -----*/

int QueueSize(Queue* queue){
    #ifdef DEBUG
        if(queue->count > 0){
            printf("QueueSize called. Size is %d.\n", (int)queue->count);
        }
    #endif

    return queue->count;
}

/*----- QueueTop    -----*/

void* QueueTop(Queue* queue){
    #ifdef DEBUG
        printf("QueueTop called\n");
    #endif
    if(queue->count == 0){
        return NULL;
    }else{
        return &(queue->elements[queue->front]);
    }
    return NULL;
}

/*----- Dequeue     -----*/

void Dequeue(Queue* queue){
    #ifdef DEBUG
        printf("Dequeue called on %p.", queue);
        int location = queue->front;
    #endif

    if(queue->count == 0){
        printf("Queue is empty.\n");
    }else{
        queue->front++;
        if(queue->front == SET_QUEUE_SIZE - 1){
            queue->front = 0;
        }
        queue->count--;
    }

    #ifdef DEBUG
        printf(" Removed element was on location %d.\n", location);
    #endif
}

Upvotes: 0

Views: 613

Answers (1)

interjay
interjay

Reputation: 110108

Your queue stores elements of type void*. However, QueueTop returns a pointer to the first element, which would make it of type void**. The fact that the function is declared as returning void* instead of DATATYPE* makes this confusing, but it's legal because any pointer can be converted to void*, including a double pointer.

When you add an element to the queue, you cast it from Sensor_Time * to void*. Later when calling QueueTop, you take the return value and cast it to Sensor_Time *, which is wrong, because it is actually a pointer to a pointer.

To fix, you'd need to either change QueueTop to return an element rather than a pointer to an element, or change your calling code to dereference the returned pointer.

Upvotes: 2

Related Questions