Embercode
✕
C++ ConditionalsLesson 2 of 14

55 min read

else if ladders and nested if

Why this matters

Most real decisions have more than two outcomes. A grade is A, B, C, D or F. A shipping cost depends on the weight band. A traffic light is red, amber or green. An if with one else can only split the world in two, so you need a way to chain decisions together. C++ gives you two tools for this: the else if ladder, which picks one outcome from a list, and the nested if, which places one decision inside another. Interviewers ask about both, and both break in the same few predictable ways. Learning those ways now saves you from hunting them later.

The idea in everyday words

Imagine a sorting desk at a post office. A parcel arrives. The clerk asks: is it heavier than 20 kilograms? If yes, it goes to the freight bay. If no, the clerk asks the next question: is it heavier than 5 kilograms? If yes, it goes to the standard bay. If no, it goes to the light-parcel bay. The clerk asks the questions in order and stops at the first question that gives a yes.

That is an else if ladder. Each question is one rung of the ladder. The parcel climbs down the rungs until one of them catches it. The order of the rungs matters a great deal. If the clerk asked "heavier than 5 kilograms?" first, every heavy parcel would go to the standard bay, and the freight bay would never be used.

A nested if is a different picture. Imagine a second clerk who only sees parcels that the first clerk sent to the freight bay. That clerk asks whether the parcel is fragile, and then sends it to a special room. The second question only makes sense because of the answer to the first. The inner decision is inside the outer one.

Both pictures describe decisions that depend on earlier decisions. The difference is shape. A ladder is a flat list of tests, and the first true test wins. A nest is a decision inside a branch of another decision.

The else if ladder

A ladder is written as an if, followed by one or more else if branches, and finally an optional else. Each else if is tested only when every test above it was false. The first test that is true runs its block, and then the whole ladder is finished. The rest of the rungs are skipped.

Here is a grade program. It reads a score out of 100 and prints a letter.

C++ · editable

Type 72 into the Input box and press Run. The output is:

grade C

Trace it step by step. The first test, 72 >= 90, is false, so the program moves down to the next rung. 72 >= 80 is false, so it moves on again. 72 >= 70 is true. The program prints grade C and jumps to the end of the whole ladder. It never looks at the >= 60 rung, and the final else does not run, because a later rung was already caught.

Each condition in this ladder is written as a range that starts at one value and goes up to the next. The test score >= 80 only needs to say "at least 80", because the program already knows the score is below 90. This is the first thing the ladder teaches you. Each rung can assume that every rung above it was false. You do not need to repeat that information in the condition.

The final else covers everything that no rung caught. Here it means any score below 60. It is optional. Without it, a score of 40 would print nothing. Leaving the else out is sometimes exactly right, but when you do it, be sure that silence is the correct behaviour.

Why the order matters

The most common ladder bug is putting the rungs in the wrong order. Suppose you write the same grades with the tests reversed:

if (score >= 60) {
    cout << "grade D" << endl;
} else if (score >= 70) {
    cout << "grade C" << endl;
}

Every score of 60 or more matches the first rung, so the program prints grade D for 95 and for 72. The later rungs are never reached, because the first one always catches them. The code is valid C++ and compiles without an error. Nothing tells you that it is wrong, and this is what makes order bugs dangerous.

The safe rule is simple: put the most specific or most restrictive test first. When the tests are all "at least" checks, that means the highest threshold goes first. When the tests are a mix, ask which case is the most special and test it first.

Here is a famous interview example, FizzBuzz. For a number, print Fizz if it is a multiple of 3, Buzz if it is a multiple of 5, FizzBuzz if it is a multiple of both, and the number itself otherwise. A multiple of 15 is also a multiple of 3, so the case for both must come first. Here is the wrong order.

C++ · editable

Type 15 into the Input box. The output is:

Fizz

The number 15 divides by 3, so the first rung catches it, and the rung for 15 is never reached. The rung that checks for 15 is dead code: no input can ever reach it, because every multiple of 15 is caught above. The compiler does not warn about this, so you have to notice it by reading. The fix is to move the test for 15 to the top:

C++ · editable

With the input 15, this prints FizzBuzz. With the input 9, it prints Fizz. With 10, it prints Buzz. With 7, it prints 7. Try all four in the Input box so you see each rung fire.

A useful test for any ladder is to ask, for each rung, "is there an input that reaches this rung and nowhere else?" If there is none, the rung is dead. Dead rungs are the sign of an order bug.

