Thursday, March 13, 2025

How to Improve Code Readability, User-Defined Types in the C Programming Language

In the C programming language, in addition to basic data types such as int, float, char, etc., you can define your own data types. These user-defined types allow programmers to create more complex data structures that meet the specific needs of their applications. User-defined types in the C programming language: struct, union, enum and typedef, provide programmers with tools to create customized and meaningful data types. Structures are ideal for grouping data, unions for saving memory, enumerations for defining constants, and typedef for simplifying syntax.

Their proper use makes the code more modular, easier to understand and adapt, which is especially important in larger projects. These mechanisms are the foundation for working with complex data in the C programming language and are often used in system programming, database work, and algorithm implementation, while at the same time these user-defined types make the code more readable, organized, and easier to maintain. In addition to user-defined data types, at the end of the lesson, we will also focus on constants in the C programming language.

You need to have a solid understanding of the C programming language to effectively use user-defined types

You need to have a solid understanding of the C programming language to effectively use user-defined types

First of all, we will start with structures because structures are the most commonly used user-defined data types in the C programming language. Structures are user-defined data types that allow grouping different types of data under a single name. They simply enable the combination of different data types into one entity. Each variable within a structure is called a member of the structure. Structures are defined using the struct keyword. A structure is useful when we want to model an entity that has multiple attributes, such as a person, a car, or a point in space.

As we know, the C programming language was developed by Dennis Ritchie at Bell Labs during the early 1970s, and it is based on the earlier programming language B, which was created by Ken Thompson and Ritchie. The B programming language, at that time, around 1970, was simple and did not have structures as a formal concept. Instead, programmers manually managed memory and grouped data using pointers and manual memory offsets. However, Ritchie recognized the need for a higher level of abstraction to make programming more efficient. This means that structures did not exist in the earliest predecessors of the C programming language, but they were introduced very early in its development, practically with the creation of the C programming language as we know it today.

Designing Complex Data Structures in C: Best Practices

We will create an example that clearly illustrates how a struct can be the foundation for complex data structures like linked lists, without relying on additional layers of abstraction. Instead of a simple example, we are opting for a more complex and professional struct example.

Structures (struct)

Structures allow the combination of different data types into one unit. Open your terminal and type the following code.

manuel@manuel-virtual-machine:~$ sudo apt-get update

manuel@manuel-virtual-machine:~$ sudo apt-get upgrade

manuel@manuel-virtual-machine:~$ clear

manuel@manuel-virtual-machine:~$ ls

manuel@manuel-virtual-machine:~$ cd tutorials

manuel@manuel-virtual-machine:/tutorials$ ls

manuel@manuel-virtual-machine:/tutorials$ cd c_tutorial

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ ls

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ mkdir structures

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ cd structures

manuel@manuel-virtual-machine:/tutorials/c_tutorial/structures$ code .

Create a file and name it structures.c, then type the following code.

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <stdbool.h>


// Maximum lengths for strings for safety

#define MAX_TITLE_LENGTH 100

#define MAX_AUTHOR_LENGTH 50

#define ISBN_LENGTH 13 


// Structure for a book

struct Book {

    char title[MAX_TITLE_LENGTH];

    char author[MAX_AUTHOR_LENGTH];

    char isbn[ISBN_LENGTH + 1]; // +1 for null terminator

    bool is_available;

};

 

// Node of the linked list containing a book

struct BookNode {

    struct Book data;

    struct BookNode* next;

};

 

// Structure for the library

struct Library {

    struct BookNode* head;

    size_t book_count;

};

 

// Function to initialize the library

struct Library* library_init(void) {

    struct Library* lib = (struct Library*)malloc(sizeof(struct Library));

    if (lib == NULL) {

        perror("Failed to allocate memory for library");

        exit(EXIT_FAILURE);

    }

    lib->head = NULL;

    lib->book_count = 0;

    return lib;

}

 

// Function to create a new node

