I am trying to achieve a double linked list using C and have encountered a crash whenever I try to append a third node to my list. I have located the line in my code in which my program crashes, but I cannot understand why since the code looks "safe". I have received no warnings or errors from the compiler. If anyone is able to explain a possible pointer error or the reason behind the crash, it would be much appreciated. Any questions or concerns related to my code will be answered as soon as I see them.
struct node *appendNode(struct node *headRef, unsigned short int newData) {
struct node *newNode = (struct node*)malloc(sizeof(struct node*));
newNode->data = newData;
newNode->next = NULL;
if(headRef == NULL) { //list is empty and returns the newNode to become the head pointer
newNode->previous = NULL;
return newNode;
} else { //list is not empty and newNode is appended to end of list ----(Area of crash)----
struct node *current = headRef;
while(current->next != NULL) {
current = current->next;
}
current->next = newNode;
newNode->previous = current;
return headRef;
} //----------------------------------------------------------------------------------
};
The code presented above is a function that appends a new node to the list. It returns a new address or same address back when finished to update the head pointer used in 'main'. The code runs functionally whenever I append the first two nodes, but crashes whenever it tries to append a third node.
The amount of memory space you are allocating is the size of a pointer to a struct node, not the actual size of a struct node - which you want.
So it should be
struct node *newNode = (struct node*)malloc(sizeof(struct node));
As a consequence of allocating insufficient memory, your program is writing outside the memory block that it allocated, which causes undefined behavior. This means that anything can happen. For example, the program may crash immediately, not at all, or at a later time.
Related
Bit of a lengthy question so please bear with me. I am trying to create a doubly linked list in C using a dummy node as the head. For whatever reason, however, the list only saves the last node I read into it, and links the prev node pointer and the next node pointer to that last node, so if I try and iterate over the list, it gets stuck in an infinite loop.
Here is my node header file and C file. The linked list implementation isn't meant to be a full linked list implementation, so I only included the functions I need:
node.h:
#ifndef _node_h
#define _node_h
#include "task_block.h"
#include <stdio.h>
typedef struct node {
task_block_type *data;
struct node *next;
struct node *prev;
}node_t;
node_t *node_new(task_block_type *data);
void add(node_t *new, node_t *head);
#endif
node.c:
#include "node.h"
#include "task_block.h"
#include <stdlib.h>
node_t *node_new(task_block_type *data) {
node_t *node = NULL;
node = malloc(sizeof(node_t));
node->data = data;
node->next = NULL;
node->prev = NULL;
return node;
}
void add(node_t *new, node_t *head) {
node_t *current = head;
if (head->next == NULL) {
head->next = new;
head->next->prev = head;
return;
}
while(current->next != NULL) {
current = current->next;
}
current->next = new;
current->next->prev = current;
return;
}
And finally, the code that is messing up from main.c:
while (j < numTasks) {
if (tasks[j].taskID == currentID) {
*newTask = *task_block_new(tasks[j].taskID, tasks[j].period);
newTask->startTime = starts[i];
newTask->deadline = deadlines[i];
newTask->executionTime = executions[i];
*nodeNew = *node_new(newTask);
add(nodeNew, eventQueue);
}
I have already tested that my new task_block_type get the correct data form the text file and that the new node I create is initialized properly with the task block. Once I read it into my list with add(), however, it messes up. Any help would be greatly appreciated as I've been trying to fix this problem for several hours now and still haven't found a solution
EDIT:
self contained example:
*node_new is meant to be a constructer for my node objects and is supposed to return a pointer to a node object. So for example, say instead of having a node which contains the task_block_type as above, I have one that contains an int. If I wanted to initialize it with a value of 5, I would call
*newNode = (node_t *)malloc(sizeof(node_t));
*newNode = *node_new(5);
Hope that helps
Change this:
*nodeNew = *node_new(newTask);
To this:
nodeNew = node_new(newTask);
Your original code copies the (dereferenced) value returned by node_new() to the value at (dereference of) *nodeNew. Thus, the pointer nodeNew never gets updated with the address of the new node created by node_new()... so you keep overwriting the value at *nodeNew while passing its unchanging address to add().
And you get a memory leak into the bargain. You are responsible for free()ing every pointer ever returned to you by malloc(). But here, for the same reason given above, you're not keeping copies of the returned pointers to enable this... just linking to nodeNew over and over again.
You need to update the pointer nodeNew with the location of, well, each new node, before passing it on to add(). Then you'll actually be linking different nodes, and at their original addresses, rather than copying them to the same address in a leaky fashion and linking it to itself, infinitely.
You also need to free() all memory that you have dynamically allocated once you're finished using it, e.g. through a sweep of the linked list in a 'destructor' function or at the end of your program. Otherwise you're leaking memory. This is a basic error and, even in cases where it doesn't stop a program from working, wastes users' RAM, which they rightly dislike!
I highly recommend studying pointers and dynamic allocation some more before continuing trying to write code like this.
Updated with some new details:
Interestingly if I get no segfault if I don't use: node->next = NULL. I can create the nodes fine, but it seems there's an issue in setting the initial list head to my new node, as well as dereferencing ->next.
Note that without the structure definitions, it make be a bit harder for us to know what is wrong...
You have a problem here where you use the allocated pointer before testing whether the malloc() failed. Although that's probably not the culprit at this point.
struct node *head = (struct node*)malloc(sizeof(struct ftt_node));
foodList->head = head; // <<<---- here using the pointer NULL or not
head->next = NULL;
rest->foods = foodList;
if (NULL == rest->foods) { // <<<---- testing here if malloc() failed
printf("List creation failed");
return FALSE;
}
As a side note, the head pointer has the same problem.
Then in add_node you do that, with newNode never allocated... so probably garbage!
struct node *newNode;
newNode->data = newFood;
You probably wanted to allocate newNode and use curr to find the last existing node.
Something like this:
void add_node(POS * POS, struct food * newFood)
{
struct node *newNode;
struct node *newNode = (struct node*)malloc(sizeof(struct node));
newNode->data = newFood;
curr = POS->foods->head;
while (curr != NULL)
{
curr = curr->next;
}
curr->next = newNode;
newNode->next = NULL;
}
That being said, I would very strongly suggest that you create a base list object with functions to handle the list, and then start your node with that list, instead of writing it this way.
As a side note: You should NOT name the variable POS in your add_node(). That's bad practice as it shadows your variable type.
Just wondering, why not use C++? At least testing for NULL is not required because new throws if memory cannot be allocated... And for list you have std::list, although in your case std::vector would probably work better so you could go through your array of nodes with a very simple for().
Your newNode variable in add_node is unitialised so it can point anywhere in memory, which can be the cause of the segfault when you try to dereference it on the second line. In addition, you allocated a new struct node structure but overwrote its adress immediately. So your first few lines should be rewritten thus:
struct node *newNode = (struct node*)malloc(sizeof(struct node));
newNode->data = newFood;
struct node *curr = POS->foods->head;
The add_node() function never modifies pos->foods->head. It also never initializes new_node, so that pointer cannot be dereferenced without triggering undefined behavior.
Thus, the list can never grow from being empty.
I am doing a bucket sort, sorting pointers to nodes into a linked list with a dummy header. The user inputs the values for the nodes, and then they are immediately dropped into their appropriate bucket. My problem arises when I am attempting to allocate the memory for the second node (not including the dummy header) for the linked list.
This is the code used to drop the nodes into the bucket, var being the value that is being sorted, and current being the newly created node to be sorted:
void bucketSort(int var, nodeptr current)
if(!bucket[var])
{
buckets[var] = (nodeptr) malloc(sizeof(nodeptr));
buckets[var]->next = current;
bucketrear[var] = current;
}
else
{
bucketrear[var]->next = current;
bucketrear[var] = current;
}
}
This is a simplified version (less values) of the code used to create the new node:
void addNode(int value)
{
nodeptr newNode;
newNode= (nodeptr) malloc(sizeof(nodeptr));
newNode->value = value;
newNode->next = NULL;
bucketDrop(value, newNode);
}
With Trace Statements, I discovered that before the Malloc of the second Node (with same value as the first), the Address of the bucket[value]->next was a normal address, but afterwards the address was 17. This value of 17 came up in every single test that I did.
Any help or ideas would be great. Thankyou in advance.
I think this is one of solution.
buckets[var] = (nodeptr) malloc(sizeof(*buckets[var]));
newNode= (nodeptr) malloc(sizeof(*newNode));
You're mixing up the struct for your node and the pointer pointing to it and thus overwriting the memory location.
Since you're casting the malloc result to a nodeptr type it means that this is a pointer (since malloc() returns a pointer) which also means your're allocating memory the size of a pointer.
So given that you named your struct nodestruct, to allocate enough memory you'd write
newNode = (nodeptr) malloc(sizeof(struct nodestruct));
The following should resolve your issue:
newNode= (nodeptr) malloc(sizeof(*nodeptr));
The reason is nodeptr looks to be a pointer to struct, and hence you should allocate memory for the struct instead of a pointer.
From, next time please paste your struct definitions also.
Here's my function to delete a linked list:
void deleteList( NODE* head )
{
NODE* temp1;
NODE* tempNext;
temp1 = head;
tempNext = NULL;
while( temp1 != NULL )
{
tempNext = temp1->next;
free(temp1);
temp1 = tempNext;
}
}
So temp1 first points where the head pointer is pointing. If it isn't NULL, tempNext will be set to point to the next element of the list. Then the first element (temp1) is free'd, and temp1 is reassigned to point to where tempNext is pointing and process repeats.
Is this the right approach to deleting an entire list?
I ask this because when I print the list after using this function, it still prints the list. And IIRC freeing something doesn't delete it but only marks it as available so I'm not sure how to tell if this is correct or not.
Your code looks correct.
You're also correct that freeing a list's elements doesn't immediately change the memory they pointed to. It just returns the memory to the heap manager which may reallocate it in future.
If you want to make sure that client code doesn't continue to use a freed list, you could change deleteList to also NULL their NODE pointer:
void deleteList( NODE** head )
{
NODE* temp1 = *head;
/* your code as before */
*head = NULL;
}
It still print the list, because you probably don't set the head pointer to NULL after calling this function.
I ask this because when I print the list after using this function, it still prints the list.
There is a difference between freeing a pointer and invalidating a pointer. If you free your whole linked list and the head, it means that you no longer "own" the memory at the locations that head and all the next pointers point to. Thus you can't garintee what values will be there, or that the memory is valid.
However, the odds are pretty good that if you don't touch anything after freeing your linked list, you'll still be able to traverse it and print the values.
struct node{
int i;
struct node * next;
};
...
struct node * head = NULL;
head = malloc(sizeof(struct node));
head->i = 5;
head->next = NULL;
free(head);
printf("%d\n", head->i); // The odds are pretty good you'll see "5" here
You should always free your pointer, then directly set it to NULL because in the above code, while the comment is true. It's also dangerous to make any assumptions about how head will react/contain after you've called free().
This is a pretty old question, but maybe it'll help someone performing a search on the topic.
This is what I recently wrote to completely delete a singly-linked list. I see a lot of people who have heartburn over recursive algorithms involving large lists, for fear of running out of stack space. So here is an iterative version.
Just pass in the "head" pointer and the function takes care of the rest...
struct Node {
int i;
struct Node *next;
};
void DeleteList(struct Node *Head) {
struct Node *p_ptr;
p_ptr = Head;
while (p_ptr->next != NULL) {
p_ptr = p_ptr->next;
Head->next = p_ptr->next;
free(p_ptr);
p_ptr = Head;
}
free(p_ptr);
}
I have a struct which holds a next pointer to a struct of the same type.
I have the following code which stores the number of the struct that the node pointer stores, frees it, and sets node to the node->next. How is node->next known what it is if free has been called right before it?
double data = node->element;
free(node)
node = node->next;
return data;
However, following the same logic, the following code segfaults. The only difference is that this uses a node and the other just stores the element in its basic data type.
struct node *temp;
temp = node;
free(node);
node = node->next;
return temp;
Why is this happening? And how does the first segment of code work anyway?
Thanks
You shouldn't ever dereference a freed pointer - it is asking for trouble and is likely the source of your segfault. Even if it doesn't segfault, you cannot make any assumptions on the vailidity of the data at that memory address and so it is just not a good thing to do.
You haven't given too many details in your question but why not modify your code slightly to try this order instead
struct node *temp = node->next;
free(node);
return temp;
this way you store the pointer before deleting node and should not get a segfault
As for the first code
double data = node->element;
free(node)
node = node->next;
return data;
why not just replace with
double data = node->element;
free(node)
return data;
as this removes the code that accesses freed memory, and your line
node = node->next;
is practically pointless when in the next line you free node anyway.