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.
void *as returned bymalloc& friends. C isn not C++! Note also: do not use all-uppercase identifiers for types/variables. They should only be used for macros and _enum-constants_This is one of the few widely accepted naming conventions in C.