You’re absolutely right! At 42 School, it’s customary to prefix typedef’ed types with t_ to clearly indicate that they are type definitions. Therefore, instead of naming the typedef as Node, it would typically be named t_node. This naming convention enhances code readability and maintains consistency across projects.

Let’s update the previous implementation to adhere to 42 School’s naming conventions by using t_node instead of Node. We’ll also include a main function to demonstrate the usage.


1. Updated Implementation Following 42 School’s Conventions

#include <stdlib.h>
#include <stdio.h>
 
// Typedef for t_node to simplify syntax
typedef struct s_node {
    int data;
    struct s_node *next;
} t_node;
 
// Function to create a new t_node
t_node *new_node(int data) {
    t_node *temp;
 
    temp = malloc(sizeof(t_node));
    if (!temp)
    {
        perror("Failed to allocate memory for new node");
        exit(EXIT_FAILURE);
    }
    temp->data = data;
    temp->next = NULL;
    return temp;
}
 
// Function to print the linked list
void print_list(t_node *head) {
    t_node *current = head;
    while (current != NULL)
    {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}
 
// Main function to demonstrate the linked list
int main(void) {
    // Creating nodes
    t_node *head = new_node(10);
    head->next = new_node(20);
    head->next->next = new_node(30);
 
    // Printing the linked list
    print_list(head);
 
    // Freeing allocated memory
    t_node *current = head;
    t_node *next_node;
    while (current != NULL)
    {
        next_node = current->next;
        free(current);
        current = next_node;
    }
 
    return 0;
}

2. Line-by-Line Explanation of the Updated 42 School Implementation

#include <stdlib.h>
#include <stdio.h>
  • #include <stdlib.h>: Includes the standard library for memory allocation (malloc, free) and other utility functions.

  • #include <stdio.h>: Includes the standard I/O library for functions like printf and perror.

// Typedef for t_node to simplify syntax
typedef struct s_node {
    int data;
    struct s_node *next;
} t_node;
  • typedef struct s_node { ... } t_node;:
    • struct s_node: Defines a structure named s_node.
    • int data;: Stores integer data.
    • struct s_node *next;: Pointer to the next node in the linked list.
    • typedef ... t_node;: Creates an alias t_node for struct s_node, allowing us to use t_node instead of struct s_node in the code. This follows the 42 School convention of prefixing typedef’ed types with t_.
// Function to create a new t_node
t_node *new_node(int data) {
    t_node *temp;
 
    temp = malloc(sizeof(t_node));
    if (!temp)
    {
        perror("Failed to allocate memory for new node");
        exit(EXIT_FAILURE);
    }
    temp->data = data;
    temp->next = NULL;
    return temp;
}
  • t_node *new_node(int data) { ... }: Function to create and initialize a new node with the given data.

  • t_node *temp;: Declares a pointer temp of type t_node*.

  • temp = malloc(sizeof(t_node));:

    • Allocates memory sufficient for one t_node.
    • No casting of malloc’s return value, adhering to C best practices and 42 School’s guidelines.
  • if (!temp) { ... }:

    • Checks if malloc returned NULL, indicating a memory allocation failure.
    • perror: Prints a descriptive error message to stderr.
    • exit(EXIT_FAILURE);: Terminates the program with a failure status.
  • temp->data = data;: Assigns the provided data to the new node.

  • temp->next = NULL;: Initializes the next pointer to NULL.

  • return temp;: Returns the pointer to the newly created node.

// Function to print the linked list
void print_list(t_node *head) {
    t_node *current = head;
    while (current != NULL)
    {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}
  • void print_list(t_node *head) { ... }: Function to traverse and print the linked list starting from head.

  • t_node *current = head;: Initializes a pointer current to traverse the list.

  • while (current != NULL) { ... }:

    • Iterates through each node in the list.
    • printf("%d -> ", current->data);: Prints the data of the current node followed by an arrow.
    • current = current->next;: Moves to the next node.
  • printf("NULL\n");: Indicates the end of the list.

// Main function to demonstrate the linked list
int main(void) {
    // Creating nodes
    t_node *head = new_node(10);
    head->next = new_node(20);
    head->next->next = new_node(30);
 
    // Printing the linked list
    print_list(head);
 
    // Freeing allocated memory
    t_node *current = head;
    t_node *next_node;
    while (current != NULL)
    {
        next_node = current->next;
        free(current);
        current = next_node;
    }
 
    return 0;
}
  • int main(void) { ... }: The entry point of the program.

  • Creating Nodes:

    • t_node *head = new_node(10);: Creates the head node with data 10.
    • head->next = new_node(20);: Creates the second node with data 20 and links it to the head.
    • head->next->next = new_node(30);: Creates the third node with data 30 and links it to the second node.
  • Printing the Linked List:

    • print_list(head);: Calls the print_list function to display the linked list.
  • Freeing Allocated Memory:

    • t_node *current = head;: Starts from the head of the list.
    • t_node *next_node;: Temporary pointer to store the next node.
    • while (current != NULL) { ... }:
      • Iterates through each node.
      • next_node = current->next;: Saves the next node.
      • free(current);: Frees the memory allocated for the current node.
      • current = next_node;: Moves to the next node.
  • return 0;: Indicates successful program termination.


3. Compilation and Execution

To compile and run the updated program:

gcc -Wall -Wextra -Werror -o linked_list linked_list.c
./linked_list

Expected Output:

10 -> 20 -> 30 -> NULL

4. Summary of Naming Conventions and Best Practices at 42 School

  1. Prefixing Typedef’ed Types with t_:

    • Example: t_node instead of Node.
    • Purpose: Clearly distinguishes type definitions from other identifiers, enhancing code readability.
  2. Avoiding Unnecessary Casting of malloc:

    • Rationale: In C, malloc returns a void*, which is implicitly convertible to any other pointer type. Casting can sometimes mask errors, especially in C++ where it could lead to ambiguities.
  3. Using typedef for Structs:

    • Benefit: Simplifies the syntax by eliminating the need to repeatedly write struct.
    • Example: typedef struct s_node { ... } t_node; allows using t_node directly.
  4. Robust Error Handling:

    • Practice: Always check the return value of malloc (or other memory allocation functions) to ensure that memory allocation was successful.
    • Implementation: Use perror and exit to handle allocation failures gracefully.
  5. Consistent Coding Style:

    • Focus: Adhering to strict formatting and naming conventions to maintain code consistency and readability.
    • Tools: Often enforced using tools like norminette at 42 School.
  6. Memory Management:

    • Emphasis: Proper allocation and deallocation of memory to prevent leaks.
    • Implementation: Ensure that every malloc has a corresponding free.

By following these conventions, the code not only becomes more readable and maintainable but also aligns with industry best practices, which is highly valued at 42 School and beyond.


5. Final Thoughts

Adhering to specific naming conventions and coding standards, such as those emphasized at 42 School, fosters a disciplined approach to programming. It ensures that codebases remain consistent, readable, and maintainable, especially as projects scale in complexity. Implementing these best practices from the outset can significantly enhance both individual and collaborative development efforts.

If you have any more questions or need further clarification on linked lists or other data structures, feel free to ask!