A common approach when learning is to add more code and then add more.
Below is the equivalent to your entire program, but done with far fewer lines of code (but lots of comments.)
Please read this and think about what and why of each line.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node { // Using 'typedef' saves LOTS of typing (and reading)
int data; // for now, just one integer
struct Node *next;
} node_t; // conventional naming of a 'type' with "_t" suffix
int mmain() {
int data[] = { 66, 11, 7, 56 }; // your data in compact form
node_t *head = NULL; // ALWAYS initialise variable. Don't let random values happen
for( int i = 0; i < sizeof data/sizeof data[0]; i++ ) { // loop to create LL
// use 'calloc()'. explained below
// do not cast the return pointer from malloc/calloc
node_t *pn = calloc( 1, sizeof *pn );
// malloc/calloc can fail. Halt processing immediately.
if( pn == NULL ) {
fprintf( stderr, "panic! calloc failed.\n" );
exit( 1 );
}
pn->data = data[i]; // for now, just one integer
pn->next = head; // two lines of code "prepend" the new node
head = pn;
// traverse here showing growth
for( pn = head; pn; pn = pn->next )
printf( "%d ", pn->data );
putchar( '\n' );
}
// Avoid memory leaks
// Don't forget to release heap memory when no longer needed.
while( head ) {
node_t *pn = head; // node to be free'd
head = head->next; // remember next
free( pn ); // OFF WITH ITS HEAD!
}
return 0;
}
Output
66
11 66
7 11 66
56 7 11 66
I recommend using calloc() over malloc() when developing code that will grow.
Right now the payload carried by each node is a single integer.
In the thick of it, it is possible to add more elements to the node structure (bigger payload)
yet omit setting every one of the new elements to a known value.
Using calloc() insures that all bytes will consistently be initialised to null.
Then, when testing, you get consistent behaviour (working or not), making it easier to track down bugs.
Notice that "prepending" to a LL is too trivial an operation to "break out" to its own function. "Appending" is not much more difficult, but may justify a function according to your tastes.
Here is the same code again, without comments, for comparison.
typedef struct Node {
int data;
struct Node *next;
} node_t;
int main() {
int data[] = { 66, 11, 7, 56 };
node_t *head = NULL;
for( int i = 0; i < sizeof data/sizeof data[0]; i++ ) {
node_t *pn = calloc( 1, sizeof *pn );
if( pn == NULL ) {
fprintf( stderr, "panic! calloc failed.\n" );
exit( 1 );
}
pn->data = data[i];
pn->next = head;
head = pn;
// traversal for debugging
for( pn = head; pn; pn = pn->next )
printf( "%d ", pn->data );
putchar( '\n' );
}
while( head ) {
node_t *pn = head;
head = head->next;
free( pn );
}
return 0;
}
Even if the program creates new nodes at different locations, you must consider the payload. Don't write a trivial insert() function that adjusts two pointers but receives 27 parameters in the function call.