Overlapping and gaps

A ladder can go wrong in a second way. Its tests can overlap, so two rungs could both be true, or they can leave a gap, so no rung is true. Overlap is usually harmless if the order is right, because the first rung wins. A gap is the more serious problem, because the program silently does nothing for those inputs. An else at the bottom closes the gap, and the ladder is then complete.

Look back at the ladder with score >= 60 as the last test. The final else covers everything under 60, so there is no gap. Without the else the program would print nothing for a score of 40. That might be a bug or it might be a design decision. Either way, decide it on purpose.

When the tests use == on a whole number, gaps are easy to see. Suppose you test a day number with day == 1, day == 2 and so on up to day == 7. A day == 8 input falls through all of them and prints nothing. A closing else that reports an invalid day handles it.

Nested if: a decision inside a decision

Now the second tool. A nested if is an if placed inside a block of another if or else. The inner decision is asked only when the outer one reaches it. This is how you express a rule that depends on a previous answer.

Consider a cinema ticket. The base price depends on age: children under 12 pay less, and people aged 65 or older pay a little less than adults. Adults pay extra on weekends. The weekend rule depends on being an adult, so it belongs inside the adult branch.

C++ · editable

Type 30 1 into the Input box. The first test, 30 < 12, is false. The second test, 30 >= 65, is false. So the program reaches the else branch, which sets the price to 10. Then it asks the nested question. Is weekend equal to 1? Yes, so the price rises by 3 to 13. The output is:

Price: 13

Now type 10 1. The child rung catches the input, the price is 5, and the nested question is never asked. The weekend flag has no effect for children, which is what the rule says. Finally, 30 0 gives 10, because the nested test is asked and is false.

Notice how the shape of the code matches the shape of the rule. The rule "adults pay extra on weekends" is written inside the adult branch. A reader can see at a glance that the surcharge applies only to adults. If you had written the weekend check as a separate if at the top level, it would be easy to forget that children and seniors are excluded.

The nested question can also use a different variable from the outer one. The outer test looks at age. The inner test looks at the weekend flag. A nested if is not limited to repeating the same variable.

Nested if versus a flat condition

Sometimes you can write the same logic with a single condition joined with &&. The ticket rule could be written as a flat test: "if the age is between 12 and 64 and it is the weekend, add 3". The two versions give the same answer. Which one is better depends on how the rule reads.

Use a flat condition when the extra test is a simple property of the same case. Use a nested if when the inner test only makes sense after the outer test has been decided, or when the inner branch has its own else. In the ticket program, the adult branch sets a base price and then changes it on weekends. Nesting shows that structure. A flat condition would hide it.

A good rule of thumb: if a nested if gets deeper than two or three levels, that is a warning. Deep nesting is hard to read, and it is usually a sign that the logic should be split into named steps, or into a function once you reach the functions module. You can reduce nesting in a few ways. You can test for the exceptional cases first and leave early, or you can compute a flag with a name and test the name.

The dangling else

The nested if has one famous trap. When an if is followed by another if without braces, an else pairs with the nearest if that does not already have an else. The indentation you see on the screen does not change that pairing. Here is an example.

C++ · editable

The output is:

end

The else indented under the outer if looks as though it belongs to if (a > 0). It does not. It belongs to if (b > 0), which is the nearest if without an else. Since a is 0, the outer test is false, and the inner if is never reached. Therefore neither A nor B prints. The end line runs because it is after the whole structure.

The fix is braces, which make the pairing explicit:

if (a > 0) {
    if (b > 0) {
        cout << "A";
    }
} else {
    cout << "B";
}

Now the else clearly belongs to the outer if. With a equal to 0, this version prints B. The rule to remember is simple: always use braces around nested blocks, and never depend on indentation to show what belongs together. Indentation is for the human reader, and the compiler ignores it.

Guard checks: test the exceptions first

A common way to flatten nested decisions is to handle the bad or special cases at the top and leave early. In a program that does not yet have functions, you can leave early with return from main. Here is a triangle classifier written that way. The shape of a triangle is a useful interview example, because it has several conditions that depend on each other.

A triangle needs three sides that are all positive. Also, the two shorter sides must add up to more than the longest side. That second rule is called the triangle inequality. If the sides are 1, 2 and 10, the short sides cannot reach across, so no triangle exists. Once the sides form a real triangle, it is equilateral if all three sides are equal, isosceles if exactly two are equal, and scalene if none are equal.

