munotes®

The Conditional Operator

Chapter Nineteen

Syllabus topic 2, "Type of operators: Arithmetic operators, relational and logical operators, Increment and Decrement operators, assignment operators, the conditional operator, Assignment operators and expression, Precedence and order of Evaluation Block Structure, Initialization, C Preprocessor"

Pages 90 to 93 of 222

In one line

condition ? a : b is an expression whose value is a when the condition is true and b when it is false, and it is the only operator in C that takes three operands.

Why an operator and not just if

if is a statement. It chooses which statement to run. An expression cannot contain a statement, so with if alone there is no way to write "this value or that value" in the middle of something else.

printf("you %s\n", marks >= 40 ? "passed" : "failed");

That cannot be done with if without splitting it into several statements or repeating the printf. The conditional operator is what fills the gap, which is why it is sometimes called the ternary operator: it is the only operator in C with three operands, so "the ternary operator" and "the conditional operator" mean the same thing.

The form

condition ? value-if-true : value-if-false

The condition is evaluated. If it is non-zero, the whole expression is the second operand; otherwise it is the third. Exactly one of the two is evaluated, which is the same guarantee && and || give and which the next section proves.

#include <stdio.h>

int main(void)
{
    int marks = 63;
    int a = 12, b = 47;

    printf("marks %d: %s\n", marks, marks >= 40 ? "pass" : "fail");
    printf("the larger of %d and %d is %d\n", a, b, a > b ? a : b);
    printf("the smaller is %d\n", a < b ? a : b);
    printf("%d is %s\n", a, a % 2 == 0 ? "even" : "odd");
    printf("the absolute value of -7 is %d\n", -7 < 0 ? -(-7) : -7);
    return 0;
}
marks 63: pass
the larger of 12 and 47 is 47
the smaller is 12
12 is even
the absolute value of -7 is 7

It sequences, and only one branch runs

#include <stdio.h>

int calls = 0;

int noisy(int value)
{
    calls = calls + 1;
    return value;
}

int main(void)
{
    int x;

    calls = 0;
    x = 1 ? 10 : noisy(20);
    printf("1 ? 10 : noisy(20) gave %d, and noisy ran %d time(s)\n", x, calls);

    calls = 0;
    x = 0 ? noisy(10) : 20;
    printf("0 ? noisy(10) : 20 gave %d, and noisy ran %d time(s)\n", x, calls);
    return 0;
}
1 ? 10 : noisy(20) gave 10, and noisy ran 0 time(s)
0 ? noisy(10) : 20 gave 20, and noisy ran 0 time(s)

The branch not taken is never evaluated. That is what makes this safe:

average = count != 0 ? (double) total / count : 0.0;

The practical: the greatest of three numbers

MU's Practical 1(b), in her own words: find the greatest of three numbers using the conditional operator. There are two correct shapes and both are worth knowing.

munotes.in90

The Conditional Operator

Nested, in one expression. This is the answer the question is asking for.

#include <stdio.h>

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

    printf("Enter three numbers: ");
    if (scanf("%d %d %d", &a, &b, &c) != 3) {
        printf("\nThose were not three numbers.\n");
        return 1;
    }

    int largest = a > b ? (a > c ? a : c) : (b > c ? b : c);

    printf("\nThe largest of %d, %d and %d is %d\n", a, b, c, largest);
    return 0;
}
34 91 57
Enter three numbers:
The largest of 34, 91 and 57 is 91

Read the expression in two halves. a > b decides which of a and b could still win. If a won, the remaining question is a against c; if b won, it is b against c. Three comparisons at most, and the brackets make the structure visible.

The brackets round the inner conditionals are not required, because ?: groups right to left, but write them. Nested conditionals without brackets are the standard example of unreadable C.

Two-step, which is clearer. Worth giving as well, and saying why you did:

int largest = a > b ? a : b;
largest = largest > c ? largest : c;

In the viva, the question after "write it" is usually "which would you prefer and why". The honest answer is the two-step form for readability, and the nested form because the question asked for one expression. Say both.

The same thing with if, for comparison

int largest;
if (a > b) {
    largest = a > c ? a : c;
} else {
    largest = b > c ? b : c;
}

or entirely without the conditional operator:

int largest = a;
if (b > largest) largest = b;
if (c > largest) largest = c;

That last form is the one that scales: for ten numbers it becomes a loop, and the nested conditional does not. It is chapter 36's pattern, and it is the right answer to "find the largest in an array". It is not the answer to this practical, which names the operator.

