How a free sucession of pointers? - c

So I have struct that has two pointer tags inside it: next, which points to a chain of other structs (all linked by pointers their next field as well) and the other one points to the last struct in the chain. I'm trying to free them but somehow I keep getting a core dump due to an invalid free. I'm a new C coder. Is there something I am doing that's obviously wrong?
void free_if(myTik *the){
while(the->endif != NULL){
myTik *eh;
eh = the->next;
the->next = the->next->next;
free(eh);
}
}

i think there is an error in your logic.
You check if 'current node' is NULL or not, but erase 'next' of current node.
the->next = the->next->next;
so above code can be error if
node(current) -> NULL (because the->next is NULL, so the->next->next will corrupt run-time error)
it is better to use 'dummy header' to erase total node in one-way linked-list
void free_if(node header){
while(header->head->next != NULL){
node *eh;
eh = header->head;
header->head = eh->next;
free(eh);
}
//if escape while loop, you get this
//HEADER(dummy) -> node -> NULL;
so, just free it
free(header->head);
}

You simply want to work down you linked-list, node-by-node, saving a copy of the current pointer (the victim to delete) and advancing the pointer you are using to iterate over your list before freeing the memory of the victim node. (you were close, you just had too many ->next thrown in there)
A normal traversal freeing all nodes is:
void free_if (myTik *the)
{
while (the != NULL) {
myTik *victim = the;
the = the->next;
free (victim);
}
}

Related

linked list traversal goes infinitely

I'm trying to implement my own version of malloc() function in c.
I decided to keep track of my allocated blocks using a linked list of meta-data objects that would store some information about the allocated chunk and and place it right before the chunk.
Now long story short while debugging I came across the fact that my linked list is behaving very strangely.
here's a piece of the code to help understanding the problem.
typedef struct meta_data
{
size_t size;
int free;
struct meta_data* next;
}meta_data;
meta_data* global_base;
void *mymalloc(size_t size)
{
if(size > 0)
{
meta_data block_meta;
void* pointer = sbrk(size + block_size);
block_meta.size = size;
block_meta.next = NULL;
block_meta.free = 0;
if(!global_base) //first allocation
{
global_base = &block_meta;
}
else
{
block_meta.next = global_base;
}
return pointer;
}
else
{
return NULL;
}
}
I wrote this code which I assume will append a new item to the tail of my global_base (linked list) every time I call mymalloc(<some_size>);
however when I tried to debug and make sure that my linked list is in order by calling mymalloc() couple of times and check is my linked list is being populated properly
void printList()
{
meta_data * node = global_base;
while (node->next != NULL)
{
printf("%zu", node->size);
printf(" -> ");
node = node->next;
}
printf(" \n ");
}
int main()
{
mymalloc(10);
mymalloc(8);
mymalloc(4);
printList();
return 0;
}
I expected my output to be
10 -> 8 -> 4 however it was 4 -> 4 -> 4 -> 4 -> 4 ..... and goes into an infinite loop
any idea where am I going wrong with this code.
I'm a little new to programming with C so my only guess is that I'm making use of reference & and pointer * improperly.
furthermore I have seen tones of code where the assignment of struct's attribute is happening with the use of -> but I could only use . to make it (could this be the problem anyhow)?
help is appreciated thanks guys
There are multiple problems with your approach:
the meta_data block_meta; is a local variable. You cannot use that to link the blocks. Local variables are reclaimed when the function exits. You should use global memory retrieved from the system with sbrk, pointed to by pointer.
the print loop is incorrect: you should write while (node != NULL) to print all blocks.
Your code has dozens of issues which I will address.
Now the problem with your code, in fact the biggest issue with it is that the myalloc function doesn't create a new block_meta node. It just declares a block_meta variable (which will end up on the stack and even worse is a recipe for disastrous bugs I believe the infinite loop is a result of this). You should you use the sbrk function to create a meta_data node before doing anything like so:
...
meta_data *block_meta = sbrk(sizeof(meta_data));
block_meta->size = size;
block_meta->next = NULL;
block_meta->free = 0;
if(!global_base)
{
global_base = block_meta;
}
The myalloc function checks to see if global_base has been assigned, that is if there is a root node in the linked list. If there is one it should simply tell the current variable to link itself to the global_base that is point it's next variable at global_base, this is a big error. Firstly, the global_base is the root node and it makes no sense to tell the current node to link itself to the root of the linked list, it's supposed to link itself to the next node not the root. Secondly, the reference to the previous node is lost which means it's not a linked list anymore. A proper solution would be saving the current node in a variable using a static variable which prevents it from getting lost when the myalloc function exits:
...
static meta_data *curr;
then right before returning the pointer to the newly allocated block you add this line to hold the node that had been newly created:
...
curr = block_meta;
return pointer;
now return to the erring else statement and change that to to ensure that the previous node points to the current node:
...
else
{
curr->next = block_meta;
}

Delete node from singly linked list and do an operation on it

