Difference between free() function with or without malloc - c

This is part of cs50 pset5 speller. Background is that I load a dictionary into a hash table with linked list and check word against the hash table to decide if that word is in the dictionary, after that I unload the hash table.
When I load the dictionary, I used malloc() and free() to insert a node into the linked list. The result of free() here is that it free the memory allocated to a pointer, but it will not remove the pointee (a node inserted into linked list in this case).
Here is my code:
bool load(const char *dictionary)
{
FILE *inputfile = fopen(dictionary, "r");
if (inputfile == NULL)
{
return false;
}
char tempWord[LENGTH+1];
while (fscanf(inputfile, "%s", tempWord) != EOF)
{
//create a tempNode and make sure
node *tempNode = malloc(sizeof(node));
if (tempNode == NULL)
{
return false;
}
strcpy(tempNode->word, tempWord);
tempNode->next = NULL;
//get the index of this word
int index = hash(tempWord);
//move tempNode to the next node in the linked list
if (table[index]->next != NULL)
{
tempNode->next = table[index];
}
table[index]->next = tempNode;
free(tempNode);
word_count ++;
}
fclose(inputfile);
return true;
}
When I unload the dictionary, I used free() again, but this time without calling malloc() at all. So the elements on the linked list can be freed one after another. The result of free() here is that it 'removes' the node from the linked list.
Here is my code:
bool unload(void)
{
for (int i = 0; i < N; i ++)
{
//freeing linked list, we need two tempNode in order to do this
node *tempPtr = table[i];
while (tempPtr != NULL)
{
node *deletePtr = tempPtr;
tempPtr = tempPtr->next; //move the tempPtr to the next element, so we are note losing the linked list
free(deletePtr); //once we moved the tempPtr to the next element, now we can delete where deletePtr is pointing at
}
}
return true;
}
Although my code was compiled and can run without issue, I am very confused of why free() does different things here.
To summarize my questions:
(1)Am I correct to say that: in 'load', free(tempNode) does not 'erase' what tempNode is pointing to (which is a node in a linked list), but only free the memory allocated to tempNode; in 'unload', however, free(deletePtr) 'erase' both deletePtr and what deletePtr is pointing to (which is a node in a linked list)?
(2) If my observation in (1) is correct, why is free() doing different things here? Is that caused by the fact that load called malloc() and unload didn't?
(3) I understand I have to call free() if I called malloc(), but when malloc() isn't called, what does free() do?
=================================
Edit:
After more research, I realized that in load section, it is unnecessary to free() the memory assigned by malloc(). The reason is, in unload section, by free() each node, I will eventually be able to free the memory assigned before.

(1)Am I correct to say that: in 'load', free(tempNode) does not
'erase' what tempNode is pointing to (which is a node in a linked
list), but only free the memory allocated to tempNode;
The object to which tempNode points is not meaningfully distinguished from the memory occupied by the object to which tempNode points. If that is a block of dynamically allocated memory then you must not attempt to access it after freeing it. Any attempt to do so produces undefined behavior.
The question is thus meaningless. There is no conforming way to tell whether the memory in question has been "erased", because you must not attempt to read it. If you do attempt to read it then the program might behave as if the memory had been overwritten in some way, or it might not. And it might do anything else within its power, too. Crashing the program (eventually) is a popular alternative, but by no means a guaranteed one.
in 'unload',
however, free(deletePtr) 'erase' both deletePtr and what deletePtr is
pointing to (which is a node in a linked list)?
See above.
(2) If my observation in (1) is correct [...]
Observation (1) is not correct.
(3) I understand I have to call free() if I called malloc(), but when
malloc() isn't called, what does free() do?
The free() function has undefined behavior (see above) if it is passed a pointer value that is non-null and was not obtained from a memory allocation function, or one that has already been freed.

Related

How a free sucession of pointers?

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

Why did my function to insert a node at the beginning of a linked-list fail the second time?