C++ · editable

Type 3 4 5 into the Input box. Trace it:

  1. The first test asks whether any side is zero or less. None is, so the program takes the else.
  2. The triangle test checks 3 + 4 > 5, 3 + 5 > 4 and 4 + 5 > 3. All three are true, so the program enters the next nested block.
  3. The equal-sides test a == b && b == c is false, because 3 is not 4.
  4. The isosceles test asks whether any pair is equal. None is, so the program takes the final else.
  5. It prints scalene.

The output is:

scalene

Now the same program gives invalid for 1 2 10, because the triangle test 1 + 2 > 10 is false. It gives equilateral for 4 4 4 and isosceles for 5 5 3.

Read this program as an example of nesting done neatly. Each outer test filters out the cases that the inner tests do not need to consider. The invalid cases are handled at the top, and the inner tests only ever see sides that form a real triangle. A reader who understands the rule can read the code in the same order as the rule.

The triangle test deserves one more look. Its three parts are joined with &&, because all three must be true for a real triangle. The || in the isosceles test means any one equal pair is enough. Getting those two operators right is the core of the problem, and interviewers often ask about exactly that.

Binary search: a nest of decisions that halves the range

Ranges and nested decisions meet in the most important search algorithm you will learn. Binary search finds a value in a sorted list by looking at the middle, then deciding which half to keep. Each decision throws away half of what is left. The decisions are a nest of ifs: is the target the middle? If not, is it below the middle? Then search the left half, otherwise the right half.

Step through the search below. Watch how each step removes half of the remaining range, and notice that the code for one step is exactly an if, an else if and an else.

20lo5182123164235386567hi

lo, mid and hi are labelled under the boxes. An outlined box is the middle, a dashed faint box is outside the search range, a filled box is the found item.

Look for 23 in the sorted list. The search range is the whole list.

Step 1 of 4

The program below does one step of that search. It reads a range from lo to hi, and a target. It computes the middle and prints the half that still needs checking.

C++ · editable

Type 1 100 73 into the Input box. The middle is (1 + 100) / 2. Integer division drops the fraction, so the middle is 50. The target 73 is not 50, and it is larger, so the else runs. The output is:

search right half: 51..100

The order of the tests is the same lesson as the ladder. The equality test must come first, because a target that equals the middle is found and needs no further search. If the test for "less than the middle" came first, an equal target would fall into the wrong branch.

A full binary search repeats this step until the range is empty or the target is found. Each step halves the range, so searching a list of a million sorted numbers takes about 20 steps. The running time is O(log n), which means the work grows by one step each time the input doubles. Compare that with a plain scan, which can take a million steps. You will write the full loop in the next module. For now, the important point is that a binary search is nothing more than repeated decisions between halves, and you already know how to write those.

Using the ladder and the nest together

Real code uses both tools together. The ticket example used a ladder for the age groups and a nested if for the weekend rule. The triangle example used guards at the top and a nest below. When you design a decision, think about the shape first:

  • Are the outcomes mutually exclusive and each set by one test? Use a ladder.
  • Does a branch need its own further decision that depends on the outer test? Use a nested if inside that branch.
  • Are there invalid inputs that should stop the program at once? Test them first and handle them in their own branch.
  • Would the rule be easier to read as a single flat condition? Use && or || and keep the code flat.

A decision like this is easy to draw on paper before you write it. Put each test in a box, and each outcome in another box, then connect them with arrows labelled yes and no. The diagram below shows the grade ladder. Read it from the top, and notice that the first yes stops the climb.

A ladder of tests from score at least 90 down to score at least 60, where the first yes sends the program to its grade and skips the restA ladder of tests from score at least 90 down to score at least 60, where the first yes sends the program to its grade and skips the rest

The next diagram shows the difference between a nest and a ladder. The inner question is only asked if the outer one says yes. Pay attention to the bottom branches, because the else on the inner question belongs to the inner question, which is the dangling else in picture form.

A nested if where the inner test belongs to the outer yes branch, and the else of the inner test is attached to it rather than to the outer testA nested if where the inner test belongs to the outer yes branch, and the else of the inner test is attached to it rather than to the outer test

What happens inside

When the processor runs a ladder, it executes the tests one after another in source order. Each false test is a comparison followed by a jump to the next rung. The first true test runs its block and then jumps to the end of the whole ladder. The cost of a ladder therefore depends on which rung catches the input. A value at the top rung costs one test. A value at the bottom costs every test. This is why the order of tests can matter for speed, as well as for correctness.