I am tasked with removing a node from a singly linked list and setting the structure that the node's dataPtr points to, to a new value. I create a structure pointer to hold the data of the popped node. There are 2 cases I want to catch 1) in which this new pointer is null, I want to set it to the popped node 2) if the pointer is not null, I want to do some operations on it.
NODE* printer;
printer = (NODE*) malloc(sizeof (NODE)); //dynamically allocate
if(printer==NULL){ //if it has no data
printer= deleteNode(sList); //call deleteNode function which returns popped node from the passed singly linked list
} else if (printer!=NULL && sList->count!=0) { //if it has data
(((PRINTJOB *) printer->dataPtr)->pageNums) -= PAGESPERMINUTE; //decrement the pageNums field by 1 (PAGESPERMINUTE)
if ((((PRINTJOB *) printer->dataPtr)->pageNums) <= 0) { //if the field is less than 0
printer = NULL; //set pointer back to null
}
printf("printers pageNum is: %d\n", ((PRINTJOB *) printer->dataPtr)->pageNums);
}
My compiler is giving me an error on 4th line: The value is never used.
It is also giving me an error in my else if statement: first condition is always true.
When I run this code block as well, it crashes my program.
My deleteNode function is:
#include "headers.h"
void* deleteNode(LIST* list){
NODE *toDelete;
toDelete = list->head;
list->head = toDelete->next;
return toDelete;
}
my NODE structure is:
typedef struct node{
void* dataPtr;
struct node* next;
} NODE;
I am tasked with removing a node from a singly linked list and setting the structure that the node's dataPtr points to, to a new value.
But you remove the node only conditionally (and on a condition that is unlikely to actually occur). If, as stated, the first step is to remove a node then Remove. That. Node.
I create a structure pointer to hold the data of the popped node.
But you shouldn't. If there is any data available to receive then that's because a node containing it already exists, and your deleteNode() function will return a pointer to it (provided that function is in fact called).
There are 2 cases I want to catch 1) in which this new pointer is null, I want to set it to the popped node
That makes no sense, because it makes no sense to create a new, separate node in the first place. What would make sense would be to check whether deleteNode returns a null pointer, which one imagines it might do if the list were empty (but see below).
if the pointer is not null, I want to do some operations on it.
That could make sense, but not in this context. According to your description, you want to perform operations on the node that was removed from the list (provided that one in fact was removed), but instead you are working on the newly-allocated, uninitialized node.
Based only on your description of the task itself, it sounds like you want something more like this:
NODE* printer = deleteNode(sList);
if (printer != NULL) {
(((PRINTJOB *) printer->dataPtr)->pageNums) -= PAGESPERMINUTE;
if ((((PRINTJOB *) printer->dataPtr)->pageNums) <= 0) {
printer = NULL; //set pointer back to null (?)
}
printf("printers pageNum is: %d\n", ((PRINTJOB *) printer->dataPtr)->pageNums);
} // else nothing to do
But there are other possibilities, depending on how the list is structured and used.
Note that the printer = NULL; line that I copied from your original code is questionable. It may make sense if later code performs a null check on printer before doing yet more processing, and you want to circumvent that. Beware, however, that failing to first free() the node might constitute a memory leak. It looks suspicious in that way, but it is possible that the node really shouldn't be freed there.
Note also, however, that your deleteNode() function appears to be likely to break when it operates on an empty list. In that event, it seems like the only sensible thing it could return is a null pointer. It might well be that list->head is in fact such a pointer in that case, but then
NODE *toDelete;
toDelete = list->head;
list->head = toDelete->next;
will attempt to dereference that null pointer when it evaluates toDelete->next, thus reaping undefined behavior. If in fact you can rely on list->head to be null when the list is empty, then you would want to modify the above something like this:
NODE *toDelete;
toDelete = list->head;
if (toDelete != NULL) {
list->head = toDelete->next;
} // else list->head is already NULL
Again, there are other possibilities depending on how the list is structured and used, but I think the above is probably what you want.

Deleting a node from a doubly linked list