struct BookNode* create_book_node(const char* title, const char* author, const char* isbn, bool is_available) {

    struct BookNode* node = (struct BookNode*)malloc(sizeof(struct BookNode));

    if (node == NULL) {

        perror("Failed to allocate memory for book node");

        return NULL;

    }

 

    // Copy data with length checking

    strncpy(node->data.title, title, MAX_TITLE_LENGTH - 1);

    node->data.title[MAX_TITLE_LENGTH - 1] = '\0';

    strncpy(node->data.author, author, MAX_AUTHOR_LENGTH - 1);

    node->data.author[MAX_AUTHOR_LENGTH - 1] = '\0';

    strncpy(node->data.isbn, isbn, ISBN_LENGTH);

    node->data.isbn[ISBN_LENGTH] = '\0';

    node->data.is_available = is_available;

 

    node->next = NULL;

    return node;

}

 

// Function to add a book to the library

bool library_add_book(struct Library* lib, const char* title, const char* author, const char* isbn, bool is_available) {

    if (lib == NULL || title == NULL || author == NULL || isbn == NULL) {

        fprintf(stderr, "Invalid input parameters\n");

        return false;

    }

 

    struct BookNode* new_node = create_book_node(title, author, isbn, is_available);

    if (new_node == NULL) {

        return false;

    }

 

    // Add to the beginning of the list

    new_node->next = lib->head;

    lib->head = new_node;

    lib->book_count++;

    return true;

}

 

// Function to search for a book by ISBN

struct Book* library_find_book_by_isbn(const struct Library* lib, const char* isbn) {

    if (lib == NULL || isbn == NULL) {

        return NULL;

    }

 

    struct BookNode* current = lib->head;

    while (current != NULL) {

        if (strcmp(current->data.isbn, isbn) == 0) {

            return &current->data; // Fixed: return a pointer to the current node's data

        }

        current = current->next;

    }

    return NULL;

}

 

// Function to remove a book by ISBN

bool library_remove_book_by_isbn(struct Library* lib, const char* isbn) {

    if (lib == NULL || isbn == NULL || lib->head == NULL) {

        return false;

    }

 

    struct BookNode* current = lib->head;

    struct BookNode* previous = NULL;

 

    while (current != NULL && strcmp(current->data.isbn, isbn) != 0) {

        previous = current;

        current = current->next;

    }

 

    if (current == NULL) {

        return false; // Book not found

    }

 

    if (previous == NULL) {

        lib->head = current->next; // Remove the first node

    } else {

        previous->next = current->next; // Remove a middle or last node

    }

 

    free(current);

    lib->book_count--;

    return true;

}

 

// Function to free the library's memory

void library_free(struct Library* lib) {

    if (lib == NULL) {

        return;

    }

 

    struct BookNode* current = lib->head;

    while (current != NULL) {

        struct BookNode* temp = current;

        current = current->next;

        free(temp);

    }

    free(lib);

}

 

// Function to print all books

void library_print(const struct Library* lib) {

    if (lib == NULL || lib->head == NULL) {

        printf("Library is empty.\n");

        return;

    }

 

    struct BookNode* current = lib->head;

    printf("Library contents (%zu books):\n", lib->book_count);

    while (current != NULL) {

        printf("Title: %s, Author: %s, ISBN: %s, Available: %s\n",

               current->data.title, current->data.author, current->data.isbn,

               current->data.is_available ? "Yes" : "No");

        current = current->next;

    }

}

 

// Main function for demonstration

int main(void) {

    struct Library* lib = library_init(); 

    // Adding books

    library_add_book(lib, "The C Programming Language", "Kernighan & Ritchie", "0131103628", true);

    library_add_book(lib, "Clean Code", "Robert C. Martin", "0132350882", false);

    library_add_book(lib, "Design Patterns", "Erich Gamma", "0201633612", true); 

    // Print library

    library_print(lib);

    // Search for a book

    struct Book* found = library_find_book_by_isbn(lib, "0132350882");

    if (found) {

        printf("\nFound book: %s by %s\n", found->title, found->author);

    } else {

        printf("\nBook not found.\n");

    }

    // Remove a book

    if (library_remove_book_by_isbn(lib, "0131103628")) {

        printf("\nBook removed successfully.\n");

    }

    library_print(lib);

    // Free memory

    library_free(lib);

    return 0;

}

