A queue using structs and dynamic memory allocation - c

I am tasked with making a queue data structure in C, as a linked list. Our lecturer gave us a large amount of code to implement a stack, but we have to adapt it to create a queue. The code our lecturer gave us ends up not compiling and segfaulting at the exact same point as the code I wrote for the queue. I'm very new to structs, malloc and C in general, so there could be something painfully obvious I've overlooked.
Here is the code I am using:
#include <stdio.h>
#include <stdlib.h>
struct node{
int data; //contains the actual data
struct node *prev; //pointer to previous node (Closer to front)
struct node *next; //pointer to next node (Closer to back)
};
typedef struct node *Nodepointer;
struct queue{
Nodepointer front;
Nodepointer back;
};
typedef struct queue *Queuepointer;
main(){
Queuepointer myqueue; //create a queue called myqueue
init(myqueue); //initialise the queue
Nodepointer new = (Nodepointer)malloc(sizeof(struct node));
myqueue->front = new;
}
int init(Queuepointer q){
q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
}
The idea is that the queue struct 'contains' the first and last nodes in a queue, and when a node is created, myqueue is updated. However, I cannot even get to that part (pop and push are written but omitted for brevity). The code is segfaulting at the line
myqueue->front = new;
with the following gdb output:
Program received signal SIGSEGV, Segmentation fault.
0x08048401 in main () at queue.c:27
27 myqueue->front = new;
Any idea what I'm doing wrong?

When you call init:
int init(Queuepointer q){
q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
}
You're passing a pointer to a queue into the function, and initializing where that pointer points (in memory) within the function. By setting q = ..., you're assigning a new value to q.
Unfortunately, the calling function does not see this. You need to pass a pointer to a pointer instead:
int init(Queuepointer * qp){
Queuepointer q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
// Set qp:
*qp = q;
}
Then change the calling function:
init(&myqueue);

init(myqueue); passes by value a pointer to unallocated memory.
init does nothing on it, consequently (instead, writing random things at random location).
Then, myqueue->stuff does it again.
You should have used pointer to pointer.
Init will receive queue**, and called as init(&myqueue).
Inside, *myqueue=()malloc stuff
Also, I recommend you against these typedefs. They are rather bad style.