Nested ifs cost the same kind of work. The outer test runs for every input. The inner tests run only for the inputs that reach them. A deep nest is still just a set of comparisons and jumps. The compiler may rearrange some of them, because it knows the results cannot change what the program prints. You do not control that, and you do not need to. Your job is to make the logic correct and easy to read. Speed differences from ordering are rarely important until you are writing code that runs millions of times per second.

Common mistakes

These are the mistakes most often made with ladders and nests. Each one has a symptom that you can recognise.

Wrong order in a ladder. The symptom is that a rung you expected to fire never does, and a broader rung fires in its place. The fix is to test the most specific case first. Check each rung for an input that can reach it.

A dead rung. A rung that no input can reach is a bug, even though the compiler is silent. It usually comes from the wrong order or from overlapping conditions. Walk through the ladder by hand with a few inputs, and any rung that never fires will show up.

A missing else at the bottom of a ladder. The symptom is that some inputs print nothing at all. Decide on purpose whether silence is correct, and add an else for the invalid or unexpected case.

Using if where you wanted else if. If the second test is a separate if, both tests run. Two separate if statements are two separate decisions. For a score of 95, the output can then contain two grades. The symptom is two lines of output where you expected one.

Writing else if but meaning if. The reverse is also true. If you want two independent checks, they need separate if statements. An else if says that the second check happens only when the first was false.

The dangling else. The symptom is an else that seems to attach to the wrong test. The fix is braces around every nested block.

Too much nesting. The symptom is code that drifts off the right side of the screen. Flatten it with guard checks at the top, or give a complicated test a name.

Testing the same thing twice. Inside a rung, you do not need to repeat the test that the rung above already covered. score >= 70 does not need to say score < 80 as well, because the rung above already dealt with the scores of 80 and above. Repeating the test is harmless but hides the logic.

Debugging a ladder

When a ladder gives an unexpected answer, add one print per rung, so that you see which branch ran. For the grade ladder, the debug version looks like this:

if (score >= 90) {
    cout << "branch A" << endl;
    cout << "grade A" << endl;
} else if (score >= 80) {
    cout << "branch B" << endl;
    cout << "grade B" << endl;
}

With these prints in place, the output shows the branch that was taken, and the grade. If the branch and the grade disagree, the bug is in the grade code. If the wrong branch was taken, the bug is in the test. If no branch was printed, the input reached the final else, or no rung matched.

For a nest, print the outer decision and the inner decision separately. A common debugging move is to print the values that each test depends on before the test runs. For the ticket program, print age and weekend before the first if. That tells you immediately whether an unexpected price came from bad input or from bad logic.

Interview-style questions

Interviewers ask about decision structures in a few recurring forms. Here are three to practise, with the point each one tests.

Classify a point. Given a point (x, y), say whether it is in the first, second, third or fourth quadrant, or on an axis. The point of the question is to see whether you handle the axes, where one coordinate is zero, as their own case. A correct answer uses a ladder with the zero cases first.

Leap year. A year is a leap year if it divides by 4, except that years divisible by 100 are not leap years, unless they are divisible by 400. The point is the order of the tests. Test the 400 case first, then the 100 case, then the 4 case. Many candidates get the century rule wrong.

Compare two dates. Given two dates as day, month and year, say which is earlier. The point is nesting. Compare the years first. Only if the years match do you compare the months, and only if the months match do you compare the days. Each level is a nested if, and the answer is decided by the first level that differs.

All three questions are solved in O(1) time, because the number of tests is fixed. Say so when you answer, because it shows you understand that the cost does not grow with the size of the input.

Reviewing a ladder written by someone else

A reviewer reads a ladder from the top, asking the same question at each rung: which inputs reach this line, and which inputs stop here? Doing this for every rung catches the two ladder bugs in this lesson, the wrong order and the dead rung, in a few minutes.

Start with the first rung. Is it the most specific test? If it is a broad test, such as a range that covers most inputs, ask whether a narrower case below it can ever be reached. In the FizzBuzz example, a broad test for multiples of 3 at the top hid the more specific test for multiples of 15. A reviewer who asks "what does this rung catch that the rungs above did not?" finds the problem at once.

Next, check each rung's boundary. Write down the lowest value that reaches the rung and the highest value that does. If the two are not what the rule says, the boundary is off by one. Pay particular attention to > against >=, because they differ by exactly one value.