When you execute the given code, you will get similar following result.

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/structures

$ gcc structures.c -o structures

 

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/structures

$ ./structures

Library contents (3 books):

Title: Design Patterns, Author: Erich Gamma, ISBN: 0201633612, Available: Yes

Title: Clean Code, Author: Robert C. Martin, ISBN: 0132350882, Available: No

Title: The C Programming Language, Author: Kernighan & Ritchie, ISBN: 0131103628, Available: Yes

 

Found book: Clean Code by Robert C. Martin

 

Book removed successfully.

Library contents (2 books):

Title: Design Patterns, Author: Erich Gamma, ISBN: 0201633612, Available: Yes

Title: Clean Code, Author: Robert C. Martin, ISBN: 0132350882, Available: No

Pay attention to the part of the code that you haven't learned yet, for example, perror is a function from the standard library <stdio.h> that prints an error message to the standard error output stderr. It takes a string as an argument and adds a system error message that describes why the last system operation, e.g., malloc, failed. In the C programming language, perror helps the programmer or user understand what went wrong with the system operation, instead of just getting a generic error.

If the system cannot allocate memory for lib, for example, due to memory overload, the program prints a message with the error reason via perror and terminates execution via exit, because it makes no sense to continue without the necessary memory. Perror and exit are often used in low-level programming where it is important to accurately report errors and safely terminate the program if something critical fails. You can also watch a video of how the program is coded.


C Tutorial – 21. How to Use the Struct in C Programming Language?

Unions (union)

Unions allow the storage of different data types in the same memory location. Open your terminal and type the following code.

manuel@manuel-virtual-machine:~$ sudo apt-get update

manuel@manuel-virtual-machine:~$ sudo apt-get upgrade

manuel@manuel-virtual-machine:~$ clear

manuel@manuel-virtual-machine:~$ ls

manuel@manuel-virtual-machine:~$ cd tutorials

manuel@manuel-virtual-machine:/tutorials$ ls

manuel@manuel-virtual-machine:/tutorials$ cd c_tutorial

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ ls

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ mkdir unions

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ cd unions

manuel@manuel-virtual-machine:/tutorials/c_tutorial/unions$ code .

Create a file and name it unions.c, then type the following code.

#include <stdio.h>

#include <stdlib.h>

 

// Constant values for tracking message type (without enum)

#define TYPE_INT 1

#define TYPE_CHAR 2

#define TYPE_FLOAT 3

 

// Union for storing message data

union MessageData {

    int int_value;    // For an integer

    char char_value;  // For a character

    float float_value; // For a float

};

 

// Function to create a message

union MessageData* create_message(int type, void* value) {

    union MessageData* msg = (union MessageData*)malloc(sizeof(union MessageData));

    if (msg == NULL) {

        perror("Failed to allocate memory for message");

        return NULL;

    }

 

    // Set value based on type

    if (type == TYPE_INT) {

        msg->int_value = *((int*)value);

    } else if (type == TYPE_CHAR) {

        msg->char_value = *((char*)value);

    } else if (type == TYPE_FLOAT) {

        msg->float_value = *((float*)value);

    } else {

        fprintf(stderr, "Invalid message type\n");

        free(msg);

        return NULL;

    }

 

    return msg;

}

 

// Function to print a message

void print_message(int type, union MessageData* msg) {

    if (msg == NULL) {

        printf("Message is NULL\n");

        return;

    }

 

    // Print based on type

    if (type == TYPE_INT) {

        printf("Message (Integer): %d\n", msg->int_value);

    } else if (type == TYPE_CHAR) {

        printf("Message (Character): %c\n", msg->char_value);

    } else if (type == TYPE_FLOAT) {

        printf("Message (Float): %.2f\n", msg->float_value);

    } else {

        printf("Unknown message type\n");

    }

}

 

