I am new to C and have written this code just to teach myself how to work with linked lists and was hoping someone could review it and give me any comments or tips for efficiency, etc. The code just creates a list, adds and removes nodes from the list, and can reverse the list./* Creates a linked list, adds and removes nodes and reverses list */#include <stdlib.h>#include <stddef.h>#include <stdio.h>typedef bool;#define false 0#define true 1 typedef struct node {    int value;    struct node *next;} node;node *head = NULL;    //Contains entire listnode *current = NULL;  //Last item currently in the list// Initialize list with input valuestruct node* create_list(int input){      node* ptr;    printf(Creating a LinkedList with head node =  %d\n, input);    ptr = (node*)malloc(sizeof(node)); // Allocating 8 bytes of memory for type node pointer    if (ptr == NULL) // Would occur is malloc can't allocate enough memory    {        printf(Node creation failed \n);        return NULL;    }    ptr->value = input;    ptr->next = NULL;    head = current = ptr;    return ptr;}// Add input value to the end of the liststruct node* add_to_end(int input){    node* ptr;    if (head == NULL)    {        return create_list(input);    }    ptr = (struct node*)malloc(sizeof(struct node));    if (ptr == NULL)    {        printf(Node creation failed \n);        return NULL;    }    else    {        ptr->value = input;        ptr->next = NULL;    // End value in list should have NULL next pointer        current -> next = ptr; // Current node contains last value information        current = ptr;    }    printf(%d Added to END of the LinkedList.\n, input);    return head; }// Add input value to the head of the liststruct node* add_to_front(int input){    node* ptr;    if (head == NULL)    {        return create_list(input);    }    ptr = (struct node*)malloc(sizeof(struct node));    if (ptr == NULL)    {        printf(Node creation failed \n);        return NULL;    }    else    {        ptr->value = input;        ptr->next = head;  // Point next value to the previous head        head = ptr;      }    printf(%d Added to HEAD of the LinkedList.\n, input);    return head;}// Return the number of items contained in a listint size_list(node* ptr){    int index_count = 0;    while (ptr != NULL)    {        ++index_count;        ptr = ptr->next;    }    return index_count;}// Add an input value at a user-specified index location in the list (starting from 0 index)struct node* add_to_list(int input, int index){    node* ptr_prev = head;    node* ptr_new;    int index_count;         // Used to count size of list    int index_track = 1;     // Used to track current index    ptr_new = (struct node*)malloc(sizeof(struct node));    // Check that list exists before adding it in    if (head == NULL)    {        if (index == 0)   // Create new list if 0 index is specified        {            add_to_front(input);        }        else        {            printf(Could not insert '%d' at index '%d' in the LinkedList because the list has not been initialized yet.\n, input, index);            return NULL;        }    }    // Count items in list to check whether item can added at specified location    if ((index_count = size_list(head)) < index)    {        printf(Could not insert '%d' at index '%d' in the LinkedList because there are only '%d' nodes in the LinkedList.\n, input, index, index_count);        return NULL;    }    //Go through list -- stop at item before insertion point    while (ptr_prev != NULL)    {         if (index == 0)  // Use add_to_front function if user-specified index is 0 (the head of the list)        {            add_to_front(input);            return head;        }        if ((index_track) == index)          {                   break;        }        ptr_prev = ptr_prev ->next;        ++index_track;    }    ptr_new ->next = ptr_prev ->next;   // Change the new node to point to the original's next pointer    ptr_new->value = input;    ptr_prev ->next = ptr_new;  // Change the original node to point to the new node    return head;}// Verify if the list contains an input value and return the pointer to the value if it existsstruct node* search_list(int input, struct node **prev){    node* ptr = head;    node* temp = (node*)malloc(sizeof(node));    bool found = false;    // Search if value to be deleted exists in the list    while (ptr != NULL)    {        if(ptr->value == input)        {            found = true;            break;        }        else        {            temp = ptr;            ptr = ptr ->next;        }    }    // If the value is found in the list return the ptr to it    if(found == true)    {        if(prev)            *prev = temp;        return ptr;    }    else    {        return NULL;    }}// Remove an input value from the liststruct node* remove_from_list(int input){    node* prev = NULL; // list starting from one item before value to be deleted    node* del = NULL;  // pointer to deleted value    // Obtain pointer to the list value to be deleted    del = search_list(input, &prev);    if(del == NULL)    {        printf(Error: '%d' could not be deleted from the LinkedList because it could not be found\n);        return NULL;    }    else    {        if (prev != NULL)        {            prev->next = del->next;        }        if (del == current)  // If item to be deleted is last in list, set the current last item as the item before deleted one        {            current = prev;        }        else if (del == head) // If item to be deleted is the head of the list, set the new head as the item following the deleted one        {            head = del ->next;        }        return head;    }}// Reverse the order of the liststruct node* reverse_list() {    node* reverse = NULL;    node* next = NULL;    node* ptr = head;     if (head == NULL)    {        printf(Error: There is no LinkedList to reverse.\n);        return NULL;    }    printf(Reversing order of the LinkedList.\n);    while (ptr != NULL)     {        next = ptr ->next;    // Holds the remaining items in the original list        ptr ->next = reverse; // List now points to items in reversed list        reverse = ptr;  // Reversed list set equal to the List        ptr = next; // List re-pointed back to hold list     }    head = reverse;}  // Print the list to the consolevoid print_list(){    node* ptr = head;    printf(------------------------------\n);    printf(PRINTING LINKED LIST\n);    while (ptr != NULL)    {        printf(%d\n, ptr->value);        ptr = ptr->next;    }    printf(------------------------------\n);}int main(){    int i;    reverse_list(); //test function error message    for (i = 3; i > 0; --i)    {        add_to_front(i);    }    for (i= 4; i < 7; ++i)    {        add_to_end(i);    }    add_to_list(4,9); //test function error message    add_to_list(4,1);     print_list();     remove_from_list(3);     print_list();    reverse_list();    print_list();    add_to_list(10,0);    print_list();    getchar();}
Reversing a linked list and adding/removing nodes
beginner;c;linked list
You code is quite good for a beginner and shows a grasp of how pointers and lists work, so that's great! However, there are a few points I'd like to address.I'll start by briefly listing what for me are less important issues or some things that others are likely to disagree with, then move on to more problematic errors:General style:Personally, I find that an if statement with a single-line block introduces too much noise. That is, I preferif (condition)    statement;toif (condition){    statement;}Since you typedefed struct node as node, you don't have to write struct node all the time.malloc() issues:Don't cast the return value of malloc() unless you're writing C++: see this SO question.It's better to write ptr = malloc(sizeof(*ptr)); instead of ptr = malloc(sizeof(node)); because that way the line won't need changing if the type of ptr changes.Bigger problems:Globals: head and current seem to be global objects in your program, making all of the functions you wrote impossible to reuse. This impedes the usefulness of your list data structure. It is generally a good idea not to have any read-write globals at all, but read-only globals like conversion tables and constants are usually fine.For the purposes of an example, let's pretend to delete head and current. Let's look at the functions create_list() and add_to_end():// Initialize list with input valuenode* create_list(int input){      node *ptr = malloc(sizeof(*ptr)); // Allocating 8 bytes of memory for type node pointer    if (ptr == NULL) // Would occur is malloc can't allocate enough memory        return NULL;    ptr->value = input;    ptr->next = NULL;    return ptr;}The function merely creates a new list node and returns it, unless there's an error. Then, we can query the return value to determine if the creation of the list was successful:node *head = create_list(7);if (head == NULL)    some_kind_of_error_handling_here();The same goes for add_to_end():// Add input value to the end of the listnode* add_to_end(node *head, int input){    if (head == NULL)        return NULL;    // Find the last element of the list    while(head->next != NULL)        head = head->next;    node *ptr = malloc(sizeof(*ptr));    if (ptr == NULL)        return NULL;    ptr->value = input;    ptr->next = NULL;    // End value in list should have NULL next pointer    // Attach new node to the end of the list.    head->next = ptr;    return ptr; }Now we find the last element, attach a new node to it (unless malloc() fails) and as a bonus return a pointer to it. Actually, a lot of this code looks familiar, so we can do better:node* add_to_end(node *head, int input){    if (head == NULL)        return NULL;    node *ptr = create_list(input);    if (ptr == NULL)        return NULL;    // Find the last element of the list    while(head->next != NULL)        head = head->next;    // Attach new node to the end of the list.    head->next = ptr;    return ptr; }Two things should be noted here: 1) We enabled code reuse by (the call to create_list()) by eliminating the globals and 2) that its possible to think of a list as consisting of a head and the rest, which is also a list.Memory leaks: Every object allocated using malloc() and friends must be deallocated using free(). The best way to deallocate the list memory would be to provide a function like delete_list().Separation of concerns: It is generally a good idea not to mix code that manipulates data with input or output code. It is best to return an error code from functions that may fail and test for it in the caller. Doing this will not only make things easier to change later (for example, should we need to log errors to a file instead of print them out) but also make the functions shorter and easier to understand.