Maybe one reason of this seem to be difficult is that
typedef struct {
int info;
struct node* next;
}node;
is the definition of a Node and not the definition of a linked list. More on that below.
But node* head = NULL; declares head as a pointer to node, a structure representing a single node of a list. Inside node, info is the data part, and could be anything, like a pointer to a giant useful structure of data. In this case, just a number. And next is the
link part, and will point to the next node on your list.
In your program, as a pointer to node, head can point to a structure like that, having a data part, the info field, and a pointer to another node, the next field. Sometimes there is also a pointer to the previous node too, and it is said to be a double linked list for obvious reasons.
But this is not a linked list in itself. Just a pointer to a node, and it is now pointing to nothing since it has been initialized to NULL.
You can write
node my_node;
and now we have a node. my_node has two fields and you can write
my_node.info = 1;
my_node.next = NULL;
and say you have a linked list of just one node. And you can even make head point to it by using the operator 'address of', the ampersand, by writing
head = &my_node;
that takes the address of my_node and put into a pointer, well, to a node. This is what pointers are meant for.
Or you can write
head = (node*) malloc( sizeof(node) );
And allocate memory just the size of a node. And then head is not pointer to NULL anymore. It is pointer to an area of the size of a node and be used as such. You can now write
head->info = -3456;
head->next = NULL;
Note that in the case of a pointer you use the operator -> to access the field, not the dot as in the example of my_node above, a local variable in you program.
You can stop reading now if is clear what head is, and the meaning of the declaration in your program. What follows is just a more complete example
(An arguably more useful) Other Linked List structure
struct c_node
{
void* data;
struct c_node* next;
struct c_node* prev;
};
typedef struct c_node CNode;
struct c_list
{
char* name;
int capacity;
int size;
CNode* start;
CNode* end;
};
typedef struct c_list _List;
Note that on the example of _List above things can get more meaning. One could just write
_List my_linked_list;
but my_linked_list here has nodes, a parameter that you keep the actual size of the list, a possible limit of capacity, pointers to the start and the end of the list to make life simpler. And even a name.
When creating the list you set things up as in
_List* create_list(const char* name, int capacity)
{
_List* list = (_List*) malloc( sizeof(_List) );
list->capacity = capacity;
list->size = 0;
list->start = list->end = NULL;
list->name = (char*)malloc(strlen(name) + 1);
strcpy(list->name, name);
return list;
}
and create a list by just calling
_List* = create_list("My First 100 Nodes", 100);
Note that in this case the data is just a pointer, the void* data; part of the node structure, CNode, so this thing can point to anything, creating an abstract data structure, a container of things.
This is just a part of an example and the intent is just to show how (I believe) more clearly the purpose and structure of a linked list. Much more than just a node.