Then look for the bottom of the ladder. Is there an else? If there is none, decide what the program should do with an input that matches no rung, and check that the code does that. Silence is sometimes correct, but it should be a choice, not an accident.

Finally, look at the nesting. Does an inner test sit under the right outer branch? Are the braces around each block? A nested block without braces is the most common reason a reviewer asks for changes, because the indentation of the code often disagrees with the way the compiler reads it.

A review comment in the same style as the switch review works well. For example: "The rung score >= 60 comes before score >= 90, so every A is printed as D. Move the test for 90 to the top." Give the rung, say what goes wrong, and give the fix. Your reviewers will do the same for you.

Real-world uses

Ladders appear wherever a value falls into a band. A tax calculator uses bands of income. A shipping service uses bands of weight. A video game uses bands of score to choose a level. A logging library uses bands of severity, so that a message at level "error" is printed and one at level "debug" is not. In every case the bands are the rungs, and the order is set by the rule.

Nested decisions appear wherever a rule has exceptions to exceptions. A discount depends on the customer type, then on the product, then on the date. A login depends on the account, then on the password, then on whether the account is locked. A permission check asks whether the user is an admin, then whether the file is public, then whether the owner matches. Each level of the nest narrows the question, which keeps each individual test simple.

A practice routine for decisions

When you are learning, use a short routine for every decision you write. It catches most of the mistakes in this lesson before you run the program.

  1. Write the rules as a list of outcomes in order, most specific first.
  2. Draw the ladder or nest on paper, with one box per test.
  3. For each rung, find one input that reaches it. If you cannot, the rung is dead, and you must reorder or remove it.
  4. Find one input that falls past every rung. Decide what it should print, and make sure an else does that.
  5. Write the code with braces on every block.
  6. Test one input for each rung and one input on each boundary. Compare the output with your list from step 1.

What you now know

  • An else if ladder tests conditions in order, and only the first true test runs. Put the most specific test first.
  • A dead rung, which no input can reach, is a sign of an order bug. Walk each rung with a real input to check.
  • A nested if asks its inner question only when the outer one says yes. Use it when the second test depends on the first.
  • An else pairs with the nearest if above it that has no else. Use braces so that the pairing is clear.
  • Guard checks for invalid inputs at the top make a nest shallow and easy to read.
  • Binary search is a nest of ifs that keeps one half of a sorted range at each step.

The next lesson introduces switch, which chooses one branch by matching a value exactly, and explains when it is a better fit than a ladder.

Practice

Write each program, compile it with -Wall, and test it on the boundaries before you check the solution. Write the expected output on paper first.

  1. Read one integer. Print small if it is below 10, medium if it is from 10 to 99, and large if it is 100 or more. Test 9, 10, 99 and 100.
Solution
#include <iostream>
using namespace std;
 
int main() {
    int n;
    cin >> n;
    if (n < 10) {
        cout << "small" << endl;
    } else if (n < 100) {
        cout << "medium" << endl;
    } else {
        cout << "large" << endl;
    }
    return 0;
}

The rungs use only the upper bound, because each rung can assume the rungs above it were false.

  1. Read one integer score from 0 to 100. Print the letter grade using the bands in this lesson. Then reverse the tests on purpose, so that you can see the order bug for yourself. Describe the output the reversed version gives for 95.
Solution

The correct version is the grade ladder from this lesson, with >= 90, >= 80, >= 70 and >= 60 in that order, and a final else for F. The reversed version tests >= 60 first, so 95 prints D. Every score of 60 or more is caught by the first rung, so the letters for 70, 80 and 90 never print.

  1. Read one integer n. Print prime if it is a prime number and not prime otherwise, for values from 2 to 20. Explain why checking only the divisors 2 and 3 is enough for values up to 20.
Solution
#include <iostream>
using namespace std;
 
int main() {
    int n;
    cin >> n;
    bool prime = true;
    if (n % 2 == 0 && n != 2) {
        prime = false;
    } else if (n % 3 == 0 && n != 3) {
        prime = false;
    } else if (n % 5 == 0 && n != 5) {
        prime = false;
    } else if (n % 7 == 0 && n != 7) {
        prime = false;
    }
    if (prime) {
        cout << "prime" << endl;
    } else {
        cout << "not prime" << endl;
    }
    return 0;
}