This is my current code which i have messed with so how im dealing with the first item or only item are wrong, which are the first 2 parts to this function. For some reason i am getting memory errors if i just try to set node=node->next_.. i would assume this would be the easiest way but when i throw that back into the program i start getting memory access issues. all other parts work fine as long as i don't manipulate the head address.
void removeNode(struct student_record_node* node)
{
struct student_record_node *temp=NULL;
temp=node;
if(node->next_==NULL&&node->prev_==NULL)
{
node=node->next_
free(node->prev_);
}
else if(node->prev_==NULL&& node->next_!=NULL)
{
node=node->next_
free(node->prev_);
}
else if(node->next_!=NULL && node->prev_!=NULL)
{
node->prev_->next_ = node->next_;
node->next_->prev_ = node->prev_;
student_record_node_deallocate(node);
}
else if(node->prev_!=NULL&& node->next_==NULL)
{
node->prev_->next_=node->next_;
student_record_node_deallocate(node);
}
}
There are several errors:
The node may be the head, so struct student_record_node* should be returned, instead of void.
node may be NULL
if node->prev_ is NULL, make sure to free the node deleted.
Since you did not provide, what your linked list looks like, I am going to assume for my code-example, that it is a struct containing a pointer to the head of the linked list (the first element). It is referred to by your_list.
The problem lies within the first two if-blocks in your code;
The first if: if(!node->next_ && !node->prev_):
This means you are deleting the head-element of the list. In this case, you will have to explicitly set the head to NULL, instead of setting the pointer to the node you wish to delete to NULL (by setting it to its predecessor, which is NULL). Also, you are freeing a NULL-Pointer, by freeing the previous node. This is in it self not a problem, but you want to delete node, not it's predecessor.
The second if: if(!node->prev_ && node->next_):
This means you are deleting the head, but the list will not be empty after the node is deleted. In this case, you must set the head of the list to point to the new head, which will be the node pointed to by node->next_. Also, you have the similar problem with free() as before.
Addressing those two points, your code should do something along the lines of this:
void removeNode(struct student_record_node *node){
if(!node->next_ && !node->prev_){
your_list->head = NULL; // Remove head - List is now empty.
student_record_node_deallocate(node);
node = NULL; // Set freed pointer to NULL, for safety.
}
else if(!node->prev_ && node->next_){
your_list->head = node->next_; // Set the head to the new head.
student_record_node_deallocate(node);
node = NULL; // Set freed pointer to NULL, for safety.
}
else if(node->next_ && node->prev_){
node->prev_->next_ = node->next_;
node->next_->prev_ = node->prev_;
student_record_node_deallocate(node);
node = NULL; // Set freed pointer to NULL, for safety.
}
else if(node->prev_ && !node->next_){
node->prev_->next_ = NULL;
student_record_node_dealocate(node);
node = NULL; // Set freed pointer to NULL, for safety.
}
}

destroy linked list in c with extra deallocating data

i have a linked list in C which i need to destroy by request and keep memory allocation
here's the code :
can someone explain to me what exactly i need to add with the parameter dealloc?
/** Destroy and de-allocate the memory hold by a list
\param list - a pointer to an existing list
\param dealloc flag that indicates whether stored data should also be de-allocated
*/
void dbllist_destroy(dbllist_t *list,dbllist_destroy_t dealloc)
{
dbllist_node_t *current = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
dbllist_node_t *current = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
if(current == NULL || temp == NULL)
return -1;
current = dbllist_tail(list);
while (current != NULL)
{
temp = dbllist_prev(current);
free(current);
current = temp;
dbllist_size(list)--;
}
free(current);
free(temp);
free(list);
return 0;
}
typedef enum { DBLLIST_LEAVE_DATA = 0, DBLLIST_FREE_DATA } dbllist_destroy_t;
So, remaining issues I can see:
the double malloc at the top - all these will do is waste memory. There is no need to be allocing anything here.
dbllist_size(list)-- is meaningless. you are simply getting a value and then reducing it. Presumably you are trying to reduce the stored size of the list. Either dbllist_size returns a pointer to the size (unlikely, but in which case you will need to do (*dbllist_size(list))--)). More likely you will either need to call a dbllist_set_size (if there is one) or (most likely) directly alter the size value (list->size-- or something similar). However, since you are deallocing the entire structure, you could just set size to 0 at the end^1
The point you will want to dealloc the data is just before the free(current) in the middle. Probably it will be something like if (DBLLIST_FREE_DATA==dealloc) { free(dbllist_get_data(current));} (again, depends on the api)
The free(current) after the for loop is not needed, as current must be null at this point.
Checking for null at the top is good, but you are checking the wrong thing. You should be checking if list is null.
You haven't declared temp
[^1]: if you needed destroy to be thread safe then you might want to set the size after freeing each item; in that case you would also want to put a mutex around the inside of the for loop. Also, since this is presumably a double linked list, you would want to updated the last/next pointers as well. Probably this is overkill for you though.

Linked List C code hangs without returning from 'free-ing' function

For a program that I am working on, I have a doubly linked list. I now have to figure out a particular node where a particular data (called id) becomes negative, and then dereference the following nodes and also free the memory. When I call this function (pasted below), the last print statement is executed and prints on screen. However the program doesn't return to main. It simply hangs. (Right after this function call, I have another print statement which doesn't get executed and the program hangs there endlessly).
static void clear_ghosts(particles *plist)
{
particles * temp = plist;
while(temp!=NULL) {
if(temp->p->id < 0)
{
break;
}
temp = temp->next;
}
if(temp)
{
particles * current = temp;
particles * next;
while(current !=NULL)
{
next = current->next;
free(current);
current = next;
}
temp = NULL;
}
printf("\n Finished Clearing \n");
return;
}
Here plist is a linked list of type struct particle *. plist has data p which itself is a struct and has member data like id etc. I need to loop through the list and terminate the list when the member id that is negative is encountered. I am getting the output "Finished Clearing", but the function is not returning to main.
What could be going wrong?
Are you sure all elements you are trying to free() have been allocated with malloc()? If, for example, some of those pointers point to memory on the stack, all kinds of horrible things might happen when you try to free() them.
Since you say its a double-linked list you should set the previous element's next pointer to NULL:
if (temp)
{
if ( temp != plist )
{
temp->prev->next = NULL;
}
...

Resources