The first problem I see is that the "init" function writes the allocated pointer in "q", that is NOT your original "myqueue". Remember that C passes its arguments by value. A possible correction (not perfect, just a hint) is
Queuepointer init(void)
Queuepointer q;
q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
return q;
}
`
And in "main":
myqueue = init();
Also beware that in your program you don't initialize the element allocated by malloc. malloc doesn't in general clean the memory it allocates.
Regards

You are passing myqueue by value so the allocation happened at init() is for the copy of myqueue not to myqueue.
So the correct version is:
int init(Queuepointer* q){
*q = (Queuepointer)malloc(sizeof(struct queue));
*q->front = NULL;
*q->back = NULL;
}
and you can call init() from main
init(&myqueue);

int init(Queuepointer q){
q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
}
Minor nitpick, but your init function has no return value so perhaps change it to:
void init(Queuepointer *q) {
or
int init(Queuepointer * qp){
Queuepointer q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
*qp = q;
if(q) {
return 1;
} else return 0;
}
Adjust according to how you want to perform error checking.

Related

Queue based on LinkedList , cannot return null pointer when creating new Queue

I am trying to create a Queue base on LinkedList in C.
and I have an issue that when I tried to initialize the Queue and return QueueNode = NULL;
it still gives me a memory address and when a tried to check if the Queue is empty the result is always not.
if I let the Queue pointer = NULL in the main is work (the pointer is equal to null).
attach mine code.
QueueNode Header:
typedef struct node
{
queueInfo value;
struct node* next;
}QueueNode;
QueueNode* createQueue();
int isEmptyQueue(QueueNode* Q);
void insert(QueueNode** Q, queueInfo x);
void delafter(QueueNode* p, queueInfo* x);
void PrintQueue(QueueNode* Q);
QueueNode.c
#include <stdio.h>
#include <stdlib.h>
QueueNode* createQueue()
{
/*
Aim: Initiolaze new Queue;
input: nothing
outpot: returns QueueNode pointer
*/
QueueNode* Q = NULL;
Q->next = NULL;
return Q;
}
int isEmptyQueue(QueueNode* Q)
{
/*
Aim: check if the Queue is empty
input: pointer to an queue
outpot: returns 1 if the queue is empty, 0 if not
*/
if ((!Q))
{
return 1;
}
return 0;
}
main:
{
QueueNode* q = createQueue;
int res = isEmptyQueue(q);
printf("%d\n", res);
return 0;
}
pictures from debug mode
enter image description here
At least these problems:
Improper attempt to assign .next
I am trying to create a Queue base on LinkedList in C. and I have an issue that when I tried to initialize the Queue and return QueueNode = NULL;
Assigning NULL to Q is OK, yet Q->next = NULL; is undefined behavior (UB) as Q does not point too valid memory. Simply do not attempt Q->next = NULL since it is not needed.
QueueNode* Q = NULL;
// Q->next = NULL;
return Q;
Warnings not all enabled
QueueNode* q = createQueue; attempts to assign the address of a function to a QueueNode pointer. Instead, call the function. A well warning enabled compiler would warn about this.
// QueueNode* q = createQueue;
QueueNode* q = createQueue();

Circular Queue using Linked List

I want to create a circular queue using linked list,also i want to create instance of that data structure(queue) not just one queue, many queues without repeating the code. this is what i came up with...
#include <stdio.h>
#include <stdlib.h>
struct queue
{
int info;
struct queue *next;
struct queue *front;
struct queue *rear;
};
void create(struct queue **q)
{
(*q)->next = 0;
(*q)->front = 0;
(*q)->rear = 0;
}
struct queue* makenode(int item){
struct queue* p = (struct queue*)malloc(sizeof (struct queue));
if (p) p->info = item;
return p;
}
void addLast(struct queue **q, int item){
struct queue* p = makenode(item);
if ((*q)->front == NULL){
(*q)->front = (*q)->rear = p;
(*q)->front->next = (*q)->front;
(*q)->rear->next = (*q)->rear;
}
else
{
(*q)->rear->next = p;
p->next = (*q)->front;
(*q)->rear = p;
}
}
int delFirst(struct queue **q){
struct queue *p = (*q)->front;
if ((*q)->front == 0)
printf("\nEmpty Queue\n");
else
{
int temp = (*q)->front->info;
if (((*q)->front->next) != ((*q)->front))
{
(*q)->front = (*q)->front->next;
(*q)->rear->next = (*q)->front;
}
else
{
(*q)->front = 0;
}
return temp;
}
free(p);
}
void main()
{
struct queue *premium, *normal;
create(&premium);
create(&normal);
addLast(&premium, 5);
addLast(&premium, 10);
addLast(&normal, 20);
addLast(&normal, 30);
printf("%i\n", delFirst(&premium));
printf("%i\n", delFirst(&premium));
delFirst(&premium);
printf("%i\n", delFirst(&normal));
printf("%i\n", delFirst(&normal));
delFirst(&normal);
getch();
}
Is there any good way to do this? I kinda feel my code is complicated. I am new to C programming and I only learned basics about queues and linked list.so i don't know even my code is 100% right or an elegant code. I compiled this code using DevC++ works fine, but when I compile it using MS Visual Studio 2013, it gave me an exception "Access violation writing location....”. so i am very sure my code is not that good. Please help me out. Thanks
Problem 1: data structure
You have one structure that contains both the linked list item (info and next element) and the queue structure (front and rear, which should be the same for all elements.
I'd suggest to use:
struct queue_item
{
int info;
struct queue_item *next;
};
struct queue
{
struct queue_item *front;
struct queue_item *rear;
};
Problem 2: queue creation
When you call create(), the pointer which address you pass (for example premium) is not yet initialized. It can point anywhere ! Most certainly to an invalid location. It doesn't point to a queue yet. So when you do things like (*q)->next = 0;, you try to overwrite an illegal location.
With the data structure proposed above, I propose the following :
struct queue* create (struct queue *q) /* q points to a queue already allocated, or it is NULL */
{
if (q==NULL)
q = malloc(sizeof (struct queue));
if (q) {
q->front = 0;
q->rear = 0;
}
return q;
}
In main() you'd then have the choice:
struct queue *premium, normal;
premium = create(NULL); /* allocate the queue structure */
create(&normal); /* use an allocated structure */
Problem 3: Node pointers not initialized at node creation
malloc() does not initialize the memory it returns. If you do'nt initialize the link pointer(s), these may in fact contain something else than NULL.
struct queue_item* makenode(int item){
struct queue* p = (struct queue_item*)malloc(sizeof (struct queue_item));
if (p) {
p->info = item;
p->next = NULL; /* There is no link yet, so make it clear to avoid any surprises later. */
}
return p;
}
Problem 4: Inconsistencies when adding/deleting items
With the new data structure, you'll have to adapt your addLast() and delFirst(). But it'll be clearer, because front and rear are at the level of the queue, and next is only at the level of the item.
From the signature, it'll be posible to avoid double indirection because the pointer to the queue will never be changed by these operations:
void addLast(struct queue *q, int item);
int delFirst(struct queue *q);
Your first problem is that you invoke create() on uninitialized pointers:
void create(struct queue **q)
{
(*q)->next = 0;
…
}
int main()
{
struct queue *premium, *normal;
create(&premium);
create(&normal);
Either you need to call makenode() inside the create() function or in main(), or you need to provide structures for premium and normal to point at.
Option A:
void create(struct queue **q)
{
*q = makenode(0);
if (*q != 0)
{
(*q)->next = 0;
…
}
}
Option B:
int main()
{
struct queue q_premium, q_normal;
struct queue *premium = &q_premium;
struct queue *normal = &q_normal;
create(&premium);
create(&normal);
Either technique can be made to work, but Option B requires care because the structures q_premium and q_normal are not allocated (though they could be if that was necessary). However, the signature of create() suggests that Option A is what was intended because Option B really doesn't require the double pointer in create().
I'm not clear what, if any, benefit the mix of three pointers — front, rear, next — provides to your structure. I implemented a circular DLL for my own benefit, just to see what might be involved, and I only needed a data pointer and next and previous pointers. From any element in the list, you can reach every other element in the list. You can insert before or after a given node, remove a given node, apply a function to all nodes, or find the first node that matches a predicate provided by a function (and get the next node, previous node or the data), or destroy the entire list.
My impression is that your code would be simpler without one of the pointers.
With the Option A change, the code compiles and seems to work, producing:
5
10
Empty Queue
20
30
Empty Queue

C - meaning of non zero adresses in nullspace

This is a linked list queue implementation.
This is my program
int size(QueuePtr q)
{
QueuePtr temp = q->next;
int size = 0;
while(temp)
{
size++;
temp = temp->next;
}
return size;
}
where QueuePtr is defined like this
struct QueueElement
{
struct QueueElement *next;
int prio;
DataPtr data;
};
typedef struct QueueElement *QueuePtr;
My program crashes when an adress is pointing to nullspace but isnt null!
Bad arg exception
temp = 0xf00000000000000 (while is not aborted since temp != 0)
temp = temp->next (this line generates the exception)
My debugger said that I'm free(----) memory that has not been malloced. But that didnt help me much -
What does this adress mean? Can I simply change my while(something) statement?
If you don't initialize the next pointers to 0 then they can contain anything including non-valid pointers.
In a Debug build uninitialized memory usually has a recognizable pattern like 0xfeeefeee or 0xdeadbeef just so it can be recognized as uninitialized.
To fix this you should set the next pointer to 0 explicitly when you create a node:
QueuePtr createNode(int prio, DataPtr data){
QueuePtr node = (QueuePtr)malloc(sizeof(struct QueueElement));
node->next = null;
node->prio = prio;
node-> data = data;
return node;
}

How to initialize my pointer to NULL

Learning C, I'm trying to implement a little program. I have two structs like this:
typedef struct QueueNode_ QueueNode;
typedef struct TQueue_ TQueue;
struct QueueNode_ {
QueueNode* next;
const Task task;
};
struct TQueue_ {
QueueNode* first;
QueueNode* last;
};
Next I defined a method to initialize my queue:
void initializeQueue(TQueue* queue){
queue = malloc(sizeof(TQueue)); //check if malloc returns NULL!
queue->first = NULL;
printf("%d", queue->first == NULL);
queue->last = NULL;
}
And the main:
int main() {
puts("TQueue example:");
TQueue q;
initializeQueue(&q);
printf("%d", q.first == NULL);
}
I though that the above would print 11 but it prints 10 meaning that my pointer first is not set to null. I'm pretty sure that I miss something basic...
Why the above prints 10 and how to initialize properly the pointer of first to NULL in my initializeQueue method?
Thanks!
The problem is that in C, arguments are always passed by value, unless explicitly passed as a pointer, so generally speaking you should not assign the arguments directly: it is confusing.
void initializeQueue(TQueue* queue) {
queue = malloc(sizeof(TQueue)); //check if malloc returns NULL!
See? Upon entering the function, queue points to the queue from main, but then you allocate a new struct and make queue point to it. So the queue from main is never initialized!
The solution, remove the malloc:
void initializeQueue(TQueue* queue){
queue->first = NULL;
printf("%d", queue->first == NULL);
queue->last = NULL;
}
Or if you prefer to go fully dynamic, to not take the queue as an argument but return a newly allocated one:
TQueue *initializeQueue(){
TQueue* queue = malloc(sizeof(TQueue)); //check if malloc returns NULL!
queue->first = NULL;
printf("%d", queue->first == NULL);
queue->last = NULL;
return queue;
}
And modify the main function accordingly.
This line is the fault:
queue = malloc(sizeof(TQueue)); //check if malloc returns NULL!
You have already allocated memory for the structure in the main function, so you don't need to do it again.
In fact, what the line is doing is allocating memory, assigning it to the pointer (and remember that arguments are passed by value so it overwrites the local copy) and you change only that structure in the function, not the one passed in by the call.

Freeing memory in C: Queue

void insert_queue (queue *this, queue_item_t item) {
//Inserts a new item at the end of queue.
queue_node *temp = malloc(sizeof (struct queue_node));
temp->item = item;
if (isempty_queue(this)) this->front = temp;
else this->rear->link = temp;
this->rear = temp;
//free(temp);
}
queue_item_t remove_queue (queue *this) {
assert (! isempty_queue (this));
//This removes the first item from queue.
queue_item_t temp = this->front->item;
this->front = this->front->link;
return temp;
}
I'm getting a seg fault error when I try to free 'temp'. I'm supposed to free a node after using it, right? So, how would I prevent memory leak in this situation? Any ideas?
Thanks.
When I remove free(temp), everything works fine, but I'm getting memory leaks. I'm not sure where to put free if it doesn't belong in this function. I also added my remove function. Should free go in here?
EDIT EDIT: Thank you everyone, here is my updated code.
queue_item_t remove_queue (queue *this) {
assert (! isempty_queue (this));
queue_node *temp = this->front;
queue_item_t rVal = temp->item;
//Moves on to the next one.
this->front = this->front->link;
//Free the unlinked node.
//free(temp->item); <<<<---- This causes program to fail.
free(temp);
return rVal;
}
Memory leaks are still occurring.
You are not done using the node when insert_queue finishes. The insert_queue routine uses temp to hold a pointer to the node, and insert_queue is done using temp when it returns, but the node itself is part of the linked list, so it is in use.
You finish using the node when remove_queue removes it from the list. remove_queue should pass the pointer to the node to free to release its memory.
Do not think of temp as a node. It is only an object that temporarily holds a pointer to the node. The node itself is a separate thing.
Well, if you're creating and inserting a new queue, why would you want to delete it? Remember, when you use malloc() you're reserving some data independent of the block you are in. Free() is what you use to destroy this memory created with malloc(). All locally scoped (NOT created with malloc) data/variables will automatically be destroyed at the end of they're respected blocks. Data created with malloc() will (in most cases) not.
void insert_queue (queue *this, queue_item_t item)
{
//Inserts a new item at the end of queue.
queue_node *temp = malloc(sizeof (struct queue_node));
temp->item = item;
if (isempty_queue(this))
this->front = temp;
else
this->rear->link = temp;
this->rear = temp;
//free(temp); // remember tmp is still referring to
// the node, so you will be erasing the
// node you just put inside the queue.
} // end of code block. Variable *temp will be
// automatically freed from memory, but
// its malloc'd data will not. This is good
// because its data is being used inside our
// queue, until it is removed with remove_queue().
Later on inside your remove function you could delete "temp" (its actually the memory allocated using malloc()) using free. Or you could use free(remove_queue(&myq)), and it will yield the exact same result because we are dealing with pointers.
First of all "this" is shadowning a keyword in c++. You should not use it in a c-context either if you ask me - just to avoid misunderstandings.
Second a queue is something where an item, request, person or something is queued at the end and earlier or later removed from the front when it is time (dequed). You seem to implement this as a linked list what is ok.
Next queue_item_t item is allocated on the stack here as copy from the original value, since I do not see that it is a pointer comming in the momory allocated for it will be deleted on the closing }.
I would not call a variable temp if it actually has meaning like newQueueNode. Meaningful application/class/variable/function names are one of the best ways to comment your code.
At last comment, the choosen return and pass by value without an ok parameter, or you will run into issues when you can not return a copy (see my example for size==0), and there is no way to tell the user of the function that something went wrong (queue is empty, in this case)
Here is my (quickly produced and tested) minimum solution for your problem:
#include <stdlib.h>
#include <stdio.h>
struct queue_item_t
{
int exampleItemData;
};
struct queue_node
{
struct queue_item_t *item;
struct queue_node *next;
};
struct queue
{
struct queue_node *firstItem;
struct queue_node *lastItem;
int size;
};
struct queue* createQueue()
{
struct queue *queuePtr = (struct queue *)malloc(sizeof (struct queue));
queuePtr->firstItem = NULL;
queuePtr->lastItem = NULL;
queuePtr->size = 0;
return queuePtr;
}
void queue(struct queue* queueData, struct queue_item_t itemToQueue)
{
// Create new node
struct queue_node* newNode = (struct queue_node*)malloc(sizeof(struct queue_node));
// Create new item
newNode->item = (struct queue_item_t*)malloc(sizeof(struct queue_item_t));
// Copy the item data from itemToQueue that will be deleted on the end of this function
newNode->item->exampleItemData = itemToQueue.exampleItemData;
// Insert the item into the queue
if(0 == queueData->size)
{
queueData->firstItem = newNode;
queueData->lastItem = newNode;
newNode->next = newNode;
}
else
{
queueData->lastItem->next = newNode;
queueData->lastItem = newNode;
}
queueData->size += 1;
// ! itemToQueue will deleted here we must have a copy of the data in the queue }
}
struct queue_item_t dequeue(struct queue* queueData)
{
struct queue_item_t item;
if (1 > queueData->size)
{
// !!! Serious problem if this happens:
// What will you return, an initialized queue_item_t?
// You can not return a null pointer ...
// Better you write ok to a boolean comming in ass parameter or something
}
else if(1 == queueData->size)
{
item.exampleItemData = queueData->firstItem->item->exampleItemData;
free(queueData->firstItem->item);
free(queueData->firstItem);
queueData->firstItem = NULL;
queueData->lastItem = NULL;
}
else if(2 == queueData->size)
{
item.exampleItemData = queueData->firstItem->item->exampleItemData;
struct queue_node* dequeuedNode = queueData->firstItem;
queueData->firstItem = dequeuedNode->next;
queueData->lastItem = dequeuedNode->next;
free(dequeuedNode->item);
free(dequeuedNode);
}
else if (1 < queueData->size)
{
item.exampleItemData = queueData->firstItem->item->exampleItemData;
struct queue_node* dequeuedNode = queueData->firstItem;
queueData->firstItem = dequeuedNode->next;
free(dequeuedNode->item);
free(dequeuedNode);
}
queueData->size -= 1;
return item;
}
int main() {
struct queue* myQueue = createQueue();
struct queue_item_t item;
item.exampleItemData = 665;
queue(myQueue, item);
item.exampleItemData = 666;
queue(myQueue, item);
item.exampleItemData = 667;
queue(myQueue, item);
for(int i = myQueue->size; i > 0; --i)
{
struct queue_item_t dequeuedItem = dequeue(myQueue);
printf("Dequed ITem data = %i\n", dequeuedItem.exampleItemData);
}
// Now the next shows an undefined state if someone dequeues with size 0 or smaller:
struct queue_item_t dequeuedItem = dequeue(myQueue);
printf("Dequed ITem data = %i\n", dequeuedItem.exampleItemData);
// I recommend using a boolean like mentioned above
return 0;
}

Resources