Wednesday, August 19, 2026

Step-by-Step Code Walkthrough: Modularizing Right-Angled Triangles in C

Step-by-Step Code Walkthrough: Modularizing Right-Angled Triangles in C

When learning to modularize code, squares and rectangles are great starting points because their row and column lengths remain identical or static. However, real-world patterns—and common coding interview challenges—often require shapes whose dimensions shift dynamically, such as right-angled triangles.

Unlike a square, a right-angled triangle's inner loop boundary changes with every iteration of the outer loop ($j \le i$). Modularizing this shape requires careful thought around parameter passing and loop dependency.

In this step-by-step code walkthrough, we will break down how to refactor a monolithic right-angled triangle script into a clean, reusable, and parameterized C function.

Step 1: The Monolithic Baseline (The Old Way)

Traditionally, when beginners learn to print a right-angled triangle, everything is written directly inside the main() function:

#include <stdio.h>

int main() {
    int rows = 4;
    
    // Monolithic loop structure
    for (int i = 1; i <= rows; i++) {
        for (int j = 1; j <= i; j++) {
            printf("* ");
        }
        printf("\n");
    }
    
    return 0;
}

While this prints the desired output, it is locked to a hardcoded height of 4 and uses only asterisks (*). If you need a triangle of height 6 using hash symbols (#) elsewhere in your program, you are forced to duplicate code.

Step 2: Designing the Function Signature

To make our triangle generator truly modular, we need to extract the core logic into a dedicated function. Let's analyze what inputs the function requires:

  1. int height: Controls the total number of rows (the outer loop limit).

  2. char symbol: Controls the rendering character, adding flexibility beyond standard stars.

Thus, our function signature becomes:

void printRightTriangle(int height, char symbol);

Step 3: Writing the Modular Implementation

Now let's encapsulate the original loop logic inside our new function definition. We will also include basic input validation to ensure safety against negative or zero heights.

#include <stdio.h>

// Modular function definition
void printRightTriangle(int height, char symbol) {
    // Input validation guard
    if (height <= 0) {
        printf("Error: Height must be greater than zero.\n");
        return;
    }

    // Outer loop controls rows
    for (int i = 1; i <= height; i++) {
        // Inner loop controls columns, dynamically scaling with row 'i'
        for (int j = 1; j <= i; j++) {
            printf("%c ", symbol);
        }
        printf("\n");
    }
}

Step 4: Orchestrating the Function in main

With our reusable function built, the main() function transforms into a clean coordinator. We can now call printRightTriangle multiple times with different arguments without repeating any loop logic.

Complete Program

#include <stdio.h>

// Function Prototype
void printRightTriangle(int height, char symbol);

int main() {
    printf("--- Triangle 1 (Height: 4, Symbol: *) ---\n");
    printRightTriangle(4, '*');

    printf("\n--- Triangle 2 (Height: 6, Symbol: #) ---\n");
    printRightTriangle(6, '#');

    printf("\n--- Triangle 3 (Height: 3, Symbol: @) ---\n");
    printRightTriangle(3, '@');

    return 0;
}

// Function Definition
void printRightTriangle(int height, char symbol) {
    if (height <= 0) {
        printf("Error: Height must be greater than zero.\n");
        return;
    }

    for (int i = 1; i <= height; i++) {
        for (int j = 1; j <= i; j++) {
            printf("%c ", symbol);
        }
        printf("\n");
    }
}

Output

--- Triangle 1 (Height: 4, Symbol: *) ---
* 
* * 
* * * 
* * * * 

--- Triangle 2 (Height: 6, Symbol: #) ---
# 
# # 
# # # 
# # # # 
# # # # # 
# # # # # # 

--- Triangle 3 (Height: 3, Symbol: @) ---
@ 
@ @ 
@ @ @ 

Summary of Takeaways

  1. Dynamic Inner Loops: Even when an inner loop depends on an outer counter (j <= i), it can be safely encapsulated inside a parameterized function.

  2. Code Reusability: Passing height and symbol transforms a single-use script into a dynamic utility capable of rendering countless variations.

  3. Clean Architecture: Keeping your loop logic separate from your main() execution flow makes your C programs significantly easier to read, test, and maintain.


For all Pattern Programs list click here

…till the next post, bye-bye & take care

No comments:

Post a Comment