简体   繁体   中英

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/

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 .

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. eg:

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. eg:

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.

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM