Trying to return a string from a queue in C/free problems - c

I've been working on a lab for a CSC class for a while, and unfortunately I'm a bit rusty with C (as you'll probably notice from the code). I'm encountering two particular problems, both related to memory management.
1) In the dequeue operation, I'm attempting to return a string value from the node at the end of the queue. Since I'm also trying to use free() and kill off that node once I retrieve the data, I need to use a method like strcpy() to grab the data. The program segfaults whenever I try to use strcpy, and Valgrind claims invalid r/w.
2) dequeue also is not properly updating the stringQueue struct for reasons I cannot understand. I have similar code for stacks where the alterations persist, but I can keep running dequeue all day and it won't actually remove the end node.
The relevant code:
typedef struct node {
char data [strMax];
struct node * next;
} queueNode;
typedef struct {
queueNode * head;
queueNode * tail;
} stringQueue;
char * dequeue(stringQueue *queue) {
char * data = malloc(strMax * sizeof(char));
if(empty(*queue)) {
return "Null list!";
}
else if(!(queue->head)->next) { // One item in the queue.
data = (queue->head)->data;
//free(queue->head);
queue->head = NULL;
queue->tail = NULL;
}
else { // Multiple items in the queue.
data = (queue->tail)->data;
free(queue->tail);
queueNode * trace = queue->head;
while(trace->next) // Seek the last node in the queue.
trace = trace->next;
queue->tail = trace;
}
return data;
}

Your main problem is in lines like data = (queue->head)->data;. You can't assign array like this. you should memcpy. (strcpy is for null-terminated strings, and I guess that it's not so)
edit: you can also use strncpy, to avoid buffer-overflow.

You probably want to declare data as a char * = NULL at first. Then when you want to return it use data = asprintf("%s", (queue->tail)->data);. That will only do the string allocation and copying when needed, and only the required size. Then your calling code must take responsibility for freeing that data itself.
You currently have a char[] in your node struct in memory on the heap. Later on, you are setting a pointer to the data member of the struct, then freeing the struct in memory. You are left with a 'dangling pointer' that points to where the struct used to be. Trying to use that pointer will end in almost certain doom (or worse, unpredictable behaviour).

