I'm writing a simple linked list implementation for the sake of learning. My linked list consists of node structures that contain an int value and a pointer to the next node. When I run my code, it loops endlessly even though it should terminate when it reaches a NULL pointer. What am I doing wrong?
#include <stdio.h>
struct node {
int value;
struct node *next_node;
};
struct node * add_node(struct node *parent, int value)
{
struct node child;
child.value = value;
child.next_node = NULL;
parent->next_node = &child;
return parent->next_node;
}
void print_all(struct node *root)
{
struct node *current = root;
while (current != NULL) {
printf("%d\n", current->value);
sleep(1);
current = current->next_node;
}
}
int main()
{
struct node root;
root.value = 3;
struct node *one;
one = add_node(&root, 5);
print_all(&root);
}
Your program exhibits undefined behavior: you are setting a pointer to a locally allocated struct here:
struct node child;
child.value = value;
child.next_node = NULL;
parent->next_node = &child;
return parent->next_node;
Since child is on the stack, returning a parent pointing to it leads to undefined behavior.
You need to allocate child dynamically to make it work:
struct node *pchild = malloc(sizeof(struct node));
// In production code you check malloc result here...
pchild->value = value;
pchild->next_node = NULL;
parent->next_node = pchild;
return parent->next_node;
Now that you have dynamically allocated memory, do not forget to call free on each of the dynamically allocated nodes of your linked list to prevent memory leaks.
add_node returns a pointer to a local variable which immediately goes out of scope and may be reused by other functions. Attempting to access this in print_all results in undefined behaviour. In your case, it appears the address is reused by the current pointer, leaving root->next_node pointing to root.
To fix this, you should allocate memory for the new node in add_node
struct node * add_node(struct node *parent, int value)
{
struct node* child = malloc(sizeof(*child));
if (child == NULL) {
return NULL;
}
child->value = value;
child->next_node = NULL;
parent->next_node = child;
return child;
}
Since this allocates memory dynamically, you'll need to call free later. Remember not to try to free root unless you change it to be allocated using malloc too.
Related
I am trying to define a simple linked list
#include <stdio.h>
struct node{
int value;
struct node* next;
};
typedef struct {
struct node* root;
} ll;
void add_to_ll(int value, ll* linked_list) {
struct node new_node = {value, linked_list->root};
linked_list->root = &new_node;
}
void print_ll(ll* ll2) {
printf("%p", ll2);
struct node* temp = ll2->root;
while (temp->next != NULL) {
printf("%d ", temp->value);
temp = temp->next;
}
}
int main()
{
printf("Creating a linked list...\n");
struct node root_node = {1, NULL};
ll my_linked_list = { &root_node };
for (int i = 0; i < 10000; i++) {
add_to_ll(i, &my_linked_list);
}
printf("my_linked_list root value %d\n", my_linked_list.root->value);
printf("my_linked_list root value %d\n", my_linked_list.root->value);
printf("my_linked_list root value %d\n", my_linked_list.root->value);
return 0;
}
The output I am getting is:
Creating a linked list...
my_linked_list root value 9999
my_linked_list root value 429391991
my_linked_list root value 429391991
I am able to get the value of the root node correctly the first time. But on trying to read it the second time (and thereafter) the value changes. What am I missing?
Your problem is with the memory allocation strategy in add.
void add_to_ll(int value, ll* linked_list) {
struct node new_node = {value, linked_list->root};
linked_list->root = &new_node;
}
Here you're instatiating new_node as a local variable. Non-static local variables have a lifespan equal to that of their block. After you exit the block, that memory (which is actually the stack) is available for successive allocations that will overwrite your object. Use explicit allocation, that means malloc, to have objects whose lifespan is independent from the scope of allocation.
I would also point out the naming... The most explicit name should be that of the type, not the variable. So struct linked_list ll and not the other way around.
This function:
void add_to_ll(int value, ll* linked_list) {
struct node new_node = {value, linked_list->root};
linked_list->root = &new_node;
}
Constructs a node on the stack and adds it to the list.
When you return from this function the stack is popped and the list root points to unallocated memory on the stack that will later be reused.
I am studying the following C code:
typedef struct msg *m_;
struct msg
{
long from;
long to;
m_ link;
};
m_ queue;
I would like to see an example that explains the role of the pointer, i.e. m_, of the structure inside the structure itself m_ link!
Thank you very much.
To be pedantic: link is a pointer. m_ is not a pointer, it's a typedef. It is used to avoid the need to say "struct msg* link;" inside the struct definition.
As answered in the comment above, the queue is represented by a pointer to the first item, which has a pointer to the second (if any), and so on until you reach a NULL pointer.
It's important to take care when building such lists that no node points to itself or to any precursor, or you get an infinite loop chasing to the tail.
Pointers to the structure type inside the structure itself are very often used for linked lists, trees, etc. In your example, it is referring to a queue implementation.
Here is a very minimal example of a stack implementation using a linked list. The functions require the address of a stack pointer, and an empty stack is a NULL pointer.
struct linked_stack
{
int data;
struct linked_stack *next;
};
void linked_stack_push(linked_stack **stck, int data)
{
struct linked_stack *node = malloc(sizeof(struct linked_stack));
if (node != NULL)
{
node->data = data;
node->next = *stck;
}
*stck = node;
}
int linked_stack_top(linked_stack **stck)
{
if (*stck != NULL)
return (*stck)->data;
return 0; /* stack is empty */
}
void linked_stack_pop(linked_stack **stck)
{
struct linked_stack *node = *stck;
if (*stck != NULL)
{
*stck = node->next;
free(node);
}
}
Example usage:
int main(void)
{
struct linked_stack *stack = NULL;
linked_stack_push(&stack, 10);
printf("top of stack = %d\n", linked_stack_top(&stack));
linked_stack_pop(&stack);
return 0;
}
I am implementing the insert function of a binary search tree in C and I am encountering a problem with malloc.
First of all, I have a Tree and Node struct
typedef struct Node {
double value;
struct Node *parent;
struct Node *right_child;
struct Node *left_child;
} Node;
typedef struct Tree {
struct Node *root;
} Tree;
And here is my insert function to insert a value into the tree.
void insert(Tree *t, double v) {
Node *n = malloc(sizeof(Node));
n->left_child = malloc(sizeof(Node));
n->right_child = malloc(sizeof(Node));
n->parent = malloc(sizeof(Node));
n->value=v;
Node *x = t->root, *y = NULL;
//follow tree down until we reach a leaf of the tree
while (x) {
//save last non-NULL value. We will insert node n as a child to this leaf.
y = x;
if (n->value < x->value) {
x = x->left_child;
} else {
x = x->right_child;
}
}
//The parent of the node to insert is the leaf we reached
n->parent = y;
//If n is greater than y then it is its right child and vice-versa.
if (n->value > y->value) {
y->right_child = n;
} else {
y->left_child = n;
}
}
And my main method
int main(void) {
Node n1;
n1.value = 4;
n1.parent = NULL;
n1.left_child = NULL;
n1.right_child = NULL;
Tree t;
t.root = &n1;
insert(&t,2.0);
printf("In order traversal\n");
inOrderTraversalNode(t.root);
return EXIT_SUCCESS;
}
When I print the in-order traveral code I get undefined behavior (eg: 26815615859885194199148049996411692254958731641184786755447122887443528060147093953603748596333806855380063716372972101707507765623893139892867298012168192.000000) instead of the correct traversal.
I am pretty sure the problem is the Node creation in the insert method. I assume the problem is that the new node exists on the stack which is then being destroyed when the insert function exits - which is what is causing the undefined behaviour during the traversal. However, I thought that malloc stores the variable on the heap and makes it available globally. Or perhaps the node is on the heap but the pointer is on the stack? Could someone show me where I am going wrong here?
The initial contents in the memory allocated via malloc is undefined.
Firstly, remove n->parent = malloc(sizeof(Node));, which causes memory leak.
Secondly, change
n->left_child = malloc(sizeof(Node));
n->right_child = malloc(sizeof(Node));
to
n->left_child = NULL;
n->right_child = NULL;
so that the program can correctly recognize the leaf.
Try using calloc instead of malloc. The problem is that malloc doesn't initialize values to zero, it only allocates the space. calloc zeros out the space you're requesting. So, you're getting jumped to a random part of memory occasionally when you get to a pointer that isn't valid, but isn't NULL either.
malloc and friends definitely allocate on the heap, you've got that thinking right; what they return is a pointer to a space in memory of at least the size you requested that is definitely safe to read from and write to. However, since the value isn't zeroed out to begin with when you use malloc, you aren't able to guarantee that the pointer stored in your struct is actually to a valid location.
EDIT: also, other poster is right: there is definitely a memory leak with what you're doing. Didn't catch that.
When I try to free an allocation in a struct inside a struct, I get an error.
How can I fix it?
typedef struct card
{
char* sign;
char* color;
int number;
char* name;
}card;
typedef struct deck
{
card data;
deck* next;
}deck;
deck* deleteHead(deck* head)
{
deck* curr = head;
if (head==NULL)
return head;
curr=curr->next;
if(head->data.color!=NULL)
free(head->data.color);//error
if(head->data.name!=NULL)
free(head->data.name);//error
if(head->data.sign!=NULL)
free(head->data.sign);//error
free(head);//ok
return curr;
}
when I'll delete the errors and only freeing the head - it'll work, but when I'll try to delete the allocations inside the head, I'll get a run time error.
How can I solve this?
Thank you in advance.
You probably did not initialize the pointers in the card structure. These should either be initialized to NULL or to a pointer to memory allocated by malloc, calloc or strdup.
Also note that you don't need to test pointers against NULL before calling free(). free(NULL); will gracefully return immediately, it is legal to call free with NULL. Incidentally it is also legal in C++ to delete a null pointer.
The function can be further simplified this way:
deck *deleteHead(deck *head) {
deck *next = NULL;
if (head != NULL) {
next = head->next;
free(head->data.color);
free(head->data.name);
free(head->data.sign);
free(head);
}
return next;
}
The function free can only de-allocate a block of memory previously allocated by a call to malloc, calloc or realloc. Your code will run without any runtime error if you initialize it properly. Here's a sample code:
int main()
{
deck* root = (deck*)malloc(sizeof(struct deck));
root->card.color = strdup("color");
root->card.name = strdup("name");
root->card.sign = strdup("sign");
root->card.number = 2;
root->next = NULL;
root = deleteHead(root);
return 0;
}
And also there is a slight correction in your code:
typedef struct deck
{
card data;
struct deck* next;
}deck;
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;
}