I have to implement a FIFO queue interface for a bigger project.
The queue needs to work with any type of data, so I decided to use void* pointers as value for the nodes of my queue, and to use a double linked list. Each node has a value, a prev and a next.
For better understanding, please note that front refers to the first node in the queue, and back is the last-added node.
I wrote an enqueue and a dequeue function, and also a peek_back and a peek_front function.
However, it looks like something's wrong when I run some tests within my main() function:
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
int main(){
queue_t* q = init_queue();
if(q == NULL){
printf("Error: q not initialized properly\n");
return 1;
}
//Test with a struct
struct point {
int x;
int y;
};
for(int i = 1; i <= 3; i++){
struct point p = {i,i};
struct point* p_ptr = &p;
enqueue(q, (void*) p_ptr);
printf("One node added, front value: %i, back value: %i\n", ((struct point*)peek_front(q))->x, ((struct point*)peek_back(q))->x);
}
int result;
int size;
while(q->size > 0){
result = *(int*) dequeue(q);
size = q->size;
printf("One node removed, value = %i. Size is now %i \n", result, size);
}
return 0;
}
The output is:
gcc main.c queue.c -o main.o -Wall -Werror
./main.o
One node added, front value: 1, back value: 1
One node added, front value: 2, back value: 2
One node added, front value: 3, back value: 3
One node removed, value = 3. Size is now 2
One node removed, value = 3. Size is now 1
One node removed, value = 3. Size is now 0
As you see, enqueue changes the front node of my queue, although it shouldn't, and dequeue always return the same value...
Do you have any idea where the problem might come from ? I tried to debug with gdb but I'm really struggling to spot the problem. Also, I'd be glad to hear your feedback about the general implementation of this queue... Any advice is welcome, as I am only a beginner in C ;)
Here's my queue.hheader file:
#ifndef QUEUE_H
#define QUEUE_H
typedef struct node{
struct node* next;
struct node* prev;
void* value;
} node_t;
typedef struct queue{
struct node* front;
struct node* back;
int size;
} queue_t;
queue_t* init_queue();
int enqueue(queue_t* q, void* val);
void* dequeue(queue_t* q);
int get_size(queue_t* q);
int is_empty(queue_t * q);
void* peek_front(queue_t * q);
void* peek_back(queue_t * q);
#endif
And here's my queue.c file:
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
/*
* Allocate memory and initialize a new queue with size = 0 and front = NULL
* @return: initialized queue if succes, NULL if failed malloc
*/
queue_t* init_queue(){
queue_t* newQueue = (queue_t*)malloc(sizeof(queue_t));
if(!newQueue){
printf("Malloc error in init_queue\n");
return NULL;
}
newQueue->front = NULL;
newQueue->back = NULL;
newQueue->size = 0;
return newQueue;
}
/*
* Add a new node with value @val at the end (back) of the queue @q
* @q: a valid queue (queue_t type)
* @val: the value to be added
* return 0 if success, -1 if failure
*/
int enqueue(queue_t* q, void* val){
struct node *newNode = (struct node*) malloc(sizeof(struct node));
if(!newNode) return -1;
newNode->value = val;
if(q->size == 0){
newNode->next = newNode;
newNode->prev = newNode;
q->front = newNode;
q->back = newNode;
}
else{
newNode->next = q->back;
newNode->prev = q->front;
q->back->prev = newNode;
q->front->next = newNode;
q->back = newNode;
}
q->size ++;
return 0;
}
/*
* Remove front node of queue @q and return its value
* @q: a valid queue
* @return: value of removed front node (int) if success
* NULL if empty queue
*/
void* dequeue(queue_t* q){
if(q->size == 0){
printf("Warning: empty queue\n");
return NULL;
}
void* tbr = q->front->value; //to be returned
if(q->size == 1){
free(q->front);
q->front = NULL;
}else{
struct node * old_front = q->front;
old_front->prev->next = q->back;
q->back->prev = old_front->prev;
q->front = old_front->prev;
}
q->size--;
return tbr;
}
/*
* @q: a valid queue
* @return: size of queue @q if q is not NULL
* -1 if q is NULL
*/
int get_size(queue_t* q){
if(q != NULL){
return q->size;
}else{
return -1;
}
}
/*
* Check wether @q is empty or not
* @q: a valid queue
* @return: 1 if @q is empty, 0 otherwise
*/
int is_empty(queue_t * q){
return get_size(q) == 0;
}
/*
* Peek the value of front node of queue @q, but doesn't remove it
* @q: a valid queue
* @return: value of front node
*/
void* peek_front(queue_t * q){
if (q->size == 0){
printf("Peeking an empty queue\n");
return NULL;
}else{
return q->front->value;
}
}
/*
* Peek the value of last node (last added, back of the tail)
* from queue @q, but doesn't remove it
* @q: a valid queue
* @return: value of last-added node (back)
*/
void* peek_back(queue_t * q){
if (q->size == 0){
printf("Peeking an empty queue\n");
return NULL;
}else{
return q->back->value;
}
}