C++ If-Else, Switch and Loops
ProgrammingLesson 3 of 65 min read
What you'll learn
- Write decisions with if, else if, else, logical operators and the ternary operator
- Use switch correctly, including
breakand the fall-through trap - Choose between for, while, do-while and the range-based for loop
- Control loops with
breakandcontinue
On this page
Programs become useful when they can decide and repeat. A checkout needs to apply a discount only for large orders, and a report needs to visit every student in a class. Conditions and loops are the tools for both, and the same constructs power everything from small utilities to game loops.
if, else if and else
An if runs its block when the condition is true. In C++ any value that converts to bool can be a condition: zero is false and any other number is true. That flexibility is also a trap, as you will see in the mistakes section. Combine tests with && (and), || (or) and ! (not). Both && and || stop evaluating as soon as the result is known, which is called short-circuiting, and is how you write checks like if (ptr != nullptr && ptr->ready()) safely.
#include <iostream>
#include <string>
using namespace std;
int main() {
int marks = 72;
if (marks >= 90) {
cout << "Grade A" << endl;
} else if (marks >= 75) {
cout << "Grade B" << endl;
} else if (marks >= 60) {
cout << "Grade C" << endl;
} else {
cout << "Needs improvement" << endl;
}
bool hasId = true;
int age = 17;
if (age >= 18 && hasId) {
cout << "Entry allowed" << endl;
} else {
cout << "Entry denied" << endl;
}
string status = marks >= 40 ? "Pass" : "Fail";
cout << status << endl;
return 0;
}Output
Grade C Entry denied Pass
The chain is checked top to bottom and only the first matching branch runs, so 72 stops at marks >= 60. The last two lines use the conditional operator, written test ? ifTrue : ifFalse, which picks one of two values inside a single expression. Always use braces, even for one-line bodies, so that adding a second line later does not silently fall outside the if.
switch and the fall-through trap
switch compares one integer-like value, such as an int, a char or an enum, against several constant labels. It cannot switch on a std::string or a double, so use if/else for those. End every case with break unless you mean to carry on: leave it out and the program falls through, running the next label's statements as well, with no warning from the compiler.
#include <iostream>
using namespace std;
int main() {
int day = 6;
switch (day) {
case 1:
case 2:
case 3:
case 4:
case 5:
cout << "Weekday" << endl;
break;
case 6:
case 7:
cout << "Weekend" << endl;
break;
default:
cout << "Invalid day" << endl;
}
char choice = 'r';
switch (choice) {
case 'b':
cout << "Adding to cart" << endl;
break;
case 'r':
cout << "Starting refund" << endl;
case 'c':
cout << "Cancelling order (fall-through!)" << endl;
break;
default:
cout << "Unknown command" << endl;
}
return 0;
}Output
Weekend Starting refund Cancelling order (fall-through!)
The first switch uses fall-through on purpose, so cases 1 to 5 share one body. The second one is a bug: the 'r' case has no break, so it also runs the 'c' case. If you ever intend fall-through, mark it with the [[fallthrough]]; attribute (C++17) so readers and compilers know it is deliberate.
for, while and do-while
Reach for for when the repeat count is known up front, and for while when you are waiting on a condition to change - compounding savings until a goal is met, say. do-while is the odd one out: it tests *after* running the body, which guarantees a first pass. The range-based loop at the end of the example visits each element directly, and is the preferred way to walk a container.
#include <iostream>
#include <vector>
using namespace std;
int main() {
for (int i = 1; i <= 3; i++) {
cout << "Round " << i << endl;
}
int balance = 1000;
int years = 0;
while (balance < 1500) {
balance += balance / 10;
years++;
}
cout << "Years: " << years << ", balance: " << balance << endl;
int attempts = 0;
do {
attempts++;
} while (attempts < 3);
cout << "Attempts: " << attempts << endl;
vector<int> marks = {45, 82, 67, 91, 30};
int sum = 0;
for (int m : marks) {
sum += m;
}
cout << "Average: " << static_cast<double>(sum) / marks.size() << endl;
for (int m : marks) {
if (m < 40) {
continue;
}
if (m > 90) {
cout << "Topper found: " << m << endl;
break;
}
cout << "Passed with " << m << endl;
}
for (int& m : marks) {
m += 5;
}
for (const auto& m : marks) {
cout << m << " ";
}
cout << endl;
return 0;
}Output
Round 1 Round 2 Round 3 Years: 5, balance: 1610 Attempts: 3 Average: 63 Passed with 45 Passed with 82 Passed with 67 Topper found: 91 50 87 72 96 35
Follow the savings loop: 1000 grows by a tenth each pass (1100, 1210, 1331, 1464, 1610), and after five passes the balance is no longer below 1500. continue skips 30 because it is below 40, and break stops the search at 91, so nothing after it is visited.
Range-based for: copy, reference or const reference?
The loop variable in for (int m : marks) is a copy of each element, so changing it does not change the vector. To modify elements in place, take a reference: for (int& m : marks), which is how the last section added 5 grace marks. To read large elements such as strings without copying them, use a const reference: for (const auto& item : items). This one habit prevents a lot of silent bugs and wasted copies.
Common mistakes
- Using `=` instead of `==`. Unlike Java,
if (marks = 90)compiles. It assigns 90 and the condition is then true. With-Wallyou getwarning: suggest parentheses around assignment used as truth value. - A stray semicolon.
if (x > 5);orfor (...);makes the following block run unconditionally or only once. There is no error. - Missing `break` in a switch. Execution falls into the next case, as the refund example showed.
- Switching on a string.
switch (command)with astd::stringfails witherror: switch quantity not an integer. Useif/else if. - Out-of-range indexing.
for (int i = 0; i <= marks.size(); i++)reads one element past the end, which is undefined behavior and may crash or print garbage. Use<. - Infinite loops. A
whileloop that never changes its condition variable runs forever. Stop it with Ctrl+C.
How this shows up in interviews and real projects
Beginner interview questions such as FizzBuzz, reversing an array, finding a maximum or checking for primes are all loops with a condition inside, and interviewers watch for correct boundaries and clean early exits. In production C++ you will often use standard algorithms like std::find or std::sort instead of hand-written loops, but they do exactly what these loops do. See coding interview prep for self-taught developers for how to practise.
Try it yourself
Store 8 daily sales figures in a vector<int>. Use a range-based loop to compute the total and count how many days had sales above 1000. Use continue to skip days with zero sales (store closed), and break if the running total passes 5000. Print the total and count.
Show a hint
Keep total and count variables outside the loop. Test for zero first, then add to the total, then check whether to break.
Key takeaways
- Conditions accept any value convertible to bool, which makes
=versus==a real danger. Turn on warnings. switchworks on integer-like values and needsbreakto avoid fall-through.- Use
forfor a known count,whilefor repeat-until,do-whilefor at least once, and range-basedforfor containers. - Take loop variables by
&to modify elements and byconst auto&to read without copying.
Test yourself
A trick from this lesson's ride: Case labels are doors you walk in through; only break lets you out. Four more tricks like it wait along the route, each followed by a question.
Frequently asked questions
What is the difference between while and do-while in C++?
while tests first, so its body can be skipped entirely; do-while runs the body once and only then tests, which means at least one execution. Use do-while for patterns like showing a menu and then asking whether to repeat.
How does a range-based for loop work in C++?
for (auto x : container) visits each element in order without needing an index. By default x is a copy. Write auto& to modify elements in place or const auto& to read them without copying. It works on vectors, arrays, strings and other standard containers.
Why do I need break in a C++ switch statement?
Without break, execution continues from the matching case into the following cases until a break or the end of the switch, which is called fall-through. This is occasionally useful, but is more often a bug, so end each case with break unless you mean to share code.