Memory Management C and free() of pointers - c

so I have some questions on how to do correct memory management.
Basically my question is, what happens when for example I take this code(shown below). Does this need to be freed to prevent memory leaks?
void traverseLeftRight(struct node *head){
current = head;
if(current == NULL){
printf("There are no nodes within the list\n");
}
while(1){
if(current != NULL){
printf("left to right output: %d\n", current -> value);
current = current -> next;
}else{
break;
}
}
}
Also, would free(current) and current = NULL break the list if i were do it within the break section of the list. Also, would something like this just break the pointing variable and not effect the node that it corresponds to?
void traverseLeftRight(struct node *head){
current = head;
if(current == NULL){
printf("There are no nodes within the list\n");
}
while(1){
if(current != NULL){
printf("left to right output: %d\n", current -> value);
current = current -> next;
}else{
free(current);
current = NULL;
break;
}
}
}

I think you are confused about memory management.
In the examples you've shown, there's no need for any freeing, because nothing has (as far as we can see) been allocated.
If you allocate memory with malloc(3) or friends, then you will typically need to free it later, exactly once. In general, failing to free something leaks memory (ie, the memory is still allocated, but you're not pointing to it any more, so can't use it), and freeing more than once is an error (in the sense that this opens the possibility of two bits of the code both believing they've been allocated exclusive use of the same bit of memory). Using a bit of memory (ie, dereferencing a pointer) after it's been freed is the classic ‘use-after-free’ error. Each of these results in somewhat hard-to-find bugs (but valgrind is your friend).
The call to free in your second would (unfortunately) not cause an error, because free doesn't report such errors.
You don't need to free memory if it's in use all the way to the end of the program – that's (in effect) freed automatically when the program finishes.
Almost the only case where you'd call free within a function like this is if you were writing a function to walk along a linked list (or something like that), freeing as it went. A traverse of a list (as your function name suggests) would not be expected to result in the list being freed.

here is your first code, corrected, so an empty list does not enter the 'while()' loop
void traverseLeftRight(struct node *head)
{
current = head;
if(current == NULL)
{ // then list empty
printf("There are no nodes within the list\n");
}
while( current != NULL )
{ // then, another node to print
printf("left to right output: %d\n", current -> value);
current = current->next; // step to next node in list
}
}
here is your second code, with comments
while(1)
{
if(current != NULL)
{ // then, not at end of list
printf("left to right output: %d\n", current -> value);
current = current->next; // step to next entry in list
}
else
{ // else, current == NULL ,, I.E. past end of list
free(current); // nothing will happen because Current == NULL
current = NULL; // already NULL, so nothing will change
break; // exit the 'while()' loop
}
}
proposed code that free's the linked list as it traverses it.
Note that the 'head' needs to be updated as the list is 'free'd
// note the 'pointer to pointer parameter, so 'head' can be modified
void traverseLeftRight(struct node **head)
{
if( *head == NULL)
{ // then, list is empty
printf("There are no nodes within the list\n");
}
while( *head != NULL)
{ // while another node to process
struct node *temp = *head; // remember current node pointer
printf("left to right output: %d\n", current -> value);
*head = (*head)->next; // step to next node
free( temp ); // eliminate current node
}
}

Related

Recursively removing the duplicate elements in a linked list

I was trying to remove the duplicate element in a sorted linked list using recursion concept.
I wanna see how to remove the elements in a sorted linked list. I made a code in which if head->data == head->next->data than head->next should be freed until we get the different element.
Now I have made so many changes I am confused how I am supposed to do it. It is deleting every value that is duplicate and only leaving the one that was only appeared in the entire code only once.
Please also tell me why this code is doing this and also what can wrong with code and if any optimal way possible to do the same thing.
(I am only providing the deleteduplicate function if there is a need to provide the whole code like print the list or insert in the list I will edit it if told).
Thanks.
Node *deleteDuplicates(Node *head) {
if (head == NULL || head->next == NULL) {
return head;
}
if (head->data == head->next->data) {
struct Node *x = head->next;
head->next = head->next->next;
free(x);
return deleteDuplicates(head);
} else
return deleteDuplicates(head->next);
}
Input: 11 11 11 13 13 20
Output: 20
Expected output: 11 13 20
It is deleting every value that is duplicate and only leaving the one value that was only appeared in the entire code only once.
No. It is deleting only duplicate values but you always return pointer to the last node.
if(head==NULL ||head->next==NULL){
return head;
}
You don't need to return the new head, since only duplicates are going to be removed, there is no way head is going to change.
There is no need for recursion in this function. Just iterate in a loop either removing the next element or skipping to the next element:
Node *deleteDuplicates(Node *head) {
if (head != NULL) {
Node *p = head;
while (p->next) {
if (p->next->data == p->data) {
Node *x = p->next;
p->next = x->next;
free(x);
} else {
p = p->next;
}
}
}
return head;
}
You could fix your recursive function, but it should be modified to not return the head node as this prevents tail recursion, therefore requiring a potentially huge amount of stack space. A sufficiently long list would cause a Stack overflow.
Here is a modified recursive function:
void deleteDuplicates(Node *head) {
if (head != NULL && head->next != NULL) {
if (head->data == head->next->data) {
struct Node *x = head->next;
head->next = x->next;
free(x);
deleteDuplicates(head);
} else {
deleteDuplicates(head->next);
}
}
}
The problem in your code is you store the return value of deleteDuplicates into your head pointer, but the function returns the pointer to the last node in the list, not the head node.

Linked lists are not created, why? [CS50 pset4]

I am doing the pset4 of CS50 which basically needs you to create 26 nodes (each node for every letter of the alphabet) and created a linked list within these nodes to connect words from a dictionary.
So, for example, node 0 will store every word of the dictionary that starts with A, node 1 wills store every word of the dictionary that starts with B, etc...
So, here is the main piece of code:
// Insert words into hash table
while (fscanf(file, "%s", word) != EOF)
{
// for every word, we allocate enough memory for a node, that will carry the word
node *new_node = malloc(sizeof(node));
if(new_node == NULL) { printf("could not allocate memory.\n"); return false; }
strcpy(new_node->word, word);
new_node->next = NULL;
if(!hashtable[alphabetPosition(word[0])]){
hashtable[alphabetPosition(word[0])] = new_node;
}
else
{
for(node *ptr = hashtable[alphabetPosition(word[0])]; ptr != NULL; ptr = ptr->next){
hashtable[alphabetPosition(word[0])]->next = new_node;
}
}
}
alphabetPosition() is basically a function that will return the first character of the word.
the main problem is this:
else
{
for(node *ptr = hashtable[alphabetPosition(word[0])]; ptr != NULL; ptr = ptr->next){
hashtable[alphabetPosition(word[0])]->next = new_node;
}
}
Because every thing else is working. The nodes are been created, but the linked lists are not.
I'm pretty sure there is something wrong with this piece of code but I can't seem to understand. If someone could help me (explaining how to solve it), it would help me so much.
Thanks!
The main flaw is: hashtable[index] is only and always pointing to the last node created. I.E. hashtable[alphabetPosition(word[0])]->next is always set to new_node.
The for loop is basically wrong. The program simply needs to point the new_node to the current head of the list (ie hashtable[alphabetPosition(word[0]) and then make new_node the new head.

Link list program crash on malloc

I'm fairly new to C and coding in general so please bear with me. I've been trying to implement a linked list recently and this is the code i came up with
typedef struct something{
int data;
struct something *next;
} thing ;
int main ()
{
thing *head, *current;
head=malloc(sizeof(thing));
puts("head=malloc(sizeof(thing));");
if (head != NULL)
puts("malloc success");
head=NULL;
current=head;
puts("current=head;");
if (current == NULL)
puts("current is NULL");
puts("while");
while (current!=NULL)
{
current = current->next;
}
puts("end while");
current->next=malloc(sizeof(thing));
puts("current->next=malloc(sizeof(thing));");
//free at end of program
}
While the compiler shows 0 errors, when i run the program it only runs until the final malloc part before crashing. It doesnt run the final puts so i will assume it's something to do with the way i'm trying to use malloc.
I'll gladly appreaciate for someone to tell me what im doing wrong.
The problem is that your while loop goes to far. You want to stop when current points to the last element of the list, so you can add to it. But you're going one step further, and stopping when current == NULL. It's then too late to assign to current->next.
First, you need to initialize head->next to NULL.
head = malloc(sizeof(thing));
head->next = NULL;
Get rid of the line:
head = NULL;
as this is overwriting the result of malloc().
Then your while loop needs to test current->next, not current itself:
while (current->next != NULL) {
current = current->next;
}
And when you add the new node, you have to set its next pointer to NULL as well:
current->next = malloc(sizeof(thing));
current->next->next = NULL;
These should fix your problem.
You allocate head and then immediately after few checks point its pointer to NULL
// Allocation here
head=malloc(sizeof(thing));
puts("head=malloc(sizeof(thing));");
// Not a null
if (head != NULL)
puts("malloc success");
// Point to NULL again ???
head=NULL;
Then your current points to head viz NULL again that makes current NULL
current=head;
puts("current=head;");
if (current == NULL)
puts("current is NULL");
and then you dereference current and try to malloc
puts("while");
while (current!=NULL)
{
current = current->next;
}
puts("end while");
current->next=malloc(sizeof(thing)); //current is NULL here NULL->next is invalid
puts("current->next=malloc(sizeof(thing));");

What am I doing wrong in my pop function (queue) C

I have to write a program that implements a queue with all sorts of menu options (which are all done). I'm having trouble with my "pop" function.
My program is a restaurant waiting list for employees. Whenever a customer calls in or comes into the restaurant they are put onto the waiting list. The only way to pop (be seated) is if the customer's status is waiting-in-restaurant. I have correctly written the portion that changes a customer from call-in to waiting in restaurant.
Also, if the group size is bigger than the table size, I'm supposed to go to the next node and check if the next group fits the criteria to be seated.
enum status(WAIT,CALL);
typedef struct restaurant
{
//stuff
}list;
//I call pop in the main as follows:
pop(&head, &tail);
void pop(list** head, list** tail)
{
list* temp = *head;
int tableSize;
if(*head == *tail && *tail == NULL)
{
printf("The queue is empty... exitting program... \n");
exit(EXIT_FAILURE);
}
printf("What is the table size? ");
scanf(" %d", &tableSize);
if(temp->groupSize > tableSize || temp->waitStatus == CALL)
while(temp->groupSize > tableSize || temp->waitStatus == CALL)
temp = temp->nextNode;
else
*head = (*head)->nextNode;
if(*tail == temp)
*tail = (*tail)->nextNode;
free(temp);
}
When I display my output it doesn't delete the node in the instance if it has to skip the first person in the queue. However, it does work when the first person meets the criteria. Why is this?
First, your pop seems to allow items in the middle of the list to be removed. While this is doable, it requires you remember what was pointing to the node popped to ensure it is set to the node that is after the node being popped. There are a number of ways to do this.
Also, your empty() condition is off. head will always be NULL if the list is empty provided you're doing your job right on setting newly added node nextNode members to NULL. The comparison against tail or checking tail for NULL is not needed.
Finally, perhaps you may want to consider returning the data from the pop if there was any, and a boolean condition of true/false as the function return result to indicate whether something was taken off. Otherwise, how is your program to know data was retrieved successfully, and what that data was?
Regardless, just using your current mantra of deleting something that matches:
void pop(list** head, list** tail)
{
list *temp = NULL, *prior = NULL;
int tableSize = 0;
if(*head == NULL)
{
printf("The queue is empty... exitting program... \n");
exit(EXIT_FAILURE);
}
printf("What is the table size? ");
scanf(" %d", &tableSize);
temp = *head;
while (temp && (temp->groupSize > tableSize || temp->waitStatus == CALL))
{
prior = temp;
temp = temp->nextNode;
}
if (temp)
{
// only way prior is set is if temp is NOT
// pointing to the first node, therefore *head
// is not changed.
if (prior)
{
prior->nextNode = temp->nextNode;
// if we made it to the tail ptr, then it needs
// to be moved back to the prior node
if (*tail == temp)
*tail = prior;
}
else
{ // first node was removed. so move head to
// the next node (which may be NULL)
*head = temp->nextNode;
}
// release the node
free(temp);
}
}

How to check if free(node) works

Here is the code for freeing the whole linked list
void free_list(RecordType *list)
{
RecordType *tempNode; /* temporary Node to hold on the value of previous node */
while(list != NULL) /* as long as the listnode doesn't point to null */
{
tempNode = list; /* let tempNode be listNode in order to free the node */
list = list->next; /* let list be the next list (iteration) */
free(tempNode); /* free the node! */
}
}
I think this code itself is working ok (?), but I have no idea how to check.
I only applied the theory (e.g. # of frees must = to the # of mallocs)
So here are some questions that I'm wondering...
Does this method work?
Do I need to malloc tempNode?
I initialized tempNode before while loop... but after I free, tempNode still works... I don't really get that part
The theory that I used:
# of free() == # of malloc()
You need a temporary node to hold the current node
Let the current node equal to the next node
Free the current node by using the temporary node
If any of my theory sounds wrong, please explain!
Thanks!
Does this method work?
Yes, assuming the list nodes were all dynamically allocated and haven't been previously freed
Do I need to malloc tempNode?
You don't need to allocate any memory inside free_list but all list elements must have been dynamically allocated previously. You can only call free on memory that was allocated using malloc (or calloc)
I initialized tempNode before while loop... but after I free, tempNode
still works... I don't really get that part
Calling free returns ownership of memory to the system. It may choose to reuse this memory immediately or may leave it untouched for some time. There's nothing to stop you accessing the memory again but the results of reading or writing it are undefined.
If you want to make it harder for client code to accidentally access freed memory, you could change free_list to NULL their pointer
void free_list(RecordType **list)
{
RecordType *tempNode;
while(*list != NULL) {
tempNode = *list;
list = tempNode->next;
free(tempNode);
}
*list = NULL;
}
If you also want to check that you really have freed all memory, look into using valgrind. This will report any memory leaks and also flags some types of invalid memory access.
The method certainly works - but it should be mallocd first before freeing. Otherwise it is undefined behavior.
You don't need to malloc() tempNode only if list has been previously malloc()d.
The third part is undefined behavior. After free() the data may still exist, but is flagged for being overwritten. You cannot rely on the node once it is free()d
The best way to check your code is interactive tracing by means of Debugger. Gdb in KDevelop on Linux or MS Visual Studio's debugger on MS Windows are perfect. I'll use the later for this demonstration.
This code defines a uni-directed list of integers with three functions: ListPush() adds an integer to the list, ListPrint() displays the list contents and ListDestroy() destroys the list. In main() I insert 3 integers into the list, print them and destroy the list.
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct Node NODE, *PNODE;
typedef struct Node {
int item;
PNODE next;
};
PNODE ListPush(PNODE head, int item) {
PNODE p;
PNODE n = (PNODE) malloc(sizeof(NODE));
if ( !n ) exit(1);
n->next = 0;
n->item = item;
if (!head) {
head = n;
}
else {
for ( p=head; p->next != 0; p=p->next );
p->next = n;
}
return head;
}
void ListPrint(PNODE head) {
PNODE p;
printf("List contents:\n\n");
for (p=head; p!=0; p=p->next) {
printf("%d ", p->item );
}
}
void ListDestroy( PNODE head ) {
PNODE n, c = head;
if ( !head ) return;
do {
n = c->next;
free(c);
c = n;
} while (c );
}
int main() {
int i;
int a[3] = {1,2,3};
PNODE head = 0;
for ( i = 0; i<3; ++i ) {
head = ListPush(head, a[i]);
}
ListPrint(head);
ListDestroy(head);
return 0;
}
Three attached images illustrate 2 stages of the program (MSVS2012 Debugger).
The first shows state of relevant local vars after for() cycle finishes. Look at head variable and proceed on the tree. You can see three nodes with their contents: integers 1,2 and 3 respectively.
The second image shows the variables inside ListDestroy() after first call to free(). You can see that head points to freed memory (red circles) and pointer in variable c points to the next node being destroyed on the next loop.

Resources