// Function to free a message

void free_message(union MessageData* msg) {

    if (msg != NULL) {

        free(msg);

    }

} 

// Main function for demonstration

int main(void) {

    // Creating messages of different types

    int int_val = 404;          // Error code

    char char_val = 'R';        // Reset command

    float float_val = 23.5;     // Sensor reading

 

    union MessageData* msg1 = create_message(TYPE_INT, &int_val);

    union MessageData* msg2 = create_message(TYPE_CHAR, &char_val);

    union MessageData* msg3 = create_message(TYPE_FLOAT, &float_val);

 

    // Printing messages

    print_message(TYPE_INT, msg1);

    print_message(TYPE_CHAR, msg2);

    print_message(TYPE_FLOAT, msg3);

    // Demonstrating the size of the union

    printf("\nSize of union MessageData: %zu bytes\n", sizeof(union MessageData)); 

    // Freeing memory

    free_message(msg1);

    free_message(msg2);

    free_message(msg3);

    return 0;

} 

When you execute the given code, you will get similar following result. 

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/unions

$ gcc unions.c -o unions

 

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/unions

$ ./unions

Message (Integer): 404

Message (Character): R

Message (Float): 23.50

 

Size of union MessageData: 4 bytes

You can also watch a video of how the program is coded.


C Tutorial – 22. How to Use the Union in C Programming Language?

Enumerated Type (enum)

Allows defining a group of constants under a single name. Open your terminal and type the following code.

manuel@manuel-virtual-machine:~$ sudo apt-get update

manuel@manuel-virtual-machine:~$ sudo apt-get upgrade

manuel@manuel-virtual-machine:~$ clear

manuel@manuel-virtual-machine:~$ ls

manuel@manuel-virtual-machine:~$ cd tutorials

manuel@manuel-virtual-machine:/tutorials$ ls

manuel@manuel-virtual-machine:/tutorials$ cd c_tutorial

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ ls

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ mkdir enumeration

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ cd enumeration

manuel@manuel-virtual-machine:/tutorials/c_tutorial/enumeration$ code .

Create a file and name it enumeration.c, then type the following code.

#include <stdio.h>

#include <stdlib.h>

 

// Constant values for tracking message type (without enum)

#define TYPE_INT 1

#define TYPE_CHAR 2

#define TYPE_FLOAT 3

 

// Union for storing message data

union MessageData {

    int int_value;    // For an integer

    char char_value;  // For a character

    float float_value; // For a float

};

 

// Function to create a message

union MessageData* create_message(int type, void* value) {

    union MessageData* msg = (union MessageData*)malloc(sizeof(union MessageData));

    if (msg == NULL) {

        perror("Failed to allocate memory for message");

        return NULL;

    }

 

    // Set value based on type

    if (type == TYPE_INT) {

        msg->int_value = *((int*)value);

    } else if (type == TYPE_CHAR) {

        msg->char_value = *((char*)value);

    } else if (type == TYPE_FLOAT) {

        msg->float_value = *((float*)value);

    } else {

        fprintf(stderr, "Invalid message type\n");

        free(msg);

        return NULL;

    }

 

    return msg;

}

 

// Function to print a message

void print_message(int type, union MessageData* msg) {

    if (msg == NULL) {

        printf("Message is NULL\n");

        return;

    }

 

    // Print based on type

    if (type == TYPE_INT) {

        printf("Message (Integer): %d\n", msg->int_value);

    } else if (type == TYPE_CHAR) {

        printf("Message (Character): %c\n", msg->char_value);

    } else if (type == TYPE_FLOAT) {

        printf("Message (Float): %.2f\n", msg->float_value);

    } else {

        printf("Unknown message type\n");

    }

}

 