This is my function to add a new node using double pointer
void insertBefore(node_t **first)
{
node_t *new = NULL;
new = (node_t *) malloc(sizeof(node_t));
new->next = *first;
*first = new;
free(new);
}
If I use it once, everything seems to work fine. However, if I use it again, my linked-list is messed up. I have the output image below (same thing happened to my function to insert node to any position).
I tried to put some very specific part of the code, so if you suspect that I must have been doing something wrong at other parts, please tell me.
Any idea what did I do wrong?
The output image
Just remove free(new);. Since new and *first have same value, freeing new also frees *first.
Refined code:
void insertBefore(node_t **first)
{
node_t *new = malloc(sizeof(node_t)); //don't cast
if(!new)
{
fputs("Don't have enough memory", stderr);
return;
}
new -> next = *first;
*first = new;
}
It because you are freeing the memory.
free(new);
You are just assigning the value to first.
*first=new;
Now first and new will point to same memory position. Then you are freeing that memory. Remove the line free(new);.
You free the node you had just allocated; whenever you attempt to use it, undefined behavior will occur because *first becomes a Dangling Pointer. The address stored in the pointer is no longer valid after the function free() returns.
Your code needs many improvements
You don't need to initialize new to NULL; probably no problem as this would be optimized.
You don't need to cast malloc() or in general void * to any other pointer type.
You don't check that malloc() was successful; you should check that new is not being assigned NULL which would indicate an error.
You MUST NOT free() the newly allocated pointer; you should free() it when you don't need it anymore and not immediately after allocating it.
You really should improve your code formatting. It was completely unreadable in the original post.

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.

Free whole list and set head to NULL

Here's the task. It is given a linked list, free all the memory and set head to NULL.
This is my function:
void free_list(struct Node *node)
{
while (node)
{
free(node);
node=node->next;
}
}
It outputs no error, just wont do anything. And another thing, how to check if the memory was freed ?
Hints at what's going wrong rather than sample code since this is homework...
You can't reliably access node after freeing it. Store the value of node->next before freeing.
You're passing the Node pointer by value. If you want to NULL the caller's pointer, use a pointer to a pointer instead.
There is no portable way to check the memory was freed, but you could investigate tools like valgrind if you want to check that no memory has been leaked when your program exits.
Note that you can't check the contents of memory locations to reassure yourself that the memory has been freed. Calling free merely passes ownership of the memory back to the system; it may get reallocated (and its values updated) at any point in future.
You should get the next node before freeing the current one
If you want to assign to the head, you need to pass its address to the function.
void free_list(struct Node **head)
{
struct node *nnode, *cnode;
cnode = *head;
while (cnode)
{
nnode = cnode->next;
free(cnode);
cnode = nnode;
}
*head = NULL;
}
call it like this..,,
free_list(&head);
EDIT:
You are accessing the same node node=node->next; after freeing it, You must have to store next pointer before freeing the node.

Segmentation Fault when freeing singly linked list from memory

I am relatively new to the idea of pointers and C, so I apologize if this is a really simple problem. I am trying to free a singly linked list from memory that is created. The singly list is created fine, but I am having trouble free it from memory, I get a segmentation fault. Any ideas where I am going wrong? I need to have separate methods for both freelist and freenode. Avail is a global pointer variable and is part of the code that I'm sure works. The problem exists in free list and I'm just not sure where.
void freelist(olnode **list) {
olnode *ptr = *list;
while (*list != NULL) {
ptr = *list
freenode(&ptr);
ptr = ptr->next;
}
}
void freenode(olnode **ptr) {
if(*ptr != NULL) {
(*ptr)->next = avail;
avail = *ptr;
*ptr = NULL:
}
}
Freenode sets the pointer passed to it to NULL. Afterwards freelist tries to dereference the pointer which is now null. That's where the program crashes.
Besides that, your program doesn't really free any data. It just changes the pointers pointing to the data to point to NULL. That means the memory will stay allocated and isn't available for new data. To mark the memory a pointer points to as no longer needed, you need to call the free() method from the standard library on the pointer which points to it. Setting the pointer to NULL afterwards is not needed, but a good practice to make sure that any subsequent try to access the free'ed memory location results in a predictable crash and not in totally unpredictable behavior.
You need to grab the next pointer from the node before freeing it.
Not this:
freenode(&ptr);
ptr = ptr->next;
but this:
olnode *next = ptr->next;
freenode(&ptr);
ptr = next;

Resources