C/C++

For Illustrative Purposes,

Let us assume we have all the basic Linked List insertions inside one single program. Since there are many methods (functions), we cannot clutter the program by writing all the method definitions above the obligatory main function. But even if we did, there can arise the problem of ordering the methods, where one method needs to be before another and so on.

So to solve this problem, we can declare all the prototypes at the beginning of the program, followed by the main method and below it, we can define them in any particular order:

Program:

FullLinkedList.c




// Full Linked List Insertions
  
#include <stdio.h>
#include <stdlib.h>
  
//--------------------------------
// Declarations - START:
//--------------------------------
  
struct Node;
struct Node* create_node(int data);
void b_insert(struct Node** head, int data);
void n_insert(struct Node** head, int data, int pos);
void e_insert(struct Node** head, int data);
void display(struct Node* temp);
  
//--------------------------------
// Declarations - END:
//--------------------------------
  
int main()
{
    struct Node* head = NULL;
  
    int ch, data, pos;
  
    printf("Linked List: \n");
    while (1) {
        printf("1.Insert at Beginning");
        printf("\n2.Insert at Nth Position");
        printf("\n3.Insert At Ending");
        printf("\n4.Display");
        printf("\n0.Exit");
        printf("\nEnter your choice: ");
        scanf("%d", &ch);
  
        switch (ch) {
        case 1:
            printf("Enter the data: ");
            scanf("%d", &data);
            b_insert(&head, data);
            break;
  
        case 2:
            printf("Enter the data: ");
            scanf("%d", &data);
  
            printf("Enter the Position: ");
            scanf("%d", &pos);
            n_insert(&head, data, pos);
            break;
  
        case 3:
            printf("Enter the data: ");
            scanf("%d", &data);
            e_insert(&head, data);
            break;
  
        case 4:
            display(head);
            break;
  
        case 0:
            return 0;
  
        default:
            printf("Wrong Choice");
        }
    }
}
  
//--------------------------------
// Definitions - START:
//--------------------------------
  
struct Node {
    int data;
    struct Node* next;
};
  
struct Node* create_node(int data)
{
    struct Node* temp
        = (struct Node*)
            malloc(sizeof(struct Node));
    temp->data = data;
    temp->next = NULL;
  
    return temp;
}
  
void b_insert(struct Node** head, int data)
{
    struct Node* new_node = create_node(data);
  
    new_node->next = *head;
    *head = new_node;
}
  
void n_insert(struct Node** head, int data, int pos)
{
    if (*head == NULL) {
        b_insert(head, data);
        return;
    }
  
    struct Node* new_node = create_node(data);
  
    struct Node* temp = *head;
  
    for (int i = 0; i < pos - 2; ++i)
        temp = temp->next;
  
    new_node->next = temp->next;
    temp->next = new_node;
}
  
void e_insert(struct Node** head, int data)
{
    if (*head == NULL) {
        b_insert(head, data);
        return;
    }
  
    struct Node* temp = *head;
  
    while (temp->next != NULL)
        temp = temp->next;
  
    struct Node* new_node = create_node(data);
    temp->next = new_node;
}
  
void display(struct Node* temp)
{
    printf("The elements are:\n");
    while (temp != NULL) {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("\n");
}
  
//--------------------------------
// Definitions - END
//--------------------------------


Compiling the code: We can compile the above program by:

gcc linkedlist.c -o linkedlist

And it works!

Underlying problems in the above code:
We can already see the underlying problem(s) with the program, the code is not at all easy to work with, neither individually nor in a group.

If someone would want to work with the above program, then some of the many problems faced by that person are:

  1. Need to go through the Full source file to improve or enhance some functionality.
  2. Cannot easily re-use the program as a framework for other project(s).
  3. Code is very cluttered and not at all appealing making it Very Difficult to navigate through the code.

In case of group project or large programs, the above approach is guaranteed to enhance the overall expenditure, energy and failure rate.

The Correct Approach:

We see these lines starting in every C/C++ program which starts with “#include ”.
This means to include all the functions declared under the “library” header (.h files) and defined possibly in library.c/cpp files.

These lines are processed by pre-processor during compilation.

We can manually try to create such a library for our own purpose.

Important things to remember:

  1. “.h” files contain only Prototype declarations (such as Functions, Structures) and global variables.
  2. “.c/.cpp” files contain the real implementation (Definitions of declaration in the header files)
  3. When compiling all the source files together, make sure there are no multiple definitions of a same functions, variable etc. for the same project. (VERY IMPORTANT)
  4. Use static functions to restrict to the file where they are declared.
  5. Use extern keyword to use variable(s) that reference external files.
  6. If using C++, be careful about namespaces always use namespace_name::function() to avoid collision.

Dividing the program into smaller codes:
Looking into the above program, we can see how this large program can be divided into suitable small parts and then easily worked on.

The above program has essentially 2 main functions:
1) Create, Insert and store data into Nodes.
2) Display the Nodes

So I can divide the program accordingly such that:
1) Main File -> Driver program, Nice Wrapper of the Insertion Modules and where we use the additional files.
2) Insert -> The Real Implementation Lies here.

Keeping the mentioned Important Points in mind, the program is divided as:

linkedlist.c -> Contains Driver Program
insert.c -> Contains Code for insertion

linkedlist.h -> Contains the necessary Node declarations
insert.h -> Contains the necessary Node Insertion Declarations

In each header file, we start with:

