Printing C linked list produces memory leak - c

I am using Heapusage, an alternative to Valgrind. When I am printing my linked list in the main function, it produces memory leak (when the printing function is commented, it is all fine). I was trying to find out what is wrong, but the printing function is so simple, that either my heap analyzer is bugged or the problem is so simple, that I can't find it.
typedef struct Point {
int x, y;
struct Point *next;
} Point;
Point *NewPoint(const int x, const int y, Point *head) {
Point *point = (Point *)malloc(sizeof(Point));
point->next = NULL;
point->x = x;
point->y = y;
if (head == NULL) {
head = point;
} else {
Point *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = point;
}
return head;
}
void FreeList(Point *head) {
Point *current = head;
while (current != NULL) {
Point *tmp = current;
current = current->next;
free(tmp);
}
}
void PrintList(Point *head) {
while (head) {
printf("[%d, %d]\n", head->x, head->y);
head = head->next;
}
}
int main() {
Point *head = NULL;
head = NewPoint(2, 3, head);
PrintList(head);
FreeList(head);
return 0;
}

you have no leaks, tested with valgrind-3.14.0.GIT
==13568== Memcheck, a memory error detector
==13568== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==13568== Using Valgrind-3.14.0.GIT and LibVEX; rerun with -h for copyright info
==13568== Command: ./a.out
==13568== [2, 3]
==13568==
==13568== HEAP SUMMARY:
==13568== in use at exit: 0 bytes in 0 blocks
==13568== total heap usage: 2 allocs, 2 frees, 1,040 bytes allocated
==13568==
==13568== All heap blocks were freed -- no leaks are possible
==13568==
==13568== For counts of detected and suppressed errors, rerun with: -v
==13568== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Related

Linkedlist | free(): double free detected in tcache 2 Aborted (core dumped)

I hope someone can help me with this issue.
I'm always getting the error free(): double free detected in tcache 2 Aborted (core dumped) when i try to free the allocated memory of the three nodes.
The code works when i free ìter and only one of the two nodes head or new, but using valgrind shows that there are Heap-leaks and that only 2 allocated memories from 3 were freed. Any advices?
#include <stdlib.h>
#include "linkedlist.h"
#include <string.h>
//adding a new node before the head node
node* add_front(node *head, node *new_node){
new_node -> next = head;
head = new_node;
return head;
}
int main(){
node *head = malloc(sizeof(node));
strcpy(head -> name, "A");
head -> next = NULL;
node *new_node = malloc(sizeof(node));
strcpy(new_node -> name, "B");
head = add_front(head, new_node);
node *iter = head;
//printing all nodes
while(iter != NULL){
printf("%s -> ", iter->name);
iter = iter -> next;
}
free(iter);
free(new_node);
free(head);
return 0;
}
-------------------------------------
//linkedlist.h
typedef struct node_t{
char name[100];
struct node_t *next;
}node;
node* add_front(node* head, node *new_node);
-------------------------------------
//valgrind error
==13290== Memcheck, a memory error detector
==13290== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==13290== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==13290== Command: ./linked
==13290==
B -> A -> ==13290==
==13290== HEAP SUMMARY:
==13290== in use at exit: 112 bytes in 1 blocks
==13290== total heap usage: 3 allocs, 2 frees, 1,248 bytes allocated
==13290==
==13290== 112 bytes in 1 blocks are definitely lost in loss record 1 of 1
==13290== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==13290== by 0x1091C8: main (linkedlist.c:13)
==13290==
==13290== LEAK SUMMARY:
==13290== definitely lost: 112 bytes in 1 blocks
==13290== indirectly lost: 0 bytes in 0 blocks
==13290== possibly lost: 0 bytes in 0 blocks
==13290== still reachable: 0 bytes in 0 blocks
==13290== suppressed: 0 bytes in 0 blocks
==13290==
==13290== For lists of detected and suppressed errors, rerun with: -s
==13290== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
head = add_front(head, new_node); moved *new_node to *head so
free(new_node);
free(head);
frees the same pointer. And since you move *iter to the next the free(iter) will be called on a null.
If you want to free the full tree I suggest you do it in the while loop.
node *curr = null;
while(iter != NULL){
printf("%s -> ", iter->name);
curr = iter;
iter = iter -> next;
free(curr);
}
iter is a pointer to your node
when you free the node it points to, you free iter by default.
if I were you, I would write a function to free the whole list as follows:
/*function to free a list*/
void free_list(node **head){
node * tmp;
while(*head!= NULL){
tmp=*head;
*head=(*head)->next;
free(tmp);
}
return;
}

