C LinkedList - how to free memory? - c

I want to write a small function that shall free the memory of a linked list. The nodes have been created with malloc.
A typical function for this is:
void freeList(struct node* head)
{
struct node* tmp;
while (head != NULL)
{
tmp = head;
head = head->next;
free(tmp);
}
}
My problem is that I receive the following errors and i dont know how to fix them:
warning: assignment from incompatible pointer type tmp = l;
error: 'linked_list' has no member named 'next' l = l -> next;
The declarations are given:
struct node_s {
struct node_s *next;
char msg[MAX_MSG_LEN];
unsigned int time;
};
typedef struct node_s node;
struct linked_list_s {
node *head;
};
typedef struct linked_list_s linked_list;
void list_free(linked_list *l) {
struct node *tmp;
while (l !=NULL) {
tmp = l;
l = l -> next;
free(tmp);
}
}

You need to assign l->head to the tmp variable inside list_free() function and have another variable to store the next node while you free() tmp, like this
void list_free(linked_list *l)
{
struct node *tmp;
struct node *next;
if (l == NULL)
return;
tmp = l->head;
while (tmp != NULL)
{
next = tmp->next;
free(tmp);
tmp = next;
}
}

Related

I'm having a problem creating a linked list [duplicate]

This question already has answers here:
Linked lists - single or double pointer to the head
(3 answers)
What is the reason for using a double pointer when adding a node in a linked list?
(15 answers)
Closed 10 months ago.
#include<stdio.h>
#include<stdlib.h>
void insert_front(struct node* head, int block_number);
void insert_rear(struct node* head, int block_number);
void print_list(struct node* head);
struct node {
int block_number;
struct node* next;
};
int main(void)
{
struct node* list = NULL;
insert_front(list, 10);
insert_rear(list, 20);
insert_front(list, 30);
insert_rear(list, 40);
print_list(list);
return 0;
}
void insert_front(struct node* head, int block_number)
{
struct node* p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = head;
head = p;
return head;
}
void insert_rear(struct node* head, int block_number)
{
struct node* p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = NULL;
if (head == NULL) {
head = p;
}
else {
struct node* q = head;
while (q->next != NULL) {
q = q->next;
}
q->next = p;
}
}
void print_list(struct node* head)
{
struct node* p = head;
while (p != NULL) {
printf("--> %d ", p->block_number);
p = p->next;
}
printf("\n");
}
When I ran it, there was no result at all.
Now, in the insert_front function p->block_number = block_number, a message appears saying that the NULL pointer 'p' is being dereferenced... (The same thing appears in the insert_rear function.)
Could it be that I am declaring the pointer wrong?
Both insert_front and insert_rear need to convey possibly head modification back to the caller, and the caller needs to reap that information. Both should be declared to return struct node *, do so, and the code in main react accordingly. E.g.:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
struct node * insert_front(struct node *head, int block_number);
struct node * insert_rear(struct node *head, int block_number);
void print_list(struct node *head);
struct node
{
int block_number;
struct node *next;
};
int main(void)
{
struct node *list = NULL;
list = insert_front(list, 10);
list = insert_rear(list, 20);
list = insert_front(list, 30);
list = insert_rear(list, 40);
print_list(list);
return 0;
}
struct node *insert_front(struct node *head, int block_number)
{
struct node *p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = head;
head = p;
return head;
}
struct node *insert_rear(struct node *head, int block_number)
{
struct node *p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = NULL;
if (head == NULL)
{
head = p;
}
else
{
struct node *q = head;
while (q->next != NULL)
{
q = q->next;
}
q->next = p;
}
return head;
}
void print_list(struct node *head)
{
struct node *p = head;
while (p != NULL)
{
printf("--> %d ", p->block_number);
p = p->next;
}
printf("\n");
}
Output
--> 30 --> 10 --> 20 --> 40
I leave the memory leaks for you to resolve.
In C all variables are passed by value – if you pass a pointer, then it is copied, too (not the pointed to object, of course...), and function parameters, apart from being initialised from outside, are nothing more than local variables. Thus via head = p; you just assign the local copy of the outside pointer, not the latter itself!
To fix that you have two options:
Return the new head and make the user responsible for re-assigning the returned value to his own head pointer.
Accept the head as pointer to pointer.
With second approach a user cannot forget to re-assign the (potentially) new head, so that's what I'd go with:
void insert_whichEver(node** head, int block_number)
{
// use `*head` where you had `head` before...
}
void demo()
{
node* head = NULL;
insert_front(&head, 1012);
}
And in insert_front drop return head;, a function with void cannot return anything concrete and does not require a return at all (but bare return; can be used to exit a function prematurely).