// Function to free a message

void free_message(union MessageData* msg) {

    if (msg != NULL) {

        free(msg);

    }

}

 

// Main function for demonstration

int main(void) {

    // Creating messages of different types

    int int_val = 404;          // Error code

    char char_val = 'R';        // Reset command

    float float_val = 23.5;     // Sensor reading

 

    union MessageData* msg1 = create_message(TYPE_INT, &int_val);

    union MessageData* msg2 = create_message(TYPE_CHAR, &char_val);

    union MessageData* msg3 = create_message(TYPE_FLOAT, &float_val);

 

    // Printing messages

    print_message(TYPE_INT, msg1);

    print_message(TYPE_CHAR, msg2);

    print_message(TYPE_FLOAT, msg3);


    // Demonstrating the size of the union

    printf("\nSize of union MessageData: %zu bytes\n", sizeof(union MessageData));

    // Freeing memory

    free_message(msg1);

    free_message(msg2);

    free_message(msg3); 

    return 0;

} 

When you execute the given code, you will get similar following result.

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/enumeration

$ gcc enumeration.c -o enumeration

 

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/enumeration

$ ./enumeration

Device state: OFF

Successfully turned on the device.

Device state: ON

Device entered standby mode.

Device state: STANDBY

Device encountered an error.

Device state: ERROR (Code: 101)

Cannot turn off device in error state without reset

Failed to turn off device due to error state.     

Device state: ERROR (Code: 101)

You can also watch a video of how the program is coded.


C Tutorial – 23. How to Use the Enum in C Programming Language?

typedef

Used to define aliases for existing types. Open your terminal and type the following code.

manuel@manuel-virtual-machine:~$ sudo apt-get update

manuel@manuel-virtual-machine:~$ sudo apt-get upgrade

manuel@manuel-virtual-machine:~$ clear

manuel@manuel-virtual-machine:~$ ls

manuel@manuel-virtual-machine:~$ cd tutorials

manuel@manuel-virtual-machine:/tutorials$ ls

manuel@manuel-virtual-machine:/tutorials$ cd c_tutorial

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ ls

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ mkdir typedef_alias

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ cd typedef_alias

manuel@manuel-virtual-machine:/tutorials/c_tutorial/typedef_alias$ code .

Create a file and name it alias.c, then type the following code.

#include <stdio.h>

#include <stdlib.h>

// Typedef for a function pointer that takes a float (delta time) and returns void

typedef void (*TickFunction)(float);

 

// Typedef for a structure representing a timer

typedef struct {

    float elapsed_time; // Elapsed time in seconds

    float last_tick;    // Time of the last update

    TickFunction tick;  // Function called every tick

} GameTimer;

 

// Function to update the game

void update_game(float delta_time) {

    printf("Game updated with delta time: %.2f seconds\n", delta_time);

}

 

// Function to update animations

void update_animations(float delta_time) {

    printf("Animations updated with delta time: %.2f seconds\n", delta_time);

}

 

// Function to initialize the timer

GameTimer* timer_init(TickFunction tick_func) {

    GameTimer* timer = (GameTimer*)malloc(sizeof(GameTimer));

    if (timer == NULL) {

        perror("Failed to allocate memory for timer");

        exit(EXIT_FAILURE);

    }

    timer->elapsed_time = 0.0f;

    timer->last_tick = 0.0f;

    timer->tick = tick_func;

    return timer;

}

 

// Function to simulate time passage and call the tick function

void timer_update(GameTimer* timer, float current_time) {

    if (timer == NULL || timer->tick == NULL) {

        fprintf(stderr, "Invalid timer or tick function\n");

        return;

    }

 

    float delta_time = current_time - timer->last_tick;

    if (delta_time > 0.0f) { // Update only if time has passed

        timer->elapsed_time += delta_time;

        timer->tick(delta_time); // Call the tick function

        timer->last_tick = current_time;

    }

}

 

// Function to print the current timer state