#ifndef FILENAME_H  
#define FILENAME_H 

Declarations...

#endif

The reason we write our declarations in between the #ifndef, #define and #endif is to prevent multiple declarations of identifiers such as data types, variables etc. when the same header file is invoked in new file belonging to the same project.

For this Sample Program:

insert.h -> Contains Node insertion’s declaration and also declaration of Node itself.

One very important thing to remember is that compiler can see declarations in header file but if you try to write code INVOLVING definition of the declaration declared elsewhere, it will lead to error since compiler compiles each .c file individually before the proceeding to the linking stage.

linkedlist.h -> A helper file that contains Node and it’s Display declarations that is to be included for files that uses them.

insert.c -> Include the Node declaration via #include “linkedlist.h” which contains the declaration and also all other definitions of methods declared under insert.h.

linkedlist.c -> Simple Wrapper containing an infinite loop prompting user to Insert Integer data at required position(s), and also contains the method that displays the list.

One final thing to keep in mind is that, mindless including files into each other may result in multiple re-definition(s) and result in error.

Keeping the above in mind should you carefully divide into suitable sub programs.

linkedlist.h




// linkedlist.h
  
#ifndef LINKED_LIST_H
#define LINKED_LIST_H
  
struct Node {
    int data;
    struct Node* next;
};
  
void display(struct Node* temp);
  
#endif


insert.h




// insert.h
  
#ifndef INSERT_H
#define INSERT_H
  
struct Node;
struct Node* create_node(int data);
void b_insert(struct Node** head, int data);
void n_insert(struct Node** head, int data, int pos);
void e_insert(struct Node** head, int data);
  
#endif


insert.c




// insert.c
  
#include "linkedlist.h"
// "" to tell the preprocessor to look
// into the current directory and
// standard library files later.
  
#include <stdlib.h>
  
struct Node* create_node(int data)
{
    struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
    temp->data = data;
    temp->next = NULL;
  
    return temp;
}
  
void b_insert(struct Node** head, int data)
{
    struct Node* new_node = create_node(data);
  
    new_node->next = *head;
    *head = new_node;
}
  
void n_insert(struct Node** head, int data, int pos)
{
    if (*head == NULL) {
        b_insert(head, data);
        return;
    }
  
    struct Node* new_node = create_node(data);
  
    struct Node* temp = *head;
  
    for (int i = 0; i < pos - 2; ++i)
        temp = temp->next;
  
    new_node->next = temp->next;
    temp->next = new_node;
}
  
void e_insert(struct Node** head, int data)
{
    if (*head == NULL) {
        b_insert(head, data);
        return;
    }
  
    struct Node* temp = *head;
  
    while (temp->next != NULL)
        temp = temp->next;
  
    struct Node* new_node = create_node(data);
    temp->next = new_node;
}


linkedlist.c




// linkedlist.c
// Driver Program
  
#include "insert.h"
#include "linkedlist.h"
#include <stdio.h>
  
void display(struct Node* temp)
{
    printf("The elements are:\n");
    while (temp != NULL) {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("\n");
}
  
int main()
{
    struct Node* head = NULL;
  
    int ch, data, pos;
  
    printf("Linked List: \n");
    while (1) {
        printf("1.Insert at Beginning");
        printf("\n2.Insert at Nth Position");
        printf("\n3.Insert At Ending");
        printf("\n4.Display");
        printf("\n0.Exit");
        printf("\nEnter your choice: ");
        scanf("%d", &ch);
  
        switch (ch) {
        case 1:
            printf("Enter the data: ");
            scanf("%d", &data);
            b_insert(&head, data);
            break;
  
        case 2:
            printf("Enter the data: ");
            scanf("%d", &data);
  
            printf("Enter the Position: ");
            scanf("%d", &pos);
            n_insert(&head, data, pos);
            break;
  
        case 3:
            printf("Enter the data: ");
            scanf("%d", &data);
            e_insert(&head, data);
            break;
  
        case 4:
            display(head);
            break;
  
        case 0:
            return 0;
  
        default:
            printf("Wrong Choice");
        }
    }
}


Finally, we save all of them and compile as follows.

gcc insert.c linkedlist.c -o linkedlist

Voila, it compiled successfully, let’s just do a quick sanity check, just in case:

Output:

It remains mostly same for C++ keeping aside usual language feature/implementation changes.

Dividing a Large file into Separate Modules in C/C++, Java and Python

If you ever wanted to write a large program or software, the most common rookie mistake is to jump in directly and try to write all the necessary code into a single program and later try to debug or extend later.

This kind of approach is doomed to fail and would usually require re-writing from scratch.

So in order to tackle this scenario, we can try to divide the problem into multiple subproblems and then try to tackle it one by one.

Doing so, not only makes our task easier but also allows us to achieve Abstraction from the high-level programmer and also promotes Re-usability of code.

If you check any Open-Source project from either GitHub or GitLab or any other site of the likes, we can see how the large program is “decentralized” into many numbers of sub-modules where each individual module contributes to a specific critical function of the program and also various members of the Open Source Community come together for contributing or maintaining such file(s) or repository.

Now, the big question lies in how to “break-down” not theoretically but PROGRAMMATICALLY.

We will see some various types of such divisions in popular languages such as C/C++, Python & Java.

  • Jump to C/C++

  • Jump to Python

  • Jump to Java

Similar Reads

C/C++

For Illustrative Purposes,...

Python

...

Java

...

Contact Us