munotes®

else-if Ladders

Chapter Twenty-Five

Syllabus topic 1, "Control Flow: Statements and Blocks, If-Else, Else-If, Switch, Loops- While and For Loops Do-while, Break and Continue, Goto and Labels"

Pages 117 to 121 of 222

In one line

An else-if ladder is a chain of tests where the first one that succeeds runs its block and the rest are skipped, so the order of the tests is part of the logic.

It is not a new construct

if (condition1) {
    ...
} else if (condition2) {
    ...
} else {
    ...
}

Read what that really is. An else governs one statement, and an if is one statement, so the second if is simply the else branch of the first. Written out with all the braces the compiler infers:

if (condition1) {
    ...
} else {
    if (condition2) {
        ...
    } else { ... }
}

A third else if adds a third level inside that innermost else. The ladder layout is the same nesting written flat, and it exists because the nested version marches across the page. Nothing about the language was added; only the layout changed.

Two consequences follow, and both are examinable.

  1. The tests are tried in order and the first true one wins. Everything below it is skipped, including tests that are also true.
  2. The final else is optional and catches everything the tests missed.

The order is the logic

#include <stdio.h>

char grade_wrong(int marks)
{
    if (marks >= 40) return 'D';        /* catches everything above 40 */
    else if (marks >= 50) return 'C';
    else if (marks >= 60) return 'A';
    else if (marks >= 70) return 'O';
    else return 'F';
}

char grade_right(int marks)
{
    if (marks >= 70) return 'O';
    else if (marks >= 60) return 'A';
    else if (marks >= 55) return 'B';
    else if (marks >= 50) return 'C';
    else if (marks >= 40) return 'D';
    else return 'F';
}

int main(void)
{
    int marks[] = {85, 63, 57, 52, 45, 30};

    printf("marks  wrong  right\n");
    for (int i = 0; i < 6; i++) {
        printf("%5d  %5c  %5c\n",
               marks[i], grade_wrong(marks[i]), grade_right(marks[i]));
    }
    return 0;
}
marks  wrong  right
   85      D      O
   63      D      A
   57      D      B
   52      D      C
   45      D      D
   30      F      F

Both ladders have the same five tests and one gives the wrong grade for every mark above 40. A ladder of overlapping tests must be ordered from the most demanding to the least. That is the whole lesson, and it is the commonest logic error in a first-semester program.

Because the earlier tests have already been ruled out, the later ones need no upper bound. marks >= 60 in grade_right means "at least 60 and, since we are here, below 70". Writing marks >= 60 && marks < 70 is correct and redundant, and the redundancy is a second place for a mistake to live.

munotes.in117

else-if Ladders

The practical: the roots of a quadratic equation

MU's Practical 2(a). For ax^2 + bx + c = 0 the discriminant is b^2 - 4ac, and its sign decides the kind of roots. That is three cases, so it is a ladder.

#include <stdio.h>
#include <math.h>

int main(void)
{
    double a, b, c;

    printf("Enter a, b and c for a*x*x + b*x + c = 0: ");
    if (scanf("%lf %lf %lf", &a, &b, &c) != 3) {
        printf("\nThose were not three numbers.\n");
        return 1;
    }
    if (fabs(a) < 1e-12) {
        printf("\nWith a = 0 this is not a quadratic equation.\n");
        return 1;
    }

    double d = b * b - 4 * a * c;

    printf("\nDiscriminant b*b - 4*a*c = %.4f\n", d);
    if (d > 1e-12) {
        double r1 = (-b + sqrt(d)) / (2 * a);
        double r2 = (-b - sqrt(d)) / (2 * a);
        printf("Two distinct real roots: %.4f and %.4f\n", r1, r2);
    } else if (d > -1e-12) {
        double r = -b / (2 * a);
        printf("One repeated real root: %.4f\n", r);
    } else {
        double real = -b / (2 * a);
        double imag = sqrt(-d) / (2 * a);
        printf("Two complex roots: %.4f + %.4fi and %.4f - %.4fi\n",
               real, imag, real, imag);
    }
    return 0;
}
1 -7 12
Enter a, b and c for a*x*x + b*x + c = 0:
Discriminant b*b - 4*a*c = 1.0000
Two distinct real roots: 4.0000 and 3.0000

Four things in that program are the difference between a pass and a good mark.

1. a is checked for zero first. With a zero the formula divides by zero, and the equation is not quadratic anyway. No textbook solution checks this and the viva question is always "what if a is zero".

2. The discriminant is never compared with ==. It is a double computed by arithmetic, so the exactly-zero case will usually miss by a fraction. Chapter 9's rule applies: the tests are d > tolerance for positive, then d > -tolerance for what is left, which means "within the tolerance of zero", and the final else is genuinely negative.

Read those two tests as a ladder and the trick becomes clear: by the time the second test runs, d > 1e-12 has already failed, so d > -1e-12 can only mean -1e-12 < d <= 1e-12. The ladder did the work that an && would otherwise have to.

3. sqrt(-d) and not sqrt(d) in the complex branch. d is negative there, and sqrt of a negative double gives a not-a-number value.

4. 1e-12 is a choice, not a constant of nature. It is small relative to the sizes in this problem. For very large coefficients it would be too small and for very small ones too large; saying so in a viva is worth more than the program.

munotes.in118

else-if Ladders

Run with different coefficients and the other two branches show:

#include <stdio.h>
#include <math.h>

