C control flow decides which statements execute and how often. if and switch select a path; for, while, and do-while repeat work; break, continue, and return change the normal sequence. The syntax is small, but correct programs depend on expressing boundaries and termination conditions precisely.
After this lesson, you can choose a branch or loop form, trace the state that makes a loop stop, avoid accidental fall-through and off-by-one errors, and simplify nested logic with early returns.
The if statement executes a block of code only if the condition is true (non-zero in C).
if (condition) {
// executes if condition is true
}
if (condition) {
// executes if condition is true
} else {
// executes if condition is false
}
Used to test multiple conditions in sequence. The first true condition executes and the rest are skipped.
if (condition1) {
// ...
} else if (condition2) {
// ...
} else if (condition3) {
// ...
} else {
// default
}
The switch statement tests a variable against a list of values (cases). Each case must end with break to prevent fall-through. The default case runs if no case matches.
#include <stdio.h>
int main() {
int marks;
printf("Enter marks (0-100): ");
scanf("%d", &marks);
if (marks >= 90) {
printf("Grade: A+ (Excellent)\n");
} else if (marks >= 80) {
printf("Grade: A (Very Good)\n");
} else if (marks >= 70) {
printf("Grade: B (Good)\n");
} else if (marks >= 60) {
printf("Grade: C (Average)\n");
} else if (marks >= 50) {
printf("Grade: D (Pass)\n");
} else {
printf("Grade: F (Fail)\n");
}
return 0;
}
/*
Enter marks (0-100): 85
Grade: A (Very Good)
*/
#include <stdio.h>
int main() {
int day;
printf("Enter day number (1-7): ");
scanf("%d", &day);
switch (day) {
case 1:
printf("Monday\n");
break;
case 2:
printf("Tuesday\n");
break;
case 3:
printf("Wednesday\n");
break;
case 4:
printf("Thursday\n");
break;
case 5:
printf("Friday\n");
break;
case 6:
printf("Saturday\n");
break;
case 7:
printf("Sunday\n");
break;
default:
printf("Invalid day number!\n");
}
// Fall-through example: weekend check
switch (day) {
case 6:
case 7:
printf("It's the weekend!\n");
break;
default:
printf("It's a weekday.\n");
}
return 0;
}
#include <stdio.h>
int main() {
int a, b, c;
printf("Enter three numbers: ");
scanf("%d %d %d", &a, &b, &c);
if (a >= b) {
if (a >= c) {
printf("Largest: %d\n", a);
} else {
printf("Largest: %d\n", c);
}
} else {
if (b >= c) {
printf("Largest: %d\n", b);
} else {
printf("Largest: %d\n", c);
}
}
return 0;
}
/*
Enter three numbers: 12 45 30
Largest: 45
*/
In C, zero is false and any nonzero scalar value is true. Write conditions around the meaning of the data: compare a length with zero, a pointer with NULL, or a status code with its documented value. Assignment is an expression, so writing if (status = READY) changes status and tests the assigned value. Enable compiler warnings to catch this common typo.
Use an if/else chain for ranges and unrelated conditions. Use switch when one integral or enumeration expression is compared with discrete case labels. A case continues into the next case unless execution reaches break, return, or another transfer; intentional fall-through should be rare and clearly documented.
Choose for when initialization, condition, and update form one counting pattern. Choose while when repetition is governed by an event or result checked before the body. Choose do-while only when the body must execute once before the condition is tested. The choice should make the termination rule easy to see.
Before writing a loop, name the state that changes and the condition that eventually becomes false. For an array of length n, valid indexes run from zero through n - 1, so i < n is the usual boundary. Use size_t for sizes and indexes that come from sizeof or library length functions, and avoid mixing signed negative values with unsigned comparisons.
continue skips to the next iteration and can keep the main operation less indented when invalid records are common. break exits only the nearest loop or switch. return exits the function and is often the clearest response to invalid arguments or failed resource acquisition.
Deeply nested branches hide which conditions are exceptional. Validate inputs and failure cases early, then leave the successful path at a shallow indentation level. When a function owns a resource, make sure every early exit either releases it or transfers ownership explicitly.
Try this next
0 of 2 completed
Explore 500+ free tutorials across 20+ languages and frameworks.