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)
Related
In the example below, I created a linked list and I can add numbers successfully. However, at the
end of the execution, the function named "traverse" does not work. How can I fix this error?
Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
struct node
{
int data;
struct node*prev;
struct node*next;
};
void add( node*head,int number )
{
node*ptr = NULL;
if( head == NULL )
{
head = (node*)malloc(sizeof(node));
head->data = number;
head->next = NULL;
head->prev = NULL;
ptr = head;
}
else
{
ptr->next = (node*)malloc(sizeof(node));
ptr->next->prev = ptr;
ptr = ptr->next;
ptr->data = number;
ptr->next = NULL;
}
}
void traverse( node* head )
{
while( head != NULL )
{
printf("%d ",head->data);
head = head->next;
}
}
int main( void )
{
node *head = NULL;
int number;
char response;
printf("%s\n","Do you want to enter a number in linked list(y/n)?" );
scanf("%c",&response);
while( response == 'y' || response == 'Y' )
{
printf("\nEnter num..> ");
scanf("%d",&number);
add(head,number);
printf("%s\n","Do you want to continue(y/n)?" );
response = getche();
}
printf("\nYour doubly linked list\n");
traverse(head);
getch();
return 0;
}
when "traverse" is called, the console print space like the following image.
If you have decided on C, then continuing from the comments, you are attempting to update a local copy of the pointer head in add(). As mentioned, you have two option, either change the return type of add() to node *add() so you can return ptr and assign as the new head back in main(), or pass the address of head as the first parameter and update the node stored at the original pointer address in add().
You can pass the address of head to add() as follows:
void add (node **head, int number)
{
node *ptr = malloc (sizeof *ptr);
if (!ptr)
return;
ptr->data = number; /* initialized new node data */
ptr->prev = ptr->next = NULL; /* initialized both pointers NULL */
if ( *head != NULL ) { /* if not 1st node */
(*head)->prev = ptr; /* Forward-Chain new node */
ptr->next = *head;
}
*head = ptr; /* set head = new node */
}
(note: since you pass the address of head as a parameter, you must remove one level of indirection from the pointer-to-pointer in add() by dereferncing head (e.g. *head) in order to update the node at the original pointer address. You also need to use the (*head) when further derferencing the pointer with -> due to C operator precedence -- so you get the original pointer address before -> is applied)
Note, the add() function uses a method call Forward-Chaining to add each node to the list in O(1) time. This also means the list will hold the numbers in the reverse order they were entered (last first). You have two options to insert in-order, (1) iterate to the end of the list each time and add a new end node (highly inefficient for large lists, no longer O(1) time, or (2) use another tail pointer that always points to the last node to allow in-order insertions in O(1) time.
You would then call your add() function in main() with
add (&head, number);
Do NOT make things difficult on yourself when testing your list implementation. There is no reason to have to type 'y' then a number and 'y' again before every number you add to your list (that would drive me nuts...). Just add numbers to your list with a loop, you can do input later, e.g.
int main (void)
{
node *head = NULL; /* list pointer initialized NULL */
for (int i = 0; i < 20; i++) /* just add 20 nodes to list */
add (&head, i + 1);
traverse (head);
delete_list (head);
head = NULL;
/* hold terminal open on windows only */
#if defined (_WIN32) || defined (_WIN64)
getchar();
#endif
}
(note: conio.h has been removed and getchar() used to hold the terminal open on windows. Since I'm on Linux, the final getchar() is not compiled as part of my executable)
Your traverse() function will work, but get in the habit of using a separate separate pointer to iterate over you list. This isn't always required, and isn't needed in traverse() since you can use the local copy of head, but always using a temporary pointer to iterate with leave you with the original head address if you need it for use later in your function, e.g.
void traverse (const node *head)
{
const node *iter = head; /* optional, but good practice */
while (iter) {
printf ("%d ", iter->data);
iter = iter->next;
}
putchar ('\n');
}
Notice also the delete_list() function added to free() all memory added for your list. You won't always be declaring lists in main() where the memory is freed on exit. Get in the habit of keeping track of the memory you allocate and freeing the memory before your pointer goes out of scope (otherwise, you will create a memory leak)
The full program would be:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *prev, *next;
} node;
void add (node **head, int number)
{
node *ptr = malloc (sizeof *ptr);
if (!ptr)
return;
ptr->data = number; /* initialized new node data */
ptr->prev = ptr->next = NULL; /* initialized both pointers NULL */
if ( *head != NULL ) { /* if not 1st node */
(*head)->prev = ptr; /* Forward-Chain new node */
ptr->next = *head;
}
*head = ptr; /* set head = new node */
}
void traverse (const node *head)
{
const node *iter = head; /* optional, but good practice */
while (iter) {
printf ("%d ", iter->data);
iter = iter->next;
}
putchar ('\n');
}
void delete_list (node *head)
{
node *iter = head;
while (iter) {
node *victim = iter;
iter = iter->next;
free (victim);
}
}
int main (void)
{
node *head = NULL; /* list pointer initialized NULL */
for (int i = 0; i < 20; i++) /* just add 20 nodes to list */
add (&head, i + 1);
traverse (head);
delete_list (head);
head = NULL;
/* hold terminal open on windows only */
#if defined (_WIN32) || defined (_WIN64)
getchar();
#endif
}
Example Use/Output
$ ./bin/llmess
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/llmess
==16661== Memcheck, a memory error detector
==16661== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16661== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16661== Command: ./bin/llmess
==16661==
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
==16661==
==16661== HEAP SUMMARY:
==16661== in use at exit: 0 bytes in 0 blocks
==16661== total heap usage: 21 allocs, 21 frees, 1,504 bytes allocated
==16661==
==16661== All heap blocks were freed -- no leaks are possible
==16661==
==16661== For counts of detected and suppressed errors, rerun with: -v
==16661== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
I wanted to write a program that removes all occurrences of a number from a simple linked list using recursion, so I tried but I had problem: the program that I have written erases all the occurrences in the list but it does not delete the one that exists at the beginning (the occurrence that exists at the first node), here is the code in C:
typedef struct list {
int data;
struct list *next;
} list;
list *delete(int x, list *head) {
if (head->next == NULL)
return head;
list *newnode = delete(x, head->next);
if (newnode->data == x) {
head->next = head->next->next;
free(newnode);
}
return head;
}
I wish someone can help me to improve my algorithm, THANKS IN ADVANCE.
There are multiple problems in the code:
You dereference head without first checking if it is NULL. The function cannot handle empty lists.
You explicitly return the head node without testing its value if the list has a single element.
You only test the second element of the list after recursing on head->next. Hence the first element is never tested.
Here is a modified version that just tests the first node and recurses for the rest of the list:
list *delete(int x, list *head) {
if (head == NULL)
return head;
if (head->data == x) {
list *node = head;
head = head->next;
free(node);
return delete(x, head);
}
head->next = delete(x, head->next);
return head;
}
This code:
if(head->next == NULL)
return head;
explicitly makes the function return any 1-element list unchanged. That creates the problem you describe, so that makes no sense to have there.
I guess it should be possible to formulate the deletion of a list element recursively, although it certainly is not a common/typical/good way to do it.
This might work, not tested:
list * delete(list *head, int value)
{
if (head == NULL)
return NULL;
if (head->data == value)
{
list * tail = head->next;
free(head);
return delete(tail, value);
}
// List was not empty and did not start with the value,
// so set the tail of the list to the tail without the value.
head->next = delete(head->next, value);
return head;
}
without it manages to delete the one that exists at the beginning (the occurrence that exists at the first node),
this is because of these lines :
if(head->next == NULL)
return head;
when there is only one element you return without managing the fact it can contains the data to remove
You do not need to have a recursive definition of delete, and worst using non terminal recursion.
Can be also adding working functions to check the execution :
#include <stdio.h>
#include <stdlib.h>
typedef struct list {
int data;
struct list* next;
} list;
list* delete(int x, list* head)
{
list ** p = &head;
while (*p != NULL) {
if ((*p)->data == x) {
list * d = *p;
*p = (*p)->next;
free(d);
}
else
p = &(*p)->next;
}
return head;
}
void print(list * l)
{
if (l == NULL)
puts("<empty>");
else {
do {
printf("%d ", l->data);
l = l->next;
} while (l != NULL);
putchar('\n');
}
}
list * make(int data, list * next)
{
list * l = malloc(sizeof(list));
l->data = data;
l->next = next;
return l;
}
int main(int argc, char ** argv)
{
list * head = make(1, make(2, make(1, NULL)));
print(head);
head = delete(1, head);
print(head);
head = delete(2, head);
print(head);
return 0;
}
Compilation and execution:
/tmp % gcc -Wall l.c
/tmp % ./a.out
1 2 1
2
<empty>
/tmp %
Under valgrind :
/tmp % valgrind ./a.out ==14732== Memcheck, a memory error detector
==14732== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==14732== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==14732== Command: ./a.out
==14732==
1 2 1
2
<empty>
==14732==
==14732== HEAP SUMMARY:
==14732== in use at exit: 0 bytes in 0 blocks
==14732== total heap usage: 3 allocs, 3 frees, 48 bytes allocated
==14732==
==14732== All heap blocks were freed -- no leaks are possible
==14732==
==14732== For counts of detected and suppressed errors, rerun with: -v
==14732== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
/tmp %
I have written a code in C language to implement a stack using LinkedList algorithm. Here is the code........
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
struct listNode {
int data;
struct listNode *next;
};
struct stack{
struct stack *top;
};
struct stack *createstk(){
struct stack *stk;
stk=malloc(sizeof(struct stack));
stk->top=NULL;
return stk;
}
void push(struct stack *stk,int data){
struct listNode *temp;
temp=malloc(sizeof(struct listNode));
if(!temp){
printf("heap overflow");
return;
}
temp->data=data;
temp->next=stk->top;
stk->top=temp;
}
int pop(struct stack *stk){
if(isEmpty(stk))
return INT_MIN;
int data;
struct listNode *temp;
temp= stk->top;
stk->top=stk->top->next;
data=temp->data;
delete(temp);
return data;
}
int peek(struct stack *stk){
if(isEmpty(stk))
return INT_MIN;
return stk->top->data;
}
int isEmpty(struct stack *stk){
return stk->top==NULL;
}
void deleteStack(struct stack *stk){
struct listNode *temp,*p;
p=stk->top;
while(p){
temp=p->next;
p=p->next;
free(temp);
}
free(stk);
}
int main(){
int i=0;
struct stack *stk=createstk();
for(i=0;i<=10;i++)
push(stk,i);
printf("Top Element is %d",peek(stk));
for(i=0;i<=10;i++){
printf("popped element is %d",pop(stk));
}
if(isEmpty(stk))
printf("stack is empty");
else
printf("stack is not empty");
deleteStack(stk);
return 0;
}
[warning]assignment from incompatible pointer type.
As you can see above in the picture. I am a newbie in coding world and facing this error first time. That's why I don't know what to do. Please tell me...
The field top in the type stack has the wrong type. Change
struct stack {
struct stack *top;
};
to
struct stack {
struct listNode *top;
};
Your have a large number of error beginning with the incorrect type for stack->top, as correctly noted by August Karlstrom your type for the member top must be struct listNode *top;, e.g.
struct stack {
struct listNode *top;
};
Following the correction, you must either reorder your functions or provide function prototypes for isEmpty() and deleteStack(). Moving them up in your code before before their first use will solve the problem, e.g.
struct stack *createstk()
{
struct stack *stk;
stk = malloc (sizeof (struct stack));
stk->top = NULL;
return stk;
}
int isEmpty (struct stack *stk)
{
return stk->top == NULL;
}
void deleteStack (struct stack *stk)
{
struct listNode *temp, *p;
p = stk->top;
while (p) {
temp = p->next;
p = p->next;
free (temp);
}
free (stk);
}
...
Next, this is C, not C++ there is no delete function to free memory, so in pop(), you must call free (temp); instead of delete (temp);.
Finally, provide spacing to make your code readable. Incorporating the above, you could do the following:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
struct listNode {
int data;
struct listNode *next;
};
struct stack {
struct listNode *top;
};
struct stack *createstk()
{
struct stack *stk;
stk = malloc (sizeof (struct stack));
stk->top = NULL;
return stk;
}
int isEmpty (struct stack *stk)
{
return stk->top == NULL;
}
void deleteStack (struct stack *stk)
{
struct listNode *temp, *p;
p = stk->top;
while (p) {
temp = p->next;
p = p->next;
free (temp);
}
free (stk);
}
void push (struct stack *stk, int data){
struct listNode *temp;
temp = malloc (sizeof *temp);
if (!temp) {
perror ("push()-malloc-temp");
return;
}
temp->data = data;
temp->next = stk->top;
stk->top = temp;
}
int pop(struct stack *stk){
int data;
struct listNode *temp;
if (isEmpty(stk))
return INT_MIN;
temp = stk->top;
data = temp->data;
stk->top = stk->top->next;
free (temp);
return data;
}
int peek(struct stack *stk){
if(isEmpty(stk))
return INT_MIN;
return stk->top->data;
}
int main (void) {
int i=0;
struct stack *stk=createstk();
for (i = 0; i <= 10; i++)
push(stk,i);
printf("Top Element is %d\n",peek(stk));
for (i = 0; i <= 10; i++)
printf (" popped element is %d\n",pop(stk));
if (isEmpty(stk))
printf ("stack is empty\n");
else
printf ("stack is not empty\n");
deleteStack(stk);
return 0;
}
Example Use/Output
$ ./bin/stack_ll
Top Element is 10
popped element is 10
popped element is 9
popped element is 8
popped element is 7
popped element is 6
popped element is 5
popped element is 4
popped element is 3
popped element is 2
popped element is 1
popped element is 0
stack is empty
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/stack_ll
==25935== Memcheck, a memory error detector
==25935== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==25935== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==25935== Command: ./bin/stack_ll
==25935==
Top Element is 10
popped element is 10
popped element is 9
popped element is 8
popped element is 7
popped element is 6
popped element is 5
popped element is 4
popped element is 3
popped element is 2
popped element is 1
popped element is 0
stack is empty
==25935==
==25935== HEAP SUMMARY:
==25935== in use at exit: 0 bytes in 0 blocks
==25935== total heap usage: 12 allocs, 12 frees, 184 bytes allocated
==25935==
==25935== All heap blocks were freed -- no leaks are possible
==25935==
==25935== For counts of detected and suppressed errors, rerun with: -v
==25935== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
If you have any further questions, just let me know.
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)
As my many previous posts show, I am making a code to simulate a crazy 8's card game. I have a delete node function that is meant to delete the card from the deck being played. It works for cards after the first, but every time i try to delete the first card (node) from the list it will not delete and then messes up the whole program after it. Here is the function:
void deleteNode(card *head, int coordinate) {
card *current = head;
card *temp = NULL;
temp = current;
int count = 1;
while (head != NULL) {
if (coordinate == 0) {
current = current->listp;
free(temp);
break;
}
else if (count == coordinate) {
temp = current->listp;
current->listp = current->listp->listp;
free(temp);
break;
}
else {
count++;
current = current->listp;
}
}
}
The *head passed into it is the top of the hand being played. The coordinate is the number of card the user wants to play. For example, if the first card in their deck is Q of Hearts and that's what they want to play, they would enter one. In the function call, I subtract one from the user choice so it will match up with the list (since the list starts at 0). Any help would be appreciated. I can't move on with my project until I get this problem resolved!
As mentioned in the comments, the problem you are running into is due to not passing the address-of the list to the deleteNode function. The problem is basic, but it catches a lot of people. The address of a linked-list, is the address of the first node. So when deleting the first node, you must set a new list address to the next node address in order for the list to continue to operate.
When you pass a pointer to a function, e.g. void deleteNode(card *head, ..., the function deleteNode receives a copy of the pointer head. The copy has an address all its own and that address has no relation to the address of the pointer back in the calling function. The value of the pointer is the same in deleteNode as it is in the caller, but the address is completely different.
The problem occurs when you delete the first node in deleteNode. The memory is free'd, and the deleteNode function returns. Now back in the caller (presumably main()), the next time you attempt to access head -- bam! segfault. Why? The address for head was never updated in main, so it still points to the original node -- and what did you just do to the memory for the original node in deleteNode? (you called free on a pointer that pointed to the block of memory holding the first node -- its gone...)
To fix the problem, simply pass the address-of the list (head) to deleteNode. (e.g. void deleteNode(card **head, ...). Then you are operating on the address of head (e.g. a pointer-to-the-pointer-head). Now before deleting the first node you can set *head = head->listp; and have the new list address reflected back in the calling function (main()). For example, your code could be written as:
void delnode (card **head, int coordinate)
{
card *current = *head;
card *victim = NULL;
victim = current;
int count = 1;
while (current != NULL) {
if (coordinate == 0) {
*head = current->listp;
free (victim);
break;
}
else if (count == coordinate) {
victim = current->listp;
current->listp = current->listp->listp;
free (victim);
break;
}
else {
count++;
current = current->listp;
}
}
}
However, you can make a few improvements to the logic of the function, with minimal effort. e.g.
void delnode (card **head, int coordinate)
{
card *current = *head;
card *victim = current;
int count = 1;
if (coordinate == 0) {
*head = current->listp;
free (victim);
return;
}
while (current != NULL)
{
if (count == coordinate) {
victim = current->listp;
current->listp = current->listp->listp;
free (victim);
return;
}
count++;
current = current->listp;
}
}
Lastly, visit the links describing How to Ask a Question and How to create a Minimal, Complete, and Verifiable example. Providing the necessary details, including your code, and associated errors, if any, will allow everyone here to help you with your question.
This question is a perfect example. For anyone to help you and actually compile and confirm the problem or answer, you are asking the folks here to write a sample program that makes an educated guess at what your underlying list structure presumably is. When you ask a question here, the purpose of providing a MCVE is so that others may compile your code and confirm the problem you are having, and if need be, run the compiled code through a debugger in order to help you. You will get much more help and much more of a positive response if you follow the minimal suggestions and rule of the site that are there to help us help you.
That being said, you can confirm the operation of your delete with this small bit of sample code.
#include <stdio.h>
#include <stdlib.h>
typedef struct card {
int cardno;
struct card *listp;
} card;
card *createnode (int c);
card *insert (card **list, int c);
void prnlist (card *list);
void delnode (card **head, int coordinate);
void dellist (card *list);
void *xcalloc (size_t nmemb, size_t sz);
int main (void) {
card *list = NULL;
insert (&list, 18); /* insert test nodes */
insert (&list, 6);
insert (&list, 54);
insert (&list, 12);
insert (&list, 60);
insert (&list, 30);
printf ("\noriginal list:\n");
prnlist (list);
printf ("\ndeleting node: 2\ndeleting node: 0\n");
delnode (&list, 2); /* delete 3rd & 1st nodes */
delnode (&list, 0);
printf ("\nfinal list:\n");
prnlist (list);
dellist (list); /* free allocated memory */
return 0;
}
card *createnode (int c)
{
card *node = xcalloc (1, sizeof *node);
node->listp = NULL;
node->cardno = c;
return node;
}
card *insert (card **list, int c)
{
card *iter = *list;
card *node = createnode (c);
if (!*list) { /* add 1st node to list */
*list = node;
return *list;
}
/* insert all other nodes at end */
for (; iter->listp; iter = iter->listp) {}
iter->listp = node;
return *list;
}
void prnlist (card *list)
{
card *iter = list;
for (; iter->listp; iter = iter->listp)
printf (" cardno : %d\n", iter->cardno);
printf (" cardno : %d\n", iter->cardno);
}
void delnode (card **head, int coordinate)
{
card *current = *head;
card *victim = current;
int count = 1;
if (coordinate == 0) {
*head = current->listp;
free (victim);
return;
}
while (current != NULL)
{
if (count == coordinate) {
victim = current->listp;
current->listp = current->listp->listp;
free (victim);
return;
}
count++;
current = current->listp;
}
}
void dellist (card *list)
{
card *iter = list;
while (iter) {
card *victim = iter;
iter = iter->listp;
free (victim);
}
}
void *xcalloc (size_t nmemb, size_t sz)
{
void *memptr = calloc (nmemb, sz);
if (!memptr) {
fprintf (stderr, "xcalloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
return memptr;
}
Example Use/Output
$ ./bin/lldelcard
original list:
cardno : 18
cardno : 6
cardno : 54
cardno : 12
cardno : 60
cardno : 30
deleting node: 2
deleting node: 0
final list:
cardno : 6
cardno : 12
cardno : 60
cardno : 30
Memory Error Check
In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an unintitialized value and finally to confirm that you have freed all the memory you have allocated.
For Linux valgrind is the normal choice. There are many subtle ways to misuse a new block of memory. Using a memory error checker allows you to identify any problems and validate proper use of of the memory you allocate rather than finding out a problem exists through a segfault. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/lldelcard
==9094== Memcheck, a memory error detector
==9094== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==9094== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==9094== Command: ./bin/lldelcard
==9094==
original list:
cardno : 18
cardno : 6
cardno : 54
cardno : 12
cardno : 60
cardno : 30
deleting node: 2
deleting node: 0
final list:
cardno : 6
cardno : 12
cardno : 60
cardno : 30
==9094==
==9094== HEAP SUMMARY:
==9094== in use at exit: 0 bytes in 0 blocks
==9094== total heap usage: 6 allocs, 6 frees, 96 bytes allocated
==9094==
==9094== All heap blocks were freed -- no leaks are possible
==9094==
==9094== For counts of detected and suppressed errors, rerun with: -v
==9094== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
Always confirm All heap blocks were freed -- no leaks are possible and equally important ERROR SUMMARY: 0 errors from 0 contexts.
Good luck with your coding.