I am writing a simple queue in c using a linked list that keeps track of the last element.
This is my code:
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
typedef struct node_s {
uint32_t x, y;
} node;
// very cheap linked list queue that lives as long as its scope
typedef struct queue_s {
node* node;
struct queue_s* next;
} queue;
bool isEmpty(queue** queue)
{
return !*queue;
}
node* dequeue(queue** head, queue** tail)
{
if (isEmpty(head)) {
printf("attempting to dequeue from an empty queue\n");
return NULL;
}
node* ret = (**head).node;
*head = (*head)->next;
if (isEmpty(head)) *tail = NULL;
printf("next %p\n", (void*) *head);
// no need to free anything, the queue lives as long as its scope
return ret;
}
void enqueue(queue** head, queue** tail, queue* new)
{
if (isEmpty(head)) {
// has no head -> make new head
*head = new;
*tail = new;
printf("empty\n");
} else {
// has head -> make new tail // TODO does this work?
(*tail)->next = new;
*tail = (*tail)->next;
printf("not empty\n");
}
}
int main()
{
queue* head = NULL;
queue* tail = NULL;
enqueue(&head, &tail, &(queue) {.node=&(node) {1, 1}, NULL});
printf("h %i\n", head->node->x);
printf("t %i\n", tail->node->x);
enqueue(&head, &tail, &(queue) {.node=&(node) {2, 2}, NULL});
printf("h %i\n", head->node->x);
printf("t %i\n", tail->node->x);
enqueue(&head, &tail, &(queue) {.node=&(node) {3, 3}, NULL});
printf("h %i\n", head->node->x);
printf("t %i\n", tail->node->x);
// for (int i = 1; i <= 3; ++i) {
// enqueue(&head, &tail, &(queue) {.node=&(node) {i, i}, NULL});
// printf("h %i\n", head->node->x);
// printf("t %i\n", tail->node->x);
// }
return 0;
}
Now the rolled out for loop in main() behaves correctly as the head element stays 1 while new elements are queued:
empty
h 1
t 1
not empty
h 1
t 2
not empty
h 1
t 3
...but the for loop itself gives a wrong output as the head element is always equal to the tail element:
empty
h 1
t 1
not empty
h 2
t 2
not empty
h 3
t 3
I'm a c beginner and this is driving me insane, can someone please help me?
This code:
for (int i = 1; i <= 3; ++i) {
enqueue(&head, &tail, &(queue) {.node=&(node) {i, i}, NULL});
printf("h %i\n", head->node->x);
printf("t %i\n", tail->node->x);
}
is equivalent to this:
for (int i = 1; i <= 3; ++i)
queue next = {.node=&(node) {i, i}, NULL};
enqueue(&head, &tail, &next);
printf("h %i\n", head->node->x);
printf("t %i\n", tail->node->x);
} // End of scope
The new element next
will cease to exist at the end of the scope (see comment). What you need to do to get this working in a loop is dynamic memory allocation.