if and if-else
Chapter Twenty-Four
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 113 to 116 of 222
In one line
if runs a statement when a condition is non-zero, and if-else chooses between two statements, exactly one of which runs.
The forms
if (condition)
statement
if (condition)
statement
else
statementThe condition is any expression. It is evaluated, and if the result is non-zero the first statement runs; otherwise, in the second form, the else statement runs.
There is no then in C. The brackets round the condition are required, and they are not optional decoration: they are what tells the compiler where the condition ends.
With braces, which is how to write it
#include <stdio.h>
int main(void)
{
int marks = 63;
if (marks >= 40) {
printf("Result : pass\n");
printf("Marks : %d\n", marks);
} else {
printf("Result : fail\n");
printf("Shortfall by %d marks\n", 40 - marks);
}
return 0;
}Result : pass
Marks : 63Chapter 23 gave the reason the braces are there: if governs one statement, and a block is how you give it two.
The condition is any expression
Chapter 16's rule applies in full: zero is false, anything else is true. So all of these are legal conditions, and the first two are worth recognising.
if (n) /* true when n is not zero */
if (!n) /* true when n is zero */
if (n != 0) /* the same, said plainly */
if (marks >= 40 && attendance >= 75)
if (strcmp(a, b) == 0) /* two strings are equal */if (n) and if (!n) are idiomatic C and you will read them constantly. When the value is a count or a quantity rather than a truth, if (n != 0) says what you mean and costs four characters.
The dangling else
An else belongs to the nearest unmatched if. Always. Indentation has nothing to do with it, and this is the standard examination trick.
#include <stdio.h>
int main(void)
{
int a = 5, b = 10;
/* Indented as though the else belonged to the OUTER if. It does not. */
if (a > 0)
if (b > 100)
printf("a positive, b over a hundred\n");
else
printf("this looks like the else of the first if\n");
printf("a is %d and b is %d\n", a, b);
return 0;
}The compiler spots the mismatch between the layout and the meaning:
dangling.c: In function ‘main’:
dangling.c:8:8: warning: suggest explicit braces to avoid ambiguous ‘else’ [-Wdangling-else]
8 | if (a > 0)
| ^this looks like the else of the first if
a is 5 and b is 10Nothing from the first group printed. Read what the compiler read:
if (a > 0) {
if (b > 100) {
printf("a positive, b over a hundred\n");
} else {
printf("this looks like the else of the first if\n");
}
}if and if-else
a > 0 is true, so the inner if is reached. b > 100 is false, so the else runs, printing the second line. The message that claims to be the outer else is in fact the inner one, and it printed.
To attach an else to the outer if, use braces. There is no other way.
#include <stdio.h>
int main(void)
{
int a = 5, b = 10;
if (a > 0) {
if (b > 100) {
printf("a positive, b over a hundred\n");
}
} else {
printf("a is not positive\n");
}
printf("finished, and nothing above printed\n");
return 0;
}finished, and nothing above printedNow a > 0 is true, the inner if fails, and there is no else for it, so nothing prints from the decision at all. That is what the first program was trying to say.
The one-line rule to write in an exam: an else matches the nearest preceding unmatched if in the same block, regardless of layout; braces are the only way to change that.
Nesting
An if may contain another if in either branch, to any depth. Beyond two levels it becomes hard to read, and the two usual cures are an else if ladder (chapter 25) and pulling the decision into a function that returns early.
#include <stdio.h>
const char *category(int age)
{
if (age < 0) {
return "not an age";
}
if (age < 13) {
return "child";
}
if (age < 20) {
return "teenager";
}
if (age < 60) {
return "adult";
}
return "senior";
}
int main(void)
{
int ages[] = {-1, 5, 15, 30, 70};
for (int i = 0; i < 5; i++) {
printf("%3d -> %s\n", ages[i], category(ages[i]));
}
return 0;
} -1 -> not an age
5 -> child
15 -> teenager
30 -> adult
70 -> seniorThat shape, a series of ifs that each return, is called an early return, and it is usually the clearest way to write a decision with several outcomes. Each test reads as "if this, we are done", and nothing is nested.
The three mistakes
1. = for ==. if (x = 5) assigns and is always true. Chapters 16 and 18.
2. A semicolon after the condition. if (x > 0); gives the if an empty body. Chapter 23.
3. Comparing floating-point values with ==. Chapter 9. Use a tolerance.
#include <stdio.h>
#include <math.h>
int main(void)
{
double x = 0.1 + 0.2;
if (x == 0.3) {
printf("exact comparison said equal\n");
} else {
printf("exact comparison said NOT equal\n");
}
if (fabs(x - 0.3) < 1e-9) {
printf("comparison with a tolerance said equal\n");
}
return 0;
}if and if-else
exact comparison said NOT equal
comparison with a tolerance said equalWhat this does NOT mean
if does not need else. The else is optional and is often better left out, especially when the if returns.
The braces are not optional in practice. They are optional in the grammar. Leave them out and you meet the passed++ bug of chapter 23 and the dangling else of this one.
Indentation does not bind an else. Only braces do.
The condition does not have to be a comparison. Any expression will do, and zero is false.
if (a > b > c) is not a range test. It groups as (a > b) > c. Chapter 20.
An if is not an expression. It has no value, so it cannot appear inside a printf argument. That is what the conditional operator of chapter 19 is for.
Quick revision
if (condition) statementandif (condition) statement else statement.- The brackets round the condition are required; there is no
then. - Zero is false, anything else is true, so
if (n)andif (!n)are idiomatic. - Each branch governs exactly one statement; use a block for more.
- An
elsematches the nearest unmatchedif, whatever the indentation. - Braces are the only way to attach an
elseto an outerif. - A semicolon after the condition gives an empty body.
if (x = 5)assigns and is always true.- Never
==on floating-point values; compare the size of the difference. - A series of
ifs that each return is usually clearer than nesting.
Test yourself
1. What does this print, and why?
int a = 5, b = 10;
if (a > 0)
if (b > 100)
printf("X\n");
else
printf("Y\n");Y. The else belongs to the inner if, not the outer one, whatever the indentation suggests. a > 0 is true, b > 100 is false, so the inner else runs.
2. How do you make that else belong to the outer if?
Put braces round the inner if: if (a > 0) { if (b > 100) printf("X\n"); } else printf("Y\n");
3. What is the difference between if (n) and if (n == 0)?
They are opposites. if (n) is true when n is not zero; if (n == 0) is true when it is.
4. Why is if (x > 0); almost always a bug?
The semicolon is the empty statement, so the if has an empty body and the statement that follows runs regardless of the condition.
5. Rewrite this without nesting:
if (marks >= 40) { if (attendance >= 75) printf("allowed\n"); }if and if-else
if (marks >= 40 && attendance >= 75) printf("allowed\n");
6. Can an if statement appear as a function argument?
No. if is a statement and has no value. Use the conditional operator: printf("%s\n", x > 0 ? "pos" : "neg");
What can be asked on this, and how to answer it
"Explain the if and if-else statements with syntax and examples." Give both forms, say the brackets are required and there is no then, give a worked program, and add the rule that each branch governs one statement so a block is needed for more. Mention that zero is false and anything else is true.
"What is the dangling else problem? How is it resolved?" An else is matched to the nearest preceding unmatched if, so in a nested if without braces the else binds to the inner one even when the indentation suggests otherwise. It is resolved with braces, which are the only way to change the match. Give the trace-the-output example.
"Find the output" with nested ifs and no braces. Rewrite the code with the braces the compiler infers, then trace it. Showing that rewrite is what earns the marks, because it demonstrates the rule rather than the answer.
"Distinguish between if-else and the conditional operator." if-else is a statement: it selects which statement runs and has no value, and each branch may hold any number of statements. ?: is an expression: it produces a value and each branch must be a single expression. Both evaluate only the branch selected.
The rest of this subject
These notes are cut from the University's printed syllabus. Open the syllabus itself for the same subject.