I see a few problems with your code...
First you do not test that your queue argument is not NULL. Then you haven't included your definition of empty() but probably testing that queue->head is NULL should tell you that the list is empty. Here you are dereferencing it prior testing it's a valid pointer, very dangerous.
Secondly, you are mallocing some data which is not used properly. When you do the affection data = (queue->head)->next; you are loosing the pointer to your allocated memory, you probably want to do a strncpy() here like strncpy(data, queue->head->data, strMax). After this you can uncomment your free(). The function calling your dequeue one will have to free() that string later when it's not used anymore.
Why not allocate your data only when you are sure that the list is not empty? If you do not want to do this, you then have to free() that unsuded malloc'ed memory.
See the code below.
queueNode* find_before_tail(stringQueue* queue)
{
queueNode* node = NULL;
if (!queue || !queue->head)
return NULL;
node = queue->head;
while (node->next != queue->tail && node->next)
node = node->next;
return node;
}
char * dequeue(stringQueue *queue) {
char *data = NULL;
queueNode* to_queue = NULL;
if(!queue || !queue->head) {
/* Nothing to dequeue here... */
return NULL;
}
data = malloc(strMax * sizeof(char));
if (!data) {
printf("Error with malloc()...\n");
return NULL;
}
/* Only one element */
if(!(queue->head)->next == queue->head) {
strncpy(data, queue->head->data, strMax);
free(queue->head);
queue->head = NULL;
queue->tail = NULL;
}
else {
strncpy(data, queue->tail->data, strMax);
to_dequeue = queue->tail;
queue->head = queue->head->next;
queue->tail = find_before_tail(queue);
if (!queue->tail)
return NULL;
queue->tail->next = NULL;
free(to_dequeue);
}
data[strMax - 1] = 0;
return data;
}
There are probably some other issues with the rest of your code, judging by this one but hopefully it gives you some basis.
EDIT WITH YOUR QUEUE CODE
Here again you are not testing the return value of malloc(). Here is a version with a non-cyclic linked list (I've also updated the dequeue() function above to work with this).
int enqueue(stringQueue *queue, char *item)
{
queueNode * newNode = NULL;
if (!queue || !item)
return EINVAL;
newNode = malloc(sizeof(queueNode));
if (!newNode) {
perror("malloc()");
return errno;
}
strncpy(newNode->data, item, strMax);
newNode->data[strMax - 1] = 0;
if (!queue->head) {
/* Element is queue and tail */
queue->tail = newNode;
}
newNode->next = queue->head;
queue->head = newNode;
return 0; /* Everything was fine */
}
I have not tested the code but it should be very similar to this. In this scenario, when you have only one element, this_element->next is NULL and not pointing to itself.

Related

Singly Linked List Implementation in C using 3 different typedefs

So, my task is to to write a full implementation of a Singly Linked List in C.
I wrote before implementations of a stack and a dynamic vector, but this time, the linked list confuses me a little because of the use of 3 different typedef.
I'll be glad to get your review and tips on my code.
I would make a test file as I always do, but I am having a hard time of writing one because of all the void * casts .
I won't add all the 14 functions, i'll add just the functions that I'm least sure of.
So we must follow the following typedefs and the given prototypes. So neither of them can be changed.
I also had to add a "dummy node" as the last node, which means there will be always a "dummy node" that will indicate that the one before it, is the "real" last node in the list. This is part of the instructions.
typedef struct slist slist_ty;
typedef struct slist_node slist_node_ty;
typedef slist_node_ty *slist_iter_ty;
This is my implementation of the structs:
They asked us to allow in theory any type of data in our nodes, that's why I wrote void *.
struct slist
{
slist_iter_ty head;
slist_iter_ty end;
};
struct slist_node
{
void *data;
slist_iter_ty next;
};
And these are the functions:
/* Creates an empty single-linked list and returns pointer to the head */
/* returns NULL on failure*/
/* Complexity: O(1) */
slist_ty *SlistCreate(void)
{
slist_ty *new_list = (slist_ty *)malloc(sizeof(slist_ty));
if (NULL == new_list)
{
fprintf(stderr, "Failed to allocate memory\n");
return(NULL);
}
new_list->head = NULL;
/* create a dummy node that will represent the end of the list */
new_list->end = (slist_node *)malloc(sizeof(slist_node));
if (NULL == new_list->end)
{
fprintf(stderr, "Failed to allocate memory\n");
free(new_list);
return(NULL);
}
new_list->end->data = NULL;
new_list->end->next = NULL;
return(new_list->head);
}
/* Deletes entire List */
/* Complexity: O(n) */
void SlistDestroy(slist_ty *slist)
{
slist_iter_ty temp = NULL;
assert(slist);
while(NULL != slist->head)
{
tmp = slist->head;
slist->head = temp;
free(temp);
}
free(slist->end);
slist->end = NULL;
free(slist);
slist = NULL;
}
/* Insters the element after the iterator, returns iterator to the new node */
/* TODO Undefined behaviour if iter is slist_END */
/* Complexity: O(1) */
slist_iter_ty SlistInsert(slist_iter_ty iter, void *data)
{
slist_iter_ty new_node = NULL;
assert(iter);
assert(iter->next);
assert(data);
new_node->data = data;
new_node->next = iter->next;
iter->next = new_node;
return(new_node);
}
/* Returns iterator to end of the list */
/* Complexity: O(1) */
slist_iter_ty SlistIteratorEnd(const slist_ty *slist)
{
slist_iter_ty iterator = slist->head;
assert (slist);
if (NULL == slist->head)
{
return(NULL);
}
while (NULL != iterator->next->data)
{
iterator = iterator->next;
}
return(iterator);
}
My question along the request to get a feedback is:
Should I free any new slist_iter_ty that I make ?
For example, I made an iterator of type slist_iter_ty in the last function, in order to help me to traverse the list. But I can't free the iterator because I need to return it as the return value.
I also made a new_node in the SlistInsertfunction.
Will it be freed as part of the SlistDestroy function?
Thanks.
slist - is the list. when you create this list you use malloc so when you want to destroy it you need to free the list.
also - you used malloc every time you used insert. so when you want to destroy the list, you need to empty it from all the nodes - so you will need to free node by node
i can see you doesn't use mallloc in slist insert - how can you keep the data without use malloc?
In destroy function
while(NULL != slist->head)
{
tmp = slist->head;
slist->head = temp;
free(temp);
}
I think what you meant is:
while(NULL != slist->head)
{
tmp = slist->head;
slist->head = slist->head->next;
free(tmp);
}
In insert function
slist_iter_ty new_node = NULL;
what you should write:
new_node = (slist_iter_ty) malloc(sizeof(slist_node));
in slist end function
slist_iter_ty SlistIteratorEnd(const slist_ty *slist)
you can just return (after you assert something :)) :
return (slist->end);
(otherwise it wouldent be O(1) it would be O(n))