int main(void)
{
    double sets[3][3] = {{1, -7, 12}, {1, -4, 4}, {1, 2, 5}};

    for (int i = 0; i < 3; i++) {
        double a = sets[i][0], b = sets[i][1], c = sets[i][2];
        double d = b * b - 4 * a * c;

        printf("a=%.0f b=%.0f c=%.0f  d=%.0f  ", a, b, c, d);
        if (d > 1e-12) {
            printf("real and distinct: %.4f, %.4f\n",
                   (-b + sqrt(d)) / (2 * a), (-b - sqrt(d)) / (2 * a));
        } else if (d > -1e-12) {
            printf("real and repeated: %.4f\n", -b / (2 * a));
        } else {
            printf("complex: %.4f +/- %.4fi\n",
                   -b / (2 * a), sqrt(-d) / (2 * a));
        }
    }
    return 0;
}
a=1 b=-7 c=12  d=1  real and distinct: 4.0000, 3.0000
a=1 b=-4 c=4  d=0  real and repeated: 2.0000
a=1 b=2 c=5  d=-16  complex: -1.0000 +/- 2.0000i

The leap year as a ladder

Chapter 16 wrote the leap-year rule as one expression. It is also three nested exceptions, and written as a ladder it reads as the rule itself:

#include <stdio.h>

int is_leap(int year)
{
    if (year % 400 == 0) {
        return 1;                 /* a century divisible by 400 IS a leap year */
    } else if (year % 100 == 0) {
        return 0;                 /* any other century is NOT */
    } else if (year % 4 == 0) {
        return 1;                 /* otherwise divisible by 4 IS */
    } else {
        return 0;
    }
}

int main(void)
{
    int years[] = {1900, 1996, 2000, 2023, 2024, 2100, 2400};

    for (int i = 0; i < 7; i++) {
        printf("%d %s\n", years[i], is_leap(years[i]) ? "leap" : "not leap");
    }
    return 0;
}
1900 not leap
1996 leap
2000 leap
2023 not leap
2024 leap
2100 not leap
2400 leap

Notice the order: most specific first. 400 before 100 before 4. Written the other way round, year % 4 would catch 1900 and answer wrongly. It is the same ordering lesson as the grades, in a form MU actually sets.

When to use a ladder, and when not to

SituationUse
Tests on ranges of a valueelse-if ladder
Tests on different variableselse-if ladder
A condition too complex for a tableelse-if ladder
Comparing one integer or char against separate constant valuesswitch, chapter 26
Choosing between two values rather than two actions?:, chapter 19
More than about six branches on one valueswitch, or a table

A ladder on a single variable against single values is what switch is for, and switch says so more clearly:

munotes.in119

else-if Ladders

if (choice == 1) { ... }
else if (choice == 2) { ... }
else if (choice == 3) { ... }

What this does NOT mean

else if is not a keyword. It is else followed by an if statement. C has no elif and no elseif.

A ladder does not test every condition. It stops at the first true one. This is why order matters and why later tests need no lower bound.

The final else is not required. Without one, a value matching no test simply falls through and nothing happens, which is sometimes right and is often a missing case.

A ladder is not a switch. A ladder tests arbitrary conditions; switch compares one integer expression against constants. Neither replaces the other.

Ordering from most to least demanding is not a style preference. Reversed, the ladder gives wrong answers, as grade_wrong shows.

Quick revision

  • An else-if ladder is nested if-else written flat. Nothing was added to the language.
  • The tests run in order; the first true one wins and the rest are skipped.
  • Order overlapping tests from most demanding to least.
  • Later tests need no upper bound, because earlier ones have been ruled out.
  • The final else is optional and catches everything else.
  • Quadratic roots: check a is not zero, then the sign of bb - 4a*c, with a tolerance rather than ==.
  • sqrt(-d) in the complex branch, because d is negative there.
  • Leap year as a ladder: 400, then 100, then 4, in that order.
  • Use switch where one integer is compared against separate constants.

Test yourself

1. Is else if a single keyword?

No. It is an else whose governed statement is another if. The ladder layout is nested if-else written flat.

2. What is wrong with this ladder?

if (m >= 40) g = 'D';
else if (m >= 70) g = 'O';

Everything from 70 upwards satisfies the first test, so the second is never reached. Order from most demanding to least: test 70 first.

3. In the quadratic program, why is the second test d > -1e-12 rather than d == 0?

Because d is a double computed by arithmetic and will rarely be exactly zero even when the roots are repeated. The ladder has already ruled out d > 1e-12, so d > -1e-12 means d is within the tolerance of zero.

4. Why must a be checked before the discriminant?

Because 2 * a is a divisor in every branch, and with a zero the equation is not quadratic at all.

munotes.in120

else-if Ladders

5. Write the leap-year test as a ladder and say why the order cannot be reversed.

Test year % 400 == 0 first, then year % 100 == 0, then year % 4 == 0. Reversed, year % 4 would catch 1900 and report it as a leap year, because the century exception would never be reached.

6. When is a switch better than a ladder?

When a single integer or character expression is being compared against separate constant values, as in a menu. switch states that intent and the compiler can often implement it as a jump table.

What can be asked on this, and how to answer it

"Explain the else-if ladder with syntax and an example." Give the syntax, say plainly that it is nested if-else written flat and that else if is not a keyword, then give the grade program. Include the ordering rule and one example of it going wrong, because that is what the question is really testing.

"Write a program to find the roots of a quadratic equation." Give this chapter's program. Keep the a == 0 check and the tolerance, and be ready to explain both: those are the two follow-up questions.

"Write a program to find the grade of a student from marks." Give grade_right, ordered from the highest boundary down, and say in one line why later tests need no upper bound.

"Distinguish between an else-if ladder and a switch statement." A ladder tests any conditions at all, on any number of variables, in a fixed order. A switch compares one integer or character expression against constant values, in no particular order, and may fall through. Use a ladder for ranges and a switch for discrete values. Add that switch cannot test a double or a string.

munotes.in121

The rest of this subject

These notes are cut from the University's printed syllabus. Open the syllabus itself for the same subject.

Report or request
Done!