What is the cause of the memory leak in c?

I was creating a linked list in c and I came across this memory leak. Valgrind is telling that the source of the problem is on line 15 but I still can't see the problem. I feel very stupid not knowing where the problem occurred but it would be nice if you could help me! thanks in advance!
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
typedef struct node
{
int number;
struct node *next;
}
node;
int main(void)
{
node *list = malloc(sizeof(node));
if (list == NULL)
{
return 1;
}
list = NULL;
// create link list
for (int i = 0; i < 3; i++)
{
node *n = malloc(sizeof(node));
if(n == NULL)
{
free(list);
return 1;
}
n->number = i+1;
n->next = NULL;
n->next = list;
list = n;
}
//print link list
for (node *tmp = list; tmp != NULL; tmp = tmp->next)
{
printf("%d - ", tmp->number);
}
printf("\n");
//free link list
while (list != NULL)
{
node *tmp = list->next;
free(list);
list = tmp;
}
}
this is my valgrind output:
==3895== Memcheck, a memory error detector
==3895== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3895== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==3895== Command: ./temp
==3895==
3 - 2 - 1 -
==3895==
==3895== HEAP SUMMARY:
==3895== in use at exit: 16 bytes in 1 blocks
==3895== total heap usage: 4 allocs, 3 frees, 64 bytes allocated
==3895==
==3895== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3895== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3895== by 0x401168: main (temp.c:15)
==3895==
==3895== LEAK SUMMARY:
==3895== definitely lost: 16 bytes in 1 blocks
==3895== indirectly lost: 0 bytes in 0 blocks
==3895== possibly lost: 0 bytes in 0 blocks
==3895== still reachable: 0 bytes in 0 blocks
==3895== suppressed: 0 bytes in 0 blocks
==3895==
==3895== For lists of detected and suppressed errors, rerun with: -s
==3895== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Pointer is just a variable that stores a memory address. You got the memory address with malloc malloc(sizeof(node)) but you put null in it list = NULL and you lost the address. Isn't this what you want?
node** list;
size_t i;
list = malloc(sizeof(node*));
*list = NULL;
for (i = 0; i < 3; i++)
{
node* n = malloc(sizeof(node));
n->number = i + 1;
n->next = *list;
*list = n;
}
/* print node... */
/* release node... free(n) */
free(list);
list = NULL;
It is evident that this allocation of memory
node *list = malloc(sizeof(node));
if (list == NULL)
{
return 1;
}
list = NULL;
is redundant and produces a memory leak because the pointer list is reassigned after the memory allocation. As a result the address of the allocated memory is lost.
Just write
node *list = NULL;
Also in this code snippet
n->number = i+1;
n->next = NULL;
n->next = list;
list = n;
this statement
n->next = NULL;
is redundant.
In the for loop
for (int i = 0; i < 3; i++)
{
node *n = malloc(sizeof(node));
if(n == NULL)
{
free(list);
return 1;
}
//...
you need to free all the allocated memory.
For example
for (int i = 0; i < 3; i++)
{
node *n = malloc(sizeof(node));
if(n == NULL)
{
while ( list )
{
node *tmp = list;
list = list->next;
free( tmp );
}
return 1;
}
//...
To avoid code duplication you could write a separate function that frees the allocated memory. For example
void free_list( node **list )
{
while ( *list )
{
node *tmp = *list;
*list = ( *list )->next;
free( tmp );
}
}
and call it like for example
for (int i = 0; i < 3; i++)
{
node *n = malloc(sizeof(node));
if(n == NULL)
{
free_list( &list );
return 1;
}
//...
Or at the end of the program like
free_list( &list );

C lang "filter map" implementation with free

I'm trying to write very simple function that updates elements of linked list in place while filtering out (and freeing) some of the elements. I've been able to derive this implementation though according to valgrind it contains invalid free as well as memory leak. I wonder what is wrong with the implementation.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct List {
int head;
struct List *tail;
} List;
List *cons(int h, List *tail)
{
List *list = malloc(sizeof(List));
list->head = h;
list->tail = (struct List*) tail;
return list;
}
bool is_odd(int val)
{
return val % 2 != 0;
}
int square(int val)
{
return val * val;
}
void print_list(List *l)
{
while (l) {
printf("item: %d, ", l->head);
l = (List*) l->tail;
}
printf("\n");
}
List *square_odd(List *list)
{
List *new_head = NULL;
List *prev_head = NULL;
while (list != NULL) {
List *next = (List *) list->tail;
if (is_odd(list->head)) {
if (new_head == NULL) new_head = list;
if (prev_head != NULL) prev_head->tail = (struct List*) list;
list->head = square(list->head);
prev_head = list;
} else {
if (next == NULL) {
prev_head->tail = NULL;
}
free(list);
}
list = next;
}
return new_head;
}
int main()
{
List *t = NULL;
List init = {100, NULL};
t = &init;
t = cons(1, t);
t = cons(2, t);
t = cons(3, t);
t = cons(4, t);
t = cons(5, t);
t = cons(6, t);
t = cons(7, t);
t = cons(8, t);
t = square_odd(t);
List *tmp = NULL;
print_list(t);
while(t->tail != NULL) {
tmp = t;
t = (List*) t->tail;
if (tmp != NULL) free(tmp);
}
return 0;
}
valgrind output is:
==17692== Memcheck, a memory error detector
==17692== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==17692== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==17692== Command: ./main
==17692==
==17692== Invalid free() / delete / delete[] / realloc()
==17692== at 0x4835948: free (in /nix/store/wrj8cjkfqzi0qlwnigx8vxwyyfl01lqq-valgrind-3.15.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17692== by 0x40127D: square_odd (in /tmp/linked/main)
==17692== by 0x401371: main (in /tmp/linked/main)
==17692== Address 0x1ffeffeac0 is on thread 1's stack
==17692== in frame #2, created by main (???:)
==17692==
item: 49, item: 25, item: 9, item: 1,
==17692==
==17692== HEAP SUMMARY:
==17692== in use at exit: 16 bytes in 1 blocks
==17692== total heap usage: 9 allocs, 9 frees, 1,152 bytes allocated
==17692==
==17692== LEAK SUMMARY:
==17692== definitely lost: 16 bytes in 1 blocks
==17692== indirectly lost: 0 bytes in 0 blocks
==17692== possibly lost: 0 bytes in 0 blocks
==17692== still reachable: 0 bytes in 0 blocks
==17692== suppressed: 0 bytes in 0 blocks
==17692== Rerun with --leak-check=full to see details of leaked memory
==17692==
==17692== For lists of detected and suppressed errors, rerun with: -s
==17692== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
what is wrong with the implementation.
You are passing the address of init to free. init is a variable with auto storage duration not allocated with malloc, so you can't free it.
Because initially t = &init, then inside the first call to cons you do new_t->tail = t you effectively do new_t->tail = &init. So after all the cons calls the last element in your chain points to &init.
t->tail-> ... ->tail->tail == &init
Inside your loop then you pass address of &init to the free function.
I would say the implementation is actually ok, the allocation of the first element is wrong.
I suggest, just remove the init and create the first chain with malloc too:
int main() {
List *t = cons(100, NULL);
t = cons(1, t);
// the rest unchanged
free(NULL) does nothing. You can replace if (tmp != NULL) free(tmp); with just free(tmp).

How to fill a linked list with elements I already have?

I am trying to create a linked list with elements I have, but I need 24 nodes for this and I don't want to end up like this:
head->next->next->next->next->next->next->next->id = 1;
How can I prevent this?
I tried creating something likes but all nodes(obviously) are pointing the same data.
void init_board(block **head)
{
block temp;
temp.id=0;
temp.name="Start";
temp.price=0;
temp.rent=0;
temp.next = NULL;
*head = &temp;
(*head)->next = NULL;
(*head)->next = (block*) malloc(sizeof(block*));
temp = head->next;
temp.id=1;
temp.name="End";
temp.price=16000;
temp.rent=800;
temp.next = NULL;
}
I am trying to create a linked list with elements I have, but I need 24 nodes for this and I don't want to end up like this:
head->next->next->next->next->next->next->next->id = 1;
How can I prevent this?
updating head (not only *head)
block temp;
...
temp = head->next;
you cannot do that, because temp is s struct but next a pointer
I tried creating something likes but all nodes(obviously) are pointing the same data.
you need to allocate a new cell for all the new element, including for the first you currently put in the stack (never return the address of something saved in the stack)
(head)->next = (block) malloc(sizeof(block*));
this is not what you want, you need to alloc for a block, not for a block *
Example initializing with two cells :
void init_board(block **plast)
{
*plast = malloc(sizeof(block));
(*plast)->id=0;
(*plast)->name="Start";
(*plast)->price=0;
(*plast)->rent=0;
(*plast)->next = malloc(sizeof(block));
plast = &(*plast)->next;
(*plast)->id=1;
(*plast)->name="End";
(*plast)->price=16000;
(*plast)->rent=800;
(*plast)->next = NULL;
}
int main()
{
block * l;
init_board(&l);
}
Of course if you have 20 block to initialize to expanse each case is not practical, may be the values come from a file or an array like that :
#include <stdio.h>
#include <stdlib.h>
typedef struct block {
int id;
const char * name;
int price;
int rent;
struct block * next;
} block;
const block Boards[] = {
{ 0, "Start", 0, 0, NULL },
{ 2, "Intermediate", 123, 456, NULL },
{ 1, "End", 16000, 800, NULL }
};
void init_board(block **plast)
{
for (const block * b = Boards; b != Boards + sizeof(Boards)/sizeof(Boards[0]); ++b) {
*plast = malloc(sizeof(block));
(*plast)->id = b->id;
(*plast)->name = b->name;
(*plast)->price = b->price;
(*plast)->rent = b->rent;
(*plast)->next = NULL;
plast = &(*plast)->next;
}
}
int main()
{
block * blocks;
init_board(&blocks);
/* debug */
for (block * b = blocks; b != NULL; b = b->next)
printf("%d %s %d %d\n", b->id, b->name, b->price, b->rent);
/* free resources */
while (blocks != NULL) {
block * b = blocks;
blocks = blocks->next;
free(b);
}
return 0;
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall l.c
pi#raspberrypi:/tmp $ ./a.out
0 Start 0 0
2 Intermediate 123 456
1 End 16000 800
Execution under valgrind :
pi#raspberrypi:/tmp $ valgrind ./a.out
==6819== Memcheck, a memory error detector
==6819== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6819== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==6819== Command: ./a.out
==6819==
0 Start 0 0
2 Intermediate 123 456
1 End 16000 800
==6819==
==6819== HEAP SUMMARY:
==6819== in use at exit: 0 bytes in 0 blocks
==6819== total heap usage: 4 allocs, 4 frees, 1,084 bytes allocated
==6819==
==6819== All heap blocks were freed -- no leaks are possible
==6819==
==6819== For counts of detected and suppressed errors, rerun with: -v
==6819== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
pi#raspberrypi:/tmp $
struct link
{
int data;
int dataOne;
// data n....
struct link* link;
};
// HeadNode
struct link* pHeadLink = NULL;
//add the link and return the current.
struct link* appendLink()
{
if(pHeadLink == NULL)
{
pHeadLink = (struct link*) malloc(sizeof(struct link));
pHeadLink->link = NULL;
return pHeadLink;
}
struct link *pTempLink = pHeadLink;
while(pTempLink->link != NULL)
{
pTempLink = pTempLink->link;
}
pTempLink->link = (struct link*) malloc(sizeof(struct link));
pTempLink->link->link = NULL;
return pTempLink;
}
// calling function:
int fun()
{
loop() // loop for 24 times.
{
struct link* pFillDataLink = appendLink();
// here you can fill rest the items like below.
pFillDataLink->data = 34;
pFillDataLink->dataOne = 334;
// etc....
}
}

Creating a linked list using recursion

I want to create a linked list using recursion. After executing the code, I get only the value of the first node and rest are not being printed.
#include<stdio.h>
#include<malloc.h>
typedef struct node NODE;
struct node
{
int data;
struct node *next;
} *start=NULL,*ptr;
void display();
int create(int);
int main()
{
int n;
printf("\nEnter the no of node?\t");
scanf("%d",&n);
create(n);
display();
}
int create(int x)
{
if(x==0)
return;
else{
NODE *node;
node=((NODE *)malloc(sizeof(NODE)));
printf("Enter the data:\n");
scanf("%d",&node->data);
node->next=NULL;
if(start==NULL)
{
ptr=start=node;
}
else
{
ptr=node->next;
ptr=node;
}
ptr->next=NULL;
}
create(x-1);
}
void display()
{
NODE *ds;
ds=start;
while(ds!=NULL)
{
printf("%d->",ds->data);
ds=ds->next;
}
}
I think the problem is when i call create(x-1);, but I am not sure.
Is my logic correct? Can someone pin-point my mistake?
Try changing the logic,
int create(int x) {
if (x == 0)
return 0;
else {
NODE *node;
node = ((NODE *) malloc(sizeof (NODE)));
printf("Enter the data:\n");
scanf("%d", &node->data);
node->next = NULL;
if (start == NULL) {
ptr = start = node;
} else {
//ptr = node->next;
ptr->next = node;
ptr = node;
}
ptr->next = NULL;
}
create(x - 1);
}
You are not resetting the head correctly.
Also good to check this implemetation out > http://geeksquiz.com/linked-list-set-1-introduction/
The significant error leading to your problem was your assignment of pointers in create(int). You were assigning the first pointer correctly, but then assigning NULL to all remaining pointers. There are several ways to handle this, but a clean and straightforward way is to only advance ptr=ptr->next within the else block as follows:
if (start == NULL)
{
ptr = start = node;
}
else
{
ptr->next = node;
ptr = ptr->next;
}
You are dynamically allocating memory, so this means you are responsible for tracking its use, preserving a pointer to the starting block of each allocation, and finally freeing the memory when it is no longer in use. Start now. Get in the habit of handling your memory cleanup whenever you allocate, and don't simply rely on the program exit to do it for you. While it may seem trivial now, when you begin handling functions with multiple allocations, etc., if you have not developed good habits in this regard, your code will likely leak memory like a sieve. A simple cleanup function could be nothing more than:
void destroy()
{
if (!start) return;
NODE *ds = start;
while (ds != NULL)
{
NODE *victim = ds;
ds = ds->next;
free (victim);
}
}
The malloc issue. malloc returns the starting address for the block of memory allocated, there is no need to cast the return in C. When you are allocating memory for data types you have just declared, use the variable with sizeof instead of the datatype. e.g.:
NODE *node;
node = malloc (sizeof *node);
instead of
node = malloc (sizeof (NODE));
This will become apparent when dealing with pointers to pointers, etc. It makes far more sense to operate on your variable than it does to remember whether you are allocating for NODE* or NODE**. This is especially true when the allocation is many lines below the declaration in your code or when receiving the pointer in a function argument list.
Additionally, you need to validate the return from malloc each time you allocate memory to insure you haven't exhausted the available memory. e.g.:
NODE *node;
if (!(node = malloc (sizeof *node))) {
fprintf (stderr, "error: virtual memory exhausted\n");
exit (EXIT_FAILURE);
}
Finally, putting it all together, one approach to your problem would be:
#include <stdio.h>
#include <stdlib.h> /* for exit & EXIT_FAILURE */
typedef struct node NODE;
struct node {
int data;
struct node *next;
} *start=NULL,*ptr;
void display();
void create (int);
void destroy();
int main (void)
{
int n;
printf ("\nEnter the no of node: ");
scanf ("%d",&n);
create (n);
display();
destroy();
return 0;
}
void create (int x)
{
if (x == 0) return;
NODE *node;
if (!(node = malloc (sizeof *node))) {
fprintf (stderr, "error: virtual memory exhausted\n");
exit (EXIT_FAILURE);
}
printf ("Enter the data: ");
scanf ("%d",&node->data);
node->next = NULL;
if (start == NULL)
{
ptr = start = node;
}
else
{
ptr->next = node;
ptr = ptr->next;
}
create (x-1);
}
void display()
{
if (!start) return;
NODE *ds = start;
while (ds != NULL)
{
if (ds == start)
printf ("%d", ds->data);
else
printf("->%d", ds->data);
ds = ds->next;
}
printf ("\n");
}
void destroy()
{
if (!start) return;
NODE *ds = start;
while (ds != NULL)
{
NODE *victim = ds;
ds = ds->next;
free (victim);
}
}
Example
$ ./bin/llrecurse
Enter the no of node: 4
Enter the data: 2
Enter the data: 4
Enter the data: 6
Enter the data: 8
2->4->6->8
Use a Memory Checker
Regardless of your platform, it is good to use a memory checker, like valgrind on Linux to check for memory errors and insure you have freed all the memory you have allocated. A memory checker, not only provides a confirmation that all memory has been freed, it will also report on subtle errors in the way you attempt to access the memory you have allocated which can alert you to issues that can bite you later. It is simple to use, simply:
$ valgrind ./bin/llrecurse
==17434== Memcheck, a memory error detector
==17434== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==17434== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==17434== Command: ./bin/llrecurse
==17434==
Enter the no of node: 4
Enter the data: 2
Enter the data: 4
Enter the data: 6
Enter the data: 8
2->4->6->8
==17434==
==17434== HEAP SUMMARY:
==17434== in use at exit: 0 bytes in 0 blocks
==17434== total heap usage: 4 allocs, 4 frees, 64 bytes allocated
==17434==
==17434== All heap blocks were freed -- no leaks are possible
==17434==
==17434== For counts of detected and suppressed errors, rerun with: -v
==17434== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
That should get you started, and if you learn the good habits early, managing memory will be a whole lot easier as you get further into programming in C.
When you're doing this:
ptr=node->next;
ptr=node;
You're loosing your reference to the tail of the list, and therefore not adding node to the list. You should be doing this:
ptr->next = node;
ptr = ptr->next;
This points the next pointer of the current tail to the new node, then moves ptr down to the new tail.
Also, the ptr->next=NULL at the end of the loop is unnecessary, since ptr is now the same as node, and you already did node->next = NULL.
Here is a method
typedef struct Node {
int data;
struct Node *pNext;
} Node;
Write a mkNode to handle malloc
Node *mkNode(int value, Node *pNext) {
Node *pNode = malloc(sizeof(Node));
if (pNode == NULL) {
printf("error");
exit(-1);
}
pNode->data = value;
pNode->pNext = pNext;
return pNode;
};
create linked list
Node *rec_create_list_from_arr(int *arr, int len, int i) {
if (i == len) {
return NULL;
}
return mkNode(arr[i], rec_create_list_from_arr(arr, len, i + 1));
}
free
void freeList(struct Node *head) {
if (head != NULL) {
freeList(head->pNext);
free(head);
}
}
test
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
Node *l = rec_create_list_from_arr(arr, 9, 0);
freeList(l);
return 0;
}
valgrind says it's ok
❯ valgrind --leak-check=full --show-leak-kinds=all ./tmp
==630325== Memcheck, a memory error detector
==630325== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==630325== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==630325== Command: ./tmp
==630325==
123456789
1233456789
1233456789
==630325==
==630325== HEAP SUMMARY:
==630325== in use at exit: 0 bytes in 0 blocks
==630325== total heap usage: 11 allocs, 11 frees, 1,184 bytes allocated
==630325==
==630325== All heap blocks were freed -- no leaks are possible
==630325==
==630325== For lists of detected and suppressed errors, rerun with: -s
==630325== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Resources