void timer_print(const GameTimer* timer) {

    if (timer == NULL) {

        printf("Timer is NULL\n");

        return;

    }

    printf("Elapsed time: %.2f seconds\n", timer->elapsed_time);

}

 

// Function to free the timer memory

void timer_free(GameTimer* timer) {

    if (timer != NULL) {

        free(timer);

    }

}

 

// Main function for demonstration

int main(void) {

    // Creating timers for different tick functions

    GameTimer* game_timer = timer_init(update_game);

    GameTimer* anim_timer = timer_init(update_animations);

 

    // Simulating time (in seconds)

    float time = 0.0f;

    printf("Simulating game loop...\n");

 

    time += 0.5f;

    timer_update(game_timer, time);

    timer_print(game_timer);

 

    time += 0.3f;

    timer_update(anim_timer, time);

    timer_print(anim_timer);

 

    time += 1.2f;

    timer_update(game_timer, time);

    timer_print(game_timer);

 

    time += 0.7f;

    timer_update(anim_timer, time);

    timer_print(anim_timer);

 

    // Freeing memory

    timer_free(game_timer);

    timer_free(anim_timer);

 

    return 0;

}

When you execute the given code, you will get similar following result.

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/typedef_alias

$ gcc alias.c -o alias

 

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/typedef_alias

$ ./alias

Simulating game loop...

Game updated with delta time: 0.50 seconds     

Elapsed time: 0.50 seconds

Animations updated with delta time: 0.80 seconds

Elapsed time: 0.80 seconds

Game updated with delta time: 1.50 seconds     

Elapsed time: 2.00 seconds

Animations updated with delta time: 1.90 seconds

Elapsed time: 2.70 seconds

You can also watch a video of how the program is coded.


C Tutorial – 24. How to Use the Typedef in C Programming Language?

#define

Macro for defining data types. Open your terminal and type the following code.

manuel@manuel-virtual-machine:~$ sudo apt-get update

manuel@manuel-virtual-machine:~$ sudo apt-get upgrade

manuel@manuel-virtual-machine:~$ clear

manuel@manuel-virtual-machine:~$ ls

manuel@manuel-virtual-machine:~$ cd tutorials

manuel@manuel-virtual-machine:/tutorials$ ls

manuel@manuel-virtual-machine:/tutorials$ cd c_tutorial

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ ls

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ mkdir define

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ cd define

manuel@manuel-virtual-machine:/tutorials/c_tutorial/define$ code .

Create a file and name it define.c, then type the following code.

#include <stdio.h>

// Definition of the PI constant

#define PI 3.14159265359

 

// Macros for calculating areas

#define CIRCLE_AREA(radius) (PI * (radius) * (radius))

#define SQUARE_AREA(side) ((side) * (side))

 

// Macros for calculating perimeters

#define CIRCLE_PERIMETER(radius) (2 * PI * (radius))

#define SQUARE_PERIMETER(side) (4 * (side))

 

// Macro for input validation

#define IS_POSITIVE(x) ((x) > 0)

 

// Function to print circle statistics

void print_circle_stats(float radius) {

    if (!IS_POSITIVE(radius)) {

        printf("Error: Radius must be positive!\n");

        return;

    }

    printf("Circle (radius %.2f):\n", radius);

    printf("  Area: %.2f\n", CIRCLE_AREA(radius));

    printf("  Perimeter: %.2f\n", CIRCLE_PERIMETER(radius));

}

 

// Function to print square statistics

void print_square_stats(float side) {

    if (!IS_POSITIVE(side)) {

        printf("Error: Side length must be positive!\n");

        return;

    }

    printf("Square (side %.2f):\n", side);

    printf("  Area: %.2f\n", SQUARE_AREA(side));

    printf("  Perimeter: %.2f\n", SQUARE_PERIMETER(side));

}

 

// Main function

