I am working on an a queue and keep running into problems with enqueuing. Here is what I believe to be the relevant code:
typedef struct Qnode QNODE;
struct Qnode
{
int length;
QNODE* next;
QNODE* prev;
};
typedef struct lqueue lQUEUE;
struct lqueue
{
QNODE *head;
QNODE *tail;
};
lQueue lqueue_init_default(void)
{
lQUEUE* pQ = NULL;
pQ = (lQUEUE*)malloc(sizeof(lQUEUE));
if (pQ != NULL)
{
pQ->head = NULL;
pQ->tail = NULL;
}
pQ->head = pQ->tail;
return pQ;
}
Status lqueue_henqueue(lQueue* hLQ, int lc)
{
lQUEUE* pLQ = (lQUEUE*)hLQ;
QNODE* new = (QNODE*)malloc(sizeof(QNODE));
if (new == NULL)
{
printf("Couldn't allocate space.\n");
return FAILURE;
}
new->length = lc;
new->next = pLQ->tail->next;
pLQ->tail = new;
return SUCCESS;
}
Whenever I try to run the program, I get this error during run time:
Exception thrown: read access violation.
pLQ->tail was nullptr.
Why is it a null pointer? Does it have to do with the Initialization function?
Here is how it is called:
int cl = 0;//Individual car length
lQueue hLQ = lqueue_init_default();//Handle to the left queue
printf("Enter the length of the lcar:\n");
scanf("%d", &cl);
lqueue_henqueue(hLQ, cl);
Your code is highly prone to undefined behavior... Look at this if statement:
if (pQ != NULL)
{
pQ->head = NULL; // This pointer is now 'NULL'
pQ->tail = NULL; // This is also 'NULL'
}
Which should be this...
if (pQ != NULL)
{
pQ->head = (QNODE*)calloc(1, sizeof(lQUEUE)); // This is proper pointer initialization...
pQ->tail = (QNODE*)calloc(1, sizeof(lQUEUE));
}
And this:
lQueue lqueue_init_default(void)
should be this:
lQueue * lqueue_init_default(void) // Since you are returning a pointer...
You will see that the code works fine because there is no undefined behavior...
Note that you can never access an object that is assigned to NULL... (Only if you don't want your program to behave undefined...) So, this:
pQ->tail = NULL;
is not safe in the very least... Structural pointers being assigned to NULL are usually only seen when being destroyed... An example is given below...
Also, unrelated, but have a destructor for the structure and call it when you don't need the structure anymore, or it will leak the memory afterwards...
void destroy_lqueue(struct lqueue ** queue)
{
if (queue != NULL)
queue = NULL;
free(queue);
}
Related
Hi I'm new to C and pointers and are having issues trying to implement the below doubly linked list structure. Memory leaks happened in listInsertEnd I believe? I am very confused as to why one work (at least no mem leak in output) and the other one doesn't. I have pasted only parts of the program, any help or explanation is much appreciated.
#include <stdio.h>
#include <stdlib.h>
typedef struct node *Node;
struct node {
int value;
Node next;
Node prev;
};
typedef struct list *List;
struct list {
Node first;
Node last;
int count;
};
Node newNode(int value) {
Node n = malloc(sizeof(*n));
if (n == NULL) fprintf(stderr, "couldn't create new node\n");
n->value = value;
n->next = NULL;
n->prev = NULL;
return n;
}
void listInsertEnd(List newList, int value) {
Node n = newNode(value);
if (newList== NULL) { //no item in list
//why is this giving me memory leaks
newList->first = newList->last = n;
//whereas this doesn't?
newList->first = newList->last = newNode(value);
} else { //add to end
n->prev = newList->last;
newList->last->next = n;
newList->last = n;
}
nList->count++;
}
First of all, talking about memory leaks: there is no direct memory leak in your code. If the leak happens somewhere, it's outside of these functions. It's most probably because you create one or more nodes and then forget to free() them, but this has nothing to do with the two functions you show.
I see that you are using typedef to declare simple pointer types, take a look at this question and answer to understand why that's bad practice and should be avoided: Is it a good idea to typedef pointers?. Also, this particular piece of Linux kernel documentation which explains the issue in more detail.
Secondly, the real problem in the code you show is that you are using pointers after you tested that they are invalid (NULL).
Here:
Node newNode(int value) {
Node n = malloc(sizeof(*n));
if (n == NULL) fprintf(stderr, "couldn't create new node\n");
n->value = value;
// ^^^^^^^^ BAD!
And also here:
if (newList== NULL) {
newList->first = newList->last = n;
// ^^^^^^^^^^^^^^ BAD!
If something is NULL, you cannot dereference it. Change your functions to safely abort after they detect an invalid pointer.
This can be done in multiple ways. Here's an example of correct code:
Node newNode(int value) {
Node n = malloc(sizeof(*n));
if (n == NULL) {
fprintf(stderr, "couldn't create new node\n");
return NULL;
}
n->value = value;
n->next = NULL;
n->prev = NULL;
return n;
}
void listInsertEnd(List newList, int value) {
Node n;
if (newList == NULL) {
return;
// You probably want to return some error value here.
// In that case change the function signature accordingly.
}
n = newNode(value);
if (newList->count == 0) {
newList->first = newList->last = n;
} else { //add to end
n->prev = newList->last;
newList->last->next = n;
newList->last = n;
}
newList->count++;
}
NOTE: the check newList->count == 0 assumes that you correctly increment/decrement the count when adding/removing elements.
This typedef declaration
typedef struct node *Node;
is confusing and presents a bad style. Consider for example this statement
Node n = malloc(sizeof(*n));
somebody can think that here is a typo and should be written
Node *n = malloc(sizeof(*n));
The function
void listInsertEnd(List newList, int value) {
Node n = newNode(value);
if (newList== NULL) { //no item in list
//why is this giving me memory leaks
newList->first = newList->last = n;
//whereas this doesn't?
newList->first = newList->last = newNode(value);
} else { //add to end
n->prev = newList->last;
newList->last->next = n;
newList->last = n;
}
nList->count++;
}
has undefined behavior. If newList is equal to NULL then you are trying to use memory pointed to by a null pointer.
if (newList== NULL) { //no item in list
//why is this giving me memory leaks
newList->first = newList->last = n;
//whereas this doesn't?
newList->first = newList->last = newNode(value);
And initially data members newList->first and newList->last can be equal to NULL. That also can be reason of undefined behavior because the function does not take this into account.
Before changing the function listInsertEnd you should define the function newNode the following way
Node newNode(int value)
{
Node n = malloc(sizeof(*n));
if ( n != NULL )
{
n->value = value;
n->next = NULL;
n->prev = NULL;
}
return n;
}
The function shall not issue any message. It is the caller of the function that decides whether to issue a message if it is required.
In this case the function listInsertEnd can be written the following way
int listInsertEnd(List newList, int value)
{
Node n = newNode(value);
int success = n != NULL;
if ( success )
{
n->prev = newList->last;
if ( newList->first == NULL )
{
newList->first = newList->last = n;
}
else
{
newList->last = newList->last->next = n;
}
++newList->count;
}
return success;
}
Within the main you should create the list the following way
int main( void )
{
struct list list1 = { .first = NULL, .last = NULL, .count = 0 };
// or
// struct list list1 = { NULL, NULL, 0 };
and call the function like
listInsertEnd) &list1, some_integer_value );
I am trying to make a function that copies a node. I am trying to have the program on error or NULL return NULL, I can only have one return statement
I have the following code and I am not sure what else to do from here.. Any tips/advice I would greatly appreciate
Node *cpnode(Node *curNode)
{
if (curNode == NULL) return NULL;
Node *result = malloc(sizeof *result);
result -> value = curNode -> value;
result -> next = cpnode(curNode -> next;
return(result);
}
EDIT:
I have edited my code when trying to compile I am getting errors such as
Node has no member named 'value' and 'next'. Why is that?
Also I know I can easily return NULL on my if statement and at the end return with my result but how could I just have only one return statement with NULL on error?
To define my Node would I have to do something like this:
Node *cpnode(Node *curNode)
{
struct Node{
*result;
*value;
*next;
}
if (curNode == NULL) return NULL;
Node *result = malloc(sizeof *result);
result -> value = curNode -> value;
result -> next = cpnode(curNode -> next;
return(result);
}
There are several issues with your code: your Node structure isn't properly defined and you're using it as a type which you didn't typedef; your text talks about copying a node but your code copies a linked list of nodes; result doesn't seem like it should be part of the Node structure; your code isn't syntactically correct (e.g. missing paren).
Here's a rework of your code into something that compiles and runs. Since you didn't specify the type for value, I'm assuming it's a string below but you can change that to whatever you want:
#include <stdlib.h>
#include <stdio.h>
typedef struct Node
{
char *value;
struct Node *next;
} Node;
Node *copyNodes(Node *currentNode)
{
Node *result = NULL;
if (currentNode != NULL)
{
if ((result = malloc(sizeof *result)) != NULL)
{
result->value = currentNode->value;
result->next = copyNodes(currentNode->next);
}
}
return result;
}
void freeNodes(Node *currentNode)
{
if (currentNode != NULL)
{
if (currentNode->next != NULL)
{
freeNodes(currentNode->next);
currentNode->next = NULL;
}
}
free(currentNode);
}
int main()
{
Node a, b;
b.value = "last";
b.next = NULL;
a.value = "first";
a.next = &b;
Node *c = copyNodes(&a);
printf("%s\n", c->next->value);
freeNodes(c);
return 0;
}
If we make a copy of all the nodes using malloc(), then when finished, we need to free all the copies in a similar fashion to how they were created. That's what the function freeNodes() does.
Recently I've been improving my programming skills by coding different data structures, and this is the very beginning!!!
Now I'm writing the linked list, but something annoyed happen and the trouble has been annoyed me for a long time since I am not quite sure about this error,
Segmentation fault(core dumped), but I did know I made something wrong in the operation of memory.
link_list.h:
struct LINK_LIST {
char *string;
struct LINK_LIST *next;
}link_list;
==============================
link_list.c:
#include<stdio.h>
#include<stdlib.h>
int init_link_list(struct LINK_LIST *new_link) {
//char *new_string;
int i;
//new_string = (char *)malloc(sizeof(char) * STRING_SIZE);
new_link = (struct LINK_LIST *)malloc(sizeof(struct LINK_LIST));
if (new_link==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return ERROR;
}
//new_link->string = new_string;
new_link->string = NULL;
//new_link->next = NULL;
return OK;
}
Here I defined the init operation, then the insert operation:
int insert(struct LINK_LIST *link, int pos, char *in) {
int i;
if (get_length(link)>=STRING_SIZE) {
fprintf(stderr, "Link list is full!!!");
return ERROR;
}
else {
if (pos < 0 || pos-1 > get_length(link)) {
fprintf(stderr, "Invalid position");
return ERROR;
}
else {
i = 0;
do {
struct LINK_LIST *new_node;
init_link_list(new_node);
new_node->next = link->next;
link->next = new_node;
new_node->string = in;
i += 1;
} while(i<pos-1);
}
}
return OK;
}
You have a bug there :
struct LINK_LIST *new_node;
init_link_list(new_node);
In init_link_list, the value of the argument is modified :
new_link = (struct LINK_LIST *)malloc(sizeof(struct LINK_LIST));
but that modification is only local to the function ; once you get back to your calling function, that change is lost :
struct LINK_LIST *new_node;
init_link_list(new_node);
// Oops ! new_node's new value is lost !
You have a memory leak (the malloc's result is lost) and new_node is not initialized. When you try to access *new_node, you access a random position in memory, hence core dumps.
There are a few possible corrections, the easiest is to discard your OK/ERROR return values and return either a non-null pointer if malloc succeeded, or NULL if it failed :
struct LINK_LIST *init_link_list(void) {
struct LINK_LIST *new_link = malloc(sizeof(struct LINK_LIST));
if (new_link==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return NULL;
}
new_link->next = NULL;
return new_link;
}
Then, code in insert becomes :
...
else {
i = 0;
do {
struct LINK_LIST *new_node = init_link_list();
// Note : here, should check whether new_node is NULL and deal with the situation
new_node->next = link->next;
link->next = new_node;
...
I use nested structure to define the linked-list queue:
queue.h:
#define QUEUE_MAX_SIZE 4096
struct QUEUE_NODE {
char *string;
struct QUEUE_NODE *next;
}queue_node;
struct COMMON_QUEUE {
struct QUEUE_NODE *q_node;
}common_queue;
=================================
queue.c:
/* here I define the operations */
struct COMMON_QUEUE *C_init_queue() {
struct QUEUE_NODE *head;
head = malloc(sizeof(struct QUEUE_NODE));
if (head==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return NULL;
}
struct COMMON_QUEUE *new_queue;
new_queue = malloc(sizeof(struct COMMON_QUEUE));
if (new_queue==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return NULL;
}
head->next = NULL;
head->string = NULL;
new_queue->q_node = head;
return new_queue;
}
int C_get_queue_length(struct COMMON_QUEUE *q) {
int count;
count = 0;
while (q->q_node->next!=NULL) {
count += 1;
q->q_node = q->q_node->next;
}
return count;
}
int C_enqueue(struct COMMON_QUEUE *q, char *in) {
if (C_get_queue_length(q)>=QUEUE_MAX_SIZE) {
fprintf(stderr, "Linked queue is full!!!");
return ERROR;
}
struct QUEUE_NODE *new_node;
new_node = malloc(sizeof(struct QUEUE_NODE));
if (new_node==NULL) {
return ERROR;
}
new_node->next = NULL;
new_node->string = NULL;
while (q->q_node->next!=NULL) {
q->q_node = q->q_node->next;
}
new_node->next = q->q_node->next;
q->q_node->next = q->q_node;
new_node->string = in;
return OK;
}
but when I use it in the main program, then it jumps into a endless loop, after backtracing, and I knew the problem is at:
while (q->q_node->next!=NULL) {
count += 1;
q->q_node = q->q_node->next;
}
but it seems correct, but I may make some mistake on my initialization of the two nested struct!
P.S. the I did not list the "free()".
This loop modifies the list while it traverses it. Specifically, it replaces q->q_node with q->q_node->next, which if nothing else will discard your entire loop.
while (q->q_node->next!=NULL) {
count += 1;
q->q_node = q->q_node->next;
}
If you want to correctly traverse the list, you need to declare a separate pointer that you use for traversal. Something like this:
int C_get_queue_length(struct COMMON_QUEUE *q) {
int count;
struct COMMON_QUEUE *p = q->q_node;
count = 0;
while (p->next != NULL) {
count += 1;
p = p->next;
}
return count;
}
The pointer p will step along the list without modifying the q_node pointers along the way.
You have a similar error in C_enqueue. You really want to use a separate pointer to walk the list, and not assign q->q_node during traversal. You can fix your C_enqueue similarly:
p = q->q_node;
while (p->next != NULL) {
p = p->next;
}
p->next = new_node; /* append the new node after where the list traversal stopped */
new_node->next = NULL; /* always NULL, because you always insert at the end */
One problem with your code is that your iterations through the queue are destructive: rather than using a temporary variable to iterate your linked list, you perform the iteration using the q_node itself. This leads to C_get_queue_length calls effectively destroying the queue, without freeing its nodes (a memory leak).
Here is an example of how to iterate a list non-destructively, using your "get length" method:
int C_get_queue_length(struct COMMON_QUEUE *q) {
int count;
count = 0;
struct QUEUE_NODE node = q->q_node;
while (node->next != NULL) {
count++;
node = node->next;
}
return count;
}
Your decision to pre-allocate one node when creating a queue is also questionable: it appears that the head node is unused, and also excluded from the count. This makes it easier to write the code to insert and delete nodes, but the same could be done with an extra level of indirection (i.e. a pointer to a pointer).
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.