How to Use Typedef Structure Name with Pointer

I am trying to implement a linked list using the given structure for a bigger project. The structure is defined below:
typedef struct node {
unint32_t size; // = size of the node
struct node * link; // = .next pointer
} * ListNode;
I was able to implement a linked list using struct node *. But when I attempt to use ListNode like in the following program:
typedef struct node {
unint32_t size;
struct node * link;
} * ListNode;
void insert_node (ListNode * head, unint32_t size) {
ListNode new_node = (ListNode) malloc (sizeof(ListNode));
new_node->size = size;
new_node->link = NULL;
if (head == NULL) {
head = &new_node;
}
else {
ListNode current = *head;
while (current->link != NULL) {
current = current->link;
}
current->link = new_node;
}
}
int main (int argc, char const * argv[]) {
ListNode head = NULL;
insert_node (&head, 10);
insert_node(&head, 20);
ListNode ptr = head;
while (ptr != NULL) {
printf ("%d ", ptr->size);
}
printf ("\n");
return 0;
}
I get a segmentation fault. Why is that? It even says that struct node * and ListNode are incompatible pointers/types. I thought they were the same struct just named differently.
A little clarification
typedef struct node {
unint32_t size;
struct node * link;
} *ListNode;
creates a type called ListNode. It is a pointer to a struct node. It is not a struct node
So when you do
sizeof(ListNode)
you get the size of a pointer, not the size of struct node
You needed to do
sizeof(struct node)
A very common thing to do is this
typedef struct node {
uint32_ size;
struct node* link;
} *PListNode, ListNode;
this creates 2 types
PlistNode which is a pointer to a struct node
ListNode which is a struct node
the 'P' is a reminder that this is a pointer
so now you can do
PListNode pn = malloc(sizeof(ListNode));
Since you supply a struct node** (a ListNode*) to insert_node, you need to dereference it to assign to it.
You malloc the size of a struct node* (a ListNode) but you need to malloc the size of a struct node.
You also need to do ptr = ptr->link in the loop in main.
Example:
void insert_node(ListNode* head, uint32_t size) {
// corrected malloc, you don't want the sizeof a pointer but the
// size of a `node`:
ListNode new_node = malloc(sizeof *new_node);
new_node->size = size;
new_node->link = NULL;
if (*head == NULL) { // corrected check (dereference head)
*head = new_node; // corrected assignment
} else {
ListNode current = *head;
while (current->link != NULL) {
current = current->link;
}
current->link = new_node;
}
}
int main() {
ListNode head = NULL;
insert_node(&head, 10);
insert_node(&head, 20);
// the below loop had no exit condition before:
for(ListNode ptr = head; ptr; ptr = ptr->link) {
printf("%d ", ptr->size);
}
printf("\n");
}
Demo

C error: dereferencing pointer to incomplete type linked list