Any composite number has a factor no larger than its square root. The square root of 20 is about 4.5, so every composite number up to 20 has a factor of 2 or 3. The tests for 5 and 7 never change the answer, but they show the pattern for larger limits. The n != 2 style guards keep the small primes themselves from being flagged as composite.

  1. Read two integers hour and minute on a 24-hour clock. Print morning for times before 12:00, afternoon for 12:00 to 17:59, and evening for 18:00 onward. Test 11 59, 12 0, 17 59 and 18 0.
Solution
#include <iostream>
using namespace std;
 
int main() {
    int hour, minute;
    cin >> hour >> minute;
    if (hour < 12) {
        cout << "morning" << endl;
    } else if (hour < 18) {
        cout << "afternoon" << endl;
    } else {
        cout << "evening" << endl;
    }
    return 0;
}

The minute is read but does not change the answer in this version. Each boundary is at a whole hour, so 11 59 is morning and 12 0 is afternoon. The minute check is needed only if the bands had boundaries in the middle of an hour.

  1. Read one integer n. Print Fizz for multiples of 3 only, Buzz for multiples of 5 only, FizzBuzz for multiples of both, and other otherwise. Test 3, 5, 15 and 7.
Solution
#include <iostream>
using namespace std;
 
int main() {
    int n;
    cin >> n;
    if (n % 15 == 0) {
        cout << "FizzBuzz" << endl;
    } else if (n % 3 == 0) {
        cout << "Fizz" << endl;
    } else if (n % 5 == 0) {
        cout << "Buzz" << endl;
    } else {
        cout << "other" << endl;
    }
    return 0;
}

The test for 15 must come first. Otherwise every multiple of 15 would match the test for 3.

  1. Read four integers x1 y1 x2 y2. Print same point if they are equal, same row if only y matches, same column if only x matches, and different otherwise. Use nested ifs so that the row and column tests happen only when the point differs from the first.
Solution
#include <iostream>
using namespace std;
 
int main() {
    int x1, y1, x2, y2;
    cin >> x1 >> y1 >> x2 >> y2;
    if (x1 == x2) {
        if (y1 == y2) {
            cout << "same point" << endl;
        } else {
            cout << "same column" << endl;
        }
    } else {
        if (y1 == y2) {
            cout << "same row" << endl;
        } else {
            cout << "different" << endl;
        }
    }
    return 0;
}

The outer test splits on whether x matches, and the inner tests decide the rest. Each inner else belongs to the inner if, and braces make that visible.

  1. Read three integers a b c. Print yes if a is strictly between b and c, in either order, and no otherwise. Test 5 1 9, 9 1 5, 1 1 9 and 5 5 9.
Solution
#include <iostream>
using namespace std;
 
int main() {
    int a, b, c;
    cin >> a >> b >> c;
    if ((b < a && a < c) || (c < a && a < b)) {
        cout << "yes" << endl;
    } else {
        cout << "no" << endl;
    }
    return 0;
}

The two alternatives cover the two orders of b and c. The brackets around each pair make the grouping clear. The inputs 1 1 9 and 5 5 9 are no because the value is on an end or the ends are equal.

  1. Read one integer n. Print negative even, negative odd, zero, positive even or positive odd, using one ladder for the sign and a nested if for even or odd. Test -4, -3, 0, 6 and 7.
Solution
#include <iostream>
using namespace std;
 
int main() {
    int n;
    cin >> n;
    if (n < 0) {
        if (n % 2 == 0) {
            cout << "negative even" << endl;
        } else {
            cout << "negative odd" << endl;
        }
    } else if (n == 0) {
        cout << "zero" << endl;
    } else {
        if (n % 2 == 0) {
            cout << "positive even" << endl;
        } else {
            cout << "positive odd" << endl;
        }
    }
    return 0;
}

The sign ladder separates the three cases, and the parity test is nested inside the two non-zero branches. In C++ the remainder of -3 is -1, so n % 2 == 0 is false for -3, which correctly gives negative odd.

  1. Explain in your own words why the output of the dangling-else example above is end and not B or A. Then write the braces version that prints B for the same input, and check it by running it.
Solution

The else belongs to the inner if (b > 0). The outer test a > 0 is false, so the inner if is never reached, and neither A nor B can print. The output is the single line end. The braces version is the one shown earlier in this lesson, with the else attached to the outer test. With a equal to 0, that version prints B and then end on the next line.

Practice this topic: coding problems for C++ Conditionals →

Stuck? Ask the tutor

Ask about anything in this lesson. Answers are short and use simple words.

Sign in to ask the tutor.

← if and else