Implementation of Queues in Linked Lists

I am given these structure declarations in order to implement a queue collection that uses a circular linked list.
typedef struct intnode {
int value;
struct intnode *next;
} intnode_t;
typedef struct {
intnode_t *rear; // Points to the node at the tail of the
// queue's linked list
int size; // The # of nodes in the queue's linked list
} intqueue_t;
intnode_t *intnode_construct(int value, intnode_t *next)
{
intnode_t *p = malloc(sizeof(intnode_t));
assert (p != NULL);
p->value = value;
p->next = next;
return p;
}
/* Return a pointer to a new, empty queue.
* Terminate (via assert) if memory for the queue cannot be allocated.
*/
intqueue_t *intqueue_construct(void)
{
intqueue_t *queue = malloc(sizeof(intqueue_t));
assert(queue != NULL);
queue->rear = NULL;
queue->size = 0;
return queue;
}
I'm trying to create a function that will enqueue at a specified value (append it to the rear of the queue), and I need to consider the two cases in which the queue is empty and when the queue has one or more elements. This is the code I have so far:
void intqueue_enqueue(intqueue_t *queue, int value)
{
intnode_t *p = intnode_construct(value, NULL);
if(queue->rear->next == NULL) {
//the queue is empty
queue->rear->next =p;
} else {
//the queue is not empty
queue->rear=p;
}
queue->rear=p;
queue->size++;
}
This code gives me a runtime error so I'm not sure whats wrong. In the code, I'm assuming queue->rear->next is the front, however I think this is where the problem might be. All help is greatly appreciated. Thanks!
Your problem occurs on this line:
if(queue->rear->next == NULL) {
The first time you call the function, queue->rear is NULL. Thus when you try to dereference it to get queue->rear->next you get the runtime error.
To fix this code, update intqueue_enqueue to just check if queue->size==0, and if so then you need to initialize it by setting queue->rear=p and p->next=p. Then update the else clause so that it inserts the element between the two existing elements. Hint: you'll need to store queue->rear->next in p.
Edit
To address your comment, here's how to graphically think about a list with three elements:
<element1: next==element2> <element2: next==element3> <element3: next==element1>
And queue->rear points to element3. So, to insert a fourth element, you need to make it so that queue->rear points to element4 and element4->rear needs to point to element1. Remember that the location of element is stored in rear->next.

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;
}

invalid write size of 1 in C