In my c program I creating a singly linked list where we have to insert a node using the prev node, I'm getting this error in my main() function:
Dereferencing pointer to incomplete type ‘struct Node’
I am not sure why is it giving that error.
while((temp->next != NULL) && (temp->next->data < randomNumData)) -- error here
typedef struct _Node
{
int data;
struct Node *next;
} ListNode;
ListNode *newList();
ListNode *insertNode(ListNode *prev, int data);
int main()
{
ListNode *head = newList();
int randomNumData;
ListNode *temp = head;
int i;
for(i = 0; i < 11; i++)
{
randomNumData = random()%1001;
while((temp->next != NULL) && (temp->next->data < randomNumData))
{
temp = temp->next;
}
temp->data = randomNumData;
head = insertNode(temp, randomNumData);
}
printList(head);
}
// returning the head of a new list using dummy head node
ListNode *newList()
{
ListNode *head;
head = malloc(sizeof(ListNode));
if(head == NULL)
{
printf("ERROR");
exit(1);
}
head->next = NULL;
return head;
}
ListNode *insertNode(ListNode *prev, int data)
{
ListNode *temp = prev;
prev->next = temp->next;
temp->next->data = data;
return temp;
}
You are missing underscore when declaring next.
typedef struct _Node
{
int data;
struct _Node *next;
} ListNode;
It looks like you don't have a struct called Node. Import it from other file or just implement it. C is good but it's not a magician so far.

Linked list and pointer to incomplete class type

I'm trying to compare a letter to data part in order to insert it in alphabetical order in linked list, What is wrong with this?
typedef struct{
char data;
struct list_node *next;
}list_node;
typedef struct{
list_node *head;
}list;
I'm trying to do the following:
void input_char(list *my_list, char x)
{
list_node *node = (list_node*)calloc(1, sizeof(list_node));
list_node *tmp = my_list->head;
node->data = x;
if (tmp == NULL)
my_list->head = tmp;
else if (tmp->next == NULL)
{
if (x < tmp->data)
{
node->next = tmp;
my_list->head = node;
}
else
tmp->next = node;
tmp = tmp->next;
}
else
{
if (x < tmp->next->data)
// This following line says "Error, Pointer to incomplete type is not allowed.
{
node->next = tmp->next;
tmp->next = node;
}
tmp = tmp->next;
}
}
Change
typedef struct{
char data;
struct list_node *next;
}list_node;
to
typedef struct list_node{
char data;
struct list_node *next;
}list_node;
Your compiler doesn't know what struct list_node is, so you have to declared it.

error in function that counts the number of times an int appears in a list

I'm trying to count the number of times a given int occurs in a list, but I'm having a difficult time getting my pointers to work. Can someone spot where is my logic failing? Is it because of how I'm implementing the "follows" "->" in the counting function?
//this is in my .h file
typedef struct list_struct LIST;
///// the rest is in my .c file
typedef struct node {
ElemType val;
struct node *next;
} NODE;
struct list_struct {
NODE *front;
NODE *back;
};
//this is my counting function
int lst_count(LIST *l, ElemType x) {
LIST *current = l;
int count = 0;
while (current != NULL) {
if ((current->front->val) == x) count++;
current = current->front->next;
//in the line above I get the following warning:
//"incompatible pointer types assigning to 'LIST*' (aka 'struct list_struct*') from 'struct node*'"
}
return count;
}
Your problem is in the while loop
You are in a list struct, then you do
current->front->next;
Now you are in a NODE type struct, in the next iteration there is no front in NODE.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
struct node *previous;
} NODE;
int lst_count(NODE *l, int x) {
NODE *current = l;
NODE *start = current; /* so that we wont loose the start*/
int count = 0;
while (current != NULL) {
if ((current->val) == x)
count++;
current = current->next;
}
return count;
}
int main()
{
NODE* p = (NODE*)malloc(sizeof(NODE));
NODE* p1 = (NODE*)malloc(sizeof(NODE));
NODE* p2 = (NODE*)malloc(sizeof(NODE));
NODE* start = p;
p->val = 5;
p->next = p1;
p1->next = p2;
p2->next=NULL;
p1->val = 5;
p2->val = 5;
printf("%d", lst_count(start, 5));
}
I got the function to work thanks to your all advises
int lst_count(LIST *l, int x) {
NODE *current = l->front;
int count = 0;
while (current != NULL) {
if ((current->val) == x) count++;
current = current->next;
}
return count;
}

Resources