int main(void) {

    float radius, side;

 

    // Input for circle

    printf("Enter the radius of the circle: ");

    if (scanf("%f", &radius) != 1) {

        printf("Invalid input!\n");

        return 1;

    }

 

    // Input for square

    printf("Enter the side length of the square: ");

    if (scanf("%f", &side) != 1) {

        printf("Invalid input!\n");

        return 1;

    }

 

    // Print results

    printf("\nCalculating geometric properties...\n");

    print_circle_stats(radius);

    printf("\n");

    print_square_stats(side);

    return 0;

}

When you execute the given code, you will get similar following result.

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/define

$ gcc define.c -o define

 

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/define

$ ./define

Enter the radius of the circle: 2.5

Enter the side length of the square: 4.5

 

Calculating geometric properties...

Circle (radius 2.50):

  Area: 19.63

  Perimeter: 15.71

 

Square (side 4.50):

  Area: 20.25

  Perimeter: 18.00

You can also watch a video of how the program is coded.


C Tutorial – 25. How to Use the Define in C Programming Language?

Const

Indicates that a variable cannot change its value after initialization.

manuel@manuel-virtual-machine:~$ sudo apt-get update

manuel@manuel-virtual-machine:~$ sudo apt-get upgrade

manuel@manuel-virtual-machine:~$ clear

manuel@manuel-virtual-machine:~$ ls

manuel@manuel-virtual-machine:~$ cd tutorials

manuel@manuel-virtual-machine:/tutorials$ ls

manuel@manuel-virtual-machine:/tutorials$ cd c_tutorial

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ ls

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ mkdir constant

manuel@manuel-virtual-machine:/tutorials/c_tutorial$ cd constant

manuel@manuel-virtual-machine:/tutorials/c_tutorial/constant$ code .

Create a file and name it constant.c, then type the following code.

#include <stdio.h>

// Function to calculate total price

float calculate_total(const float price, int quantity) {

    // 'price' is const, so it cannot be modified within the function

    return price * quantity;

}

 

int main(void) {

    // Defining a constant for the item price

    const float ITEM_PRICE = 5.99; // Item price in euros, cannot be changed

    int quantity;

 

    // Input quantity from the user

    printf("Enter the quantity of items: ");

    scanf("%d", &quantity);

 

    // Input validation

    if (quantity < 0) {

        printf("Error: Quantity cannot be negative!\n");

        return 1;

    }

 

    // Calculating and printing the total price

    float total = calculate_total(ITEM_PRICE, quantity);

    printf("Total price for %d items at %.2f each: %.2f euros\n",

           quantity, ITEM_PRICE, total);

 

    // Attempt to modify the constant (this will cause a compilation error)

    // ITEM_PRICE = 6.99; // Uncomment to see the error

 

    return 0;

}

When you execute the given code, you will get similar following result.

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/constant

$ gcc constant.c -o constant

 

manue@DESKTOP-E2QR9K9 MINGW64 /d/tutorials/c_tutorials/constant

$ ./constant

Enter the quantity of items: 18

Total price for 18 items at 5.99 each: 107.82 euros

You might wonder what the purpose of const – constant is, when you have the preprocessor directive define, or vice versa. You need to understand that these are two completely different things, even though they essentially seem to do the same thing. #define is a preprocessor macro directive, which means that values are defined before the compilation phase. This means that #define does not occupy memory, but the replacement is done during preprocessing. There is no data type, the compiler does not check types during assignment. Debugging can be more difficult because values are directly inserted into the code.

While const is used to define variables that cannot be changed after initialization. This means that const variables have a data type, so the compiler checks type compatibility. They occupy memory because they are actually variables with a fixed value. They can be used with pointers and structures.

When to use which? Use #define for simple macros, such as including debug options or defining flags #define DEBUG. Use const when you want to define immutable values with a specific data type, as it allows type checking and better code safety. In modern C programming, const is considered a better practice than #define for defining constants. You can also watch a video of how the program is coded.


C Tutorial – 26. How to Use the Const in C Programming Language?




















No comments:

Post a Comment