I'm trying to implement queue using linked lists. Here is my program
#include <stdio.h>
#include <stdlib.h>
struct queue_struct{
int ele;
struct queue_struct *next;
};
struct Queue{
struct queue_struct *front, *rear;
};
int isEmpty(struct Queue *q){
return (q->front==NULL||q->rear==NULL);
}
void enqueue(struct Queue *q, int x){
struct queue_struct *temp=(struct queue_struct *)malloc(sizeof(struct queue_struct));
temp->ele=x;
temp->next=NULL;
if(isEmpty(q)){
q->front=q->rear=temp;
return;
}
q->rear=temp;
printf("The item %d has been enqueued into the queue\n", x);
}
void dequeue(struct Queue *q){
if(isEmpty(q)){
printf("The queue is already empty. No more elements can be removed!\n");
return;
}
struct queue_struct *temp=q->front;
printf("The item %d has been dequeued from the queue\n", temp->ele);
q->front=q->front->next;
if(q->front=NULL)
q->rear=NULL;
free(temp);
}
void display(struct Queue *q){
struct queue_struct *temp=q->front;
int len;
printf("The contents of the queue are:\n");
if(isEmpty(q)){
printf("Nothing to be shown, the queue is empty.\n");
return;
}
while(temp!=NULL){
temp=temp->next;
len++;
}
temp=q->front;
for(int i=1;i<len-1;i++){
printf("| %d |\n", temp->ele);
printf(" ------ \n");
temp=temp->next;
}
printf("| %d |\n", temp->ele);
}
int main()
{
int choice, element;
printf("LET'S START WITH AN EMPTY QUEUE\n\n");
struct Queue *q=(struct Queue *)malloc(sizeof(struct Queue));
q->front=q->rear=NULL;
while(1){
printf("\nMENU\n");
printf("----\n");
printf("\t1. Enqueue\n");
printf("\t2. Dequeue\n");
printf("\t3. Display queue\n");
printf("\t4. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch(choice){
case 1: printf("Enter the element to be enqueued: ");
scanf("%d", &element);
enqueue(q, element);
break;
case 2: dequeue(q);
break;
case 3: display(q);
break;
case 4: printf("Program terminated successfully!\n");
return 0;
default: printf("Invalid input");
}
}
}
However, when I'm trying to enqueue an element, I'm getting a segmentation fault
Upon debugging I find that my isEmpty() function is the culprit, but I can't seem to find the problem. Considering the nature of the problem, I thought the front OR rear should be NULL for the queue to be empty. Am I wrong in my understanding? Any help is appreciated.
Edit
As suggested by @interjay, I have made changes to the q=NULL
part of the main()
method. However, my display
method is now going awry. I don't understand why.
There were some issues.
In main
, doing q = NULL;
is a memory leak and will produce a segfault. The correct way to initialize an empty queue is:
q->front = NULL;
q->rear = NULL;
The queue display uses a while
loop to find the end of the queue, thus guaranteeing that temp
will be NULL
in the subsequent for
loop (ie segfault). Only the for
loop is needed
enqueue
does not properly handle appending to a non-empty list.
dequeue
has an if statement that uses the assignment operator if (q->front = NULL)
instead of the equality operator if (q->front == NULL)
. But, even with that fix, it still doesn't handle the operation correctly.
There really isn't much use for isEmpty
function with the other functions as they can/should just check front
.
Don't cast the return value of malloc
. See: Do I cast the result of malloc? Doing the cast can introduce subtle, hard to find bugs.
Here's a refactored version that fixes the issues. I did a bit of cleanup/renaming of some of the struct
names to be a bit more descriptive of function.
In the code below, I used cpp
conditionals to show the changes (eg):
#if 0
// old code
#else
// new code
#endif
I've annotated the bugs where possible:
#include <stdio.h>
#include <stdlib.h>
typedef struct queue_element QElement;
struct queue_element {
int ele;
QElement *next;
};
typedef struct Queue {
QElement *front, *rear;
} Queue;
int
isEmpty(Queue *q)
{
return (q->front == NULL || q->rear == NULL);
}
void
enqueue(Queue *q, int x)
{
QElement *temp = malloc(sizeof(*temp));
temp->ele = x;
temp->next = NULL;
// NOTE/BUG: this does _not_ append correctly to a non-empty list
#if 0
if (isEmpty(q)) {
q->front = q->rear = temp;
return;
}
q->rear = temp;
#else
// link old rear node to new node
if (q->rear != NULL)
q->rear->next = temp;
// set new rear node
q->rear = temp;
// set the front of the list if it was empty
if (q->front == NULL)
q->front = temp;
#endif
printf("The item %d has been enqueued into the queue\n", x);
}
void
dequeue(Queue *q)
{
QElement *temp = q->front;
if (temp == NULL) {
printf("The queue is already empty. No more elements can be removed!\n");
return;
}
printf("The item %d has been dequeued from the queue\n", temp->ele);
q->front = temp->next;
if (q->rear == temp)
q->rear = NULL;
free(temp);
}
void
dequeue_OLD(Queue *q)
{
if (isEmpty(q)) {
printf("The queue is already empty. No more elements can be removed!\n");
return;
}
QElement *temp = q->front;
printf("The item %d has been dequeued from the queue\n", temp->ele);
q->front = q->front->next;
// NOTE/BUG: this if is invalid -- it is using the assignment operator in
// place of the [desired] equality operator
// NOTE/BUG: even with this fix, the dequeue is still broken -- see the fix
// above
#if 0
if (q->front = NULL)
q->rear = NULL;
#else
if (q->front == NULL)
q->rear = NULL;
#endif
free(temp);
}
void
display(Queue *q)
{
QElement *temp = q->front;
printf("The contents of the queue are:\n");
if (temp == NULL) {
printf("Nothing to be shown, the queue is empty.\n");
return;
}
// NOTE/BUG: doing the while loop ensures that temp will be NULL so that the
// for loop will try to dereference temp and it will segfault
#if 0
int len;
while (temp != NULL) {
temp = temp->next;
len++;
}
for (int i = 1; i < len - 1; i++) {
printf("| %d |\n", temp->ele);
printf(" ------ \n");
temp = temp->next;
}
printf("| %d |\n", temp->ele);
#else
int sep = 0;
for (; temp != NULL; temp = temp->next) {
if (sep)
printf(" ------ \n");
sep = 1;
printf("| %d |\n", temp->ele);
}
#endif
}
int
main(void)
{
int choice, element;
printf("LET'S START WITH AN EMPTY QUEUE\n\n");
Queue *q = malloc(sizeof(*q));
// NOTE/BUG: setting q to NULL ensures a segfault and is a memory leak
#if 0
q = NULL;
#else
q->front = NULL;
q->rear = NULL;
#endif
while (1) {
printf("\nMENU\n");
printf("----\n");
printf("\t1. Enqueue\n");
printf("\t2. Dequeue\n");
printf("\t3. Display queue\n");
printf("\t4. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("Enter the element to be enqueued: ");
scanf("%d", &element);
enqueue(q, element);
break;
case 2:
dequeue(q);
break;
case 3:
display(q);
break;
case 4:
printf("Program terminated successfully!\n");
return 0;
default:
printf("Invalid input");
break;
}
}
return 0;
}
There are the following issues:
You should not assign NULL
to q
, since that is the pointer to the memory you had just allocated, and which holds the pointers front
and rear
, which you will need always , even when the queue is empty. Instead you should set those front
and rear
pointers to NULL
:
q->front = q->rear = NULL;
In dequeue
you have an assignment inside an if
condition, where you actually want a comparison . Change this:
if(q->front=NULL)
to:
if(q->front==NULL)
In display
you are dereferencing temp
after the first loop, where you are sure that it is actually NULL
. So this is going to raise an exception. You should only have one loop. Any attempt to loop again over the list with the same temp
pointer would need the temp
pointer to be reset to the front
. Here is a simple replacement for your display
function:
void display(struct Queue *q){ struct queue_struct *temp=q->front; printf("The contents of the queue are:\n"); if(isEmpty(q)){ printf("Nothing to be shown, the queue is empty.\n"); return; } while(temp,=NULL){ printf("%d->"; temp->ele); temp=temp->next; } printf("NULL\n"); }
if you want an i
counter to be displayed as well, then just increment it in the same loop above.
With these changes your code will work.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.