I trying to write a queue(String Version) program in C by using linked lists.
Here is the structure:
struct strqueue;
typedef struct strqueue *StrQueue;
struct node {
char *item;
struct node *next;
};
struct strqueue {
struct node *front;//first element
struct node *back;//last element in the list
int length;
};
I creates a new StrQueue first
StrQueue create_StrQueue(void) {
StrQueue q = malloc(sizeof (struct strqueue));
q->front = NULL;
q->back = NULL;
q->length = 0;
return q;
}
makes a copy of str and places it at the end of the queue
void push(StrQueue sq, const char *str) {
struct node *new = malloc(sizeof(struct node));
new->item = NULL;
strcpy(new->item,str);//invalid write size of 1 ?
new->next = NULL;
if (sq->length == 0) {
sq->front = new;
sq->back = new;
} else {
sq->back->next = new;
sq->back = new;
}
sq->length++;
}
frees the node at the front of the sq and returns the string that was first in the queue
char *pop(StrQueue sq) {
if (sq->length == 0) {
return NULL;
}
struct node *i = sq->front;
char *new = sq->front->item;
sq->front = i->next;
sq->length --;
free(sq->front);
return new;
}
I got invalid write size of 1 at strcpy(new->item,str); I dont understand why I got this error.
Can anyone tell me why and tell me how should I fix it? Thanks in advance.
Okay, first things first, in the answer below I am NOT fixing your doubly linked list concepts, I am just showing you how you should fix the code above within the scope of your question. You may want to look into how doubly linked lists are done.
In:
void push(StrQueue sq, const char *str) {
struct node *new = malloc(sizeof(struct node));
new->item = NULL;
The next statement is wrong:
strcpy(new->item,str);
There are two ways you can solve it:
Make sure that *str is a valid pointer outside of the list management context while the list is being used.
Let the list manage the string allocation (and possibly deallocation).
is the quick and dirty method, it's easier to debug later but larger codebase makes it cumbersome.
cleaner looking code, but requires initial setup discipline, you should create object (string) management routines in addition to list management routines. can be cumbersome in its own right.
CASE 1: const char *str is guaranteed to be valid for life of StrQueue (this is what you are looking for really)
It should be:
new->item = str;
Here we assume str was a dynamic string allocated elsewhere
Now, in pop when you pop off the string you are okay. because the pointer you are returning is still valid (you are guaranteeing it elsewhere)
CASE 2: const char *str is not guaranteed to be valid for life of StrQueue
Then use:
new->item = strdup(str);
Now, in pop when you pop off the string you can either
de-allocate the strdup and not return anything, (not quite the same things as you did)
pass a container pointer to pop where contents of item are copied (clean)
return the popped off pointer, but you must deallocate it separately when you are done with it (ugly)
Which would make your pop function one of the following:
Case 2.1:
void pop(StrQueue sq) {
if (sq->length == 0) {
return NULL;
}
struct node *node = sq->front;
sq->front = node->next;
sq->length--;
free(node->item);
free(node);
}
Case 2.2:
char *pop(StrQueue sq, char *here) {
if (sq->length == 0) {
return NULL;
}
struct node *node = sq->front;
sq->front = node->next;
sq->length--;
strcpy(here, node->item);
free(node->item);
free(node);
}
Case 2.3:
char *pop(StrQueue sq) {
char *dangling_item = NULL;
if (sq->length == 0) {
return NULL;
}
struct node *node = sq->front;
sq->front = node->next;
sq->length--;
dangling_item = node->item;
free(node);
return dangling_item;
}
I got invalid write size of 1 at strcpy(new->item,str); I dont understand why I got this error. Can anyone tell me why and tell me how should I fix it?
Why:
This code:
new->item = NULL;
strcpy(new->item,str);//invalid write size of 1 ?
You're not suppose to pass a null pointer to the first argument, it should be a pointer to allocated memory. The reason why you're getting this error message, I can imagine, is because the implementation of strcpy probably looks like this:
for (int i = 0; str2[i]; i++) str1[i] = str2[i];
And in the first iteration of the for loop, it writes to address 0 (a read-only section of memory) - this gives you the invalid write of size 1. I'm not sure, however, why you are only getting a size of 1, though (I would imagine it would be the entire size of the string). This could be because either a) str is only of size 1 or b) because the signal, SIGSEGV stops the program.
How to fix:
Allocate space for new->item before calling strcpy, like this:
new->item = malloc (strlen (str) + 1); // + 1 for null-terminating character
But you could probably include some error checking, like this:
int len = strlen (str) + 1;
if (len){
new->item = malloc (len);
if (!new->item){
return;
}
}

C: pop function in double linked list

I am working with a double linked list and I have run into a problem with my pop() function.
//QueueElement describe the block in the cache
typedef struct _queue_ele_
{
char *content; //the data of the block
struct _queue_ele_ *prev;
struct _queue_ele_ *next;
}QueueElement;
typedef struct _queue_
{
int queue_len;
int max_queue_size;
QueueElement *head;
QueueElement *tail;
}MyQueue;
The pop function works until there is an input of 2 elements ( I clear the queue by poping one by one and freeing the memory)
pop:
// head is removed and returned
QueueElement* pop(MyQueue* myqueue)
{
// if empty
if(myqueue->queue_len == 0) return NULL;
QueueElement *p = myqueue->head;
// if one element
if(myqueue->queue_len == 1)
{
myqueue->queue_len--;
myqueue->head = NULL;
myqueue->tail = NULL;
return p;
}
else
{
myqueue->queue_len--;
//remove the head from the queue
myqueue->head = myqueue->head->prev;
myqueue->head->next = NULL; //******************Seg Fault here
p->prev = NULL;
return p;
}
}
The error I get when there are two elements is a segmentation fault in line shown, but it works for queues with more. Why wont it let me assign NULL to myqueue->head->next???
Change this:
myqueue->head = myqueue->head->prev;
myqueue->head->next = NULL; //******************Seg Fault here
To:
myqueue->head = myqueue->head->prev;
if (myqueue->head != NULL) {
myqueue->head->next = NULL;
}
It is likely that you are trying to dereference a NULL pointer. It also would appear that you may have a memory leak from not calling free on the nodes you are deleting, but it is possible you do that elsewhere in the code.

Resources