Where it is genuinely the right tool

1. Choosing a word inside output. The example that started the chapter.

2. Choosing a value in an initialisation, where if would force you to declare without a value first.

const double rate = years > 5 ? 8.5 : 7.25;

3. Guarding a division, shown above.

4. Singular and plural.

#include <stdio.h>

int main(void)
{
    for (int n = 0; n <= 3; n++) {
        printf("%d file%s found\n", n, n == 1 ? "" : "s");
    }
    return 0;
}
munotes.in91

The Conditional Operator

0 files found
1 file found
2 files found
3 files found

Where it is the wrong tool: anywhere the two branches do something rather than produce a value. x > 0 ? printf("pos\n") : printf("neg\n"); works and is bad style, because it uses an expression's value for nothing and hides a decision inside one. Use if.

Nesting, and when to stop

A conditional operator can be nested in either branch, and ?: groups right to left, so:

grade = marks >= 70 ? 'O'
      : marks >= 60 ? 'A'
      : marks >= 55 ? 'B'
      : marks >= 50 ? 'C'
      : marks >= 40 ? 'D'
      :               'F';

Laid out one condition per line like that, it is readable and it is a genuine use: every branch produces a value of the same kind. Written on one line it is unreadable. Chapter 25 gives the same thing as an else if ladder, which is what most programs use.

What this does NOT mean

?: is not a shorter if. It is an expression, so it has a value and must produce one. if is a statement and produces nothing. Where you want two branches that act rather than evaluate, if is correct.

It does not evaluate both branches. Exactly one is evaluated, guaranteed.

The two branches are not free to be any types. They are converted to a common type, which is the type of the whole expression. cond ? 1 : 2.5 has type double and yields 1.0 when the condition is true, not 1.

It is not the only ternary operator, it is the only one C has. "Ternary" describes the number of operands. Since C has exactly one such operator, the two names have come to mean the same thing.

Nesting is not automatically bad. A ladder of conditions each producing a value, laid out one per line, is clear. What is bad is nesting inside the condition rather than inside a branch, and putting it all on one line.

Quick revision

  • condition ? a : b yields a if the condition is non-zero, otherwise b.
  • It is the only operator in C with three operands, so "ternary" and "conditional" name the same thing.
  • Exactly one branch is evaluated, which makes it safe for guarding a division.
  • It is an expression, so it can appear inside a printf argument or an initialiser, where if cannot.
  • It groups right to left, so nesting in the false branch needs no brackets. Write them anyway.
  • The two branches are converted to a common type, which becomes the type of the expression.
  • Greatest of three: a > b ? (a > c ? a : c) : (b > c ? b : c).
  • Use if when the branches act rather than produce a value.
munotes.in92

The Conditional Operator

Test yourself

1. What is the value of 5 > 3 ? 10 : 20?

10.

2. Write one statement that prints "even" or "odd" for an int n.

printf("%s\n", n % 2 == 0 ? "even" : "odd");

3. Write the greatest of three numbers using only the conditional operator.

int largest = a > b ? (a > c ? a : c) : (b > c ? b : c);

4. Is count != 0 ? total / count : 0 safe when count is zero?

Yes. Only the branch selected is evaluated, so the division never happens when count is zero.

5. What is the type and value of 1 ? 1 : 2.5?

Type double, value 1.0. The two branches are converted to a common type before the expression has a value.

6. Why can ?: appear inside a printf argument when if cannot?

Because ?: is an operator and produces a value, and a function argument must be an expression. if is a statement and has no value.

7. Rewrite max = a > b ? a : b; using if.

if (a > b) max = a; else max = b;

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

"What is the conditional operator? Explain with an example." Give the form, say it is the only ternary operator in C, give one example that produces a value inside a larger expression, and add that exactly one branch is evaluated. That last point is what distinguishes a full answer.

"Write a program to find the greatest of three numbers using the conditional operator." Give this chapter's program with the nested expression, and read the expression out in the two halves. Keep the scanf return check; it is one line and it is the difference between a program and a program that works.

"Distinguish between the conditional operator and the if-else statement." ?: is an expression: it produces a value and can be used wherever a value is wanted, and each branch must be an expression. if-else is a statement: it selects which statement to execute, the branches may contain any number of statements, and it produces no value. Both evaluate only the branch selected.

"Can the conditional operator be nested? Give an example." Yes, in either branch, and it groups right to left. Give the grade ladder laid out one condition per line, and say that beyond three or four branches an else if ladder or a switch is clearer.

munotes.in93

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!