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:
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:
int height: Controls the total number of rows (the outer loop limit).char symbol: Controls the rendering character, adding flexibility beyond standard stars.
Thus, our function signature becomes:
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.
// 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
// 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 2 (Height: 6, Symbol: #) ---
#
# #
# # #
# # # #
# # # # #
# # # # # #
--- Triangle 3 (Height: 3, Symbol: @) ---
@
@ @
@ @ @
Summary of Takeaways
Dynamic Inner Loops: Even when an inner loop depends on an outer counter (
j <= i), it can be safely encapsulated inside a parameterized function.Code Reusability: Passing
heightandsymboltransforms a single-use script into a dynamic utility capable of rendering countless variations.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