Introduction
The C language has conditional statements, also called selection statements (and colloquially called if statements). Essentially, depending on a certain condition, a program can decide which statements to execute and which ones to ignore.The simplest selection statement is the if statement:
Note that the parentheses after the if keyword are required.if ( expression ) statement
You read this as:
"If expression is true, then execute statement."You could also read it as:
"If expression is false, then do not execute statement." (In which case statement is simply skipped.)Notes about expression:
0 0F 0.0 NULL '\0'
a > b a a > 2 2 < a b < 2 a - b 2 a * 5 * b + 4
b > a b a < 2 2 > a a - 5 0 a * 5 * b
Equality operators: (They both have the same precedence)
< less than > greater than <= less than or equal to >= greater than or equal to
Note that the relational operators have higher precedence than the equality operators. (Operators in C)
Operator Meaning == equal to != not equal to
Some example usage:
Statement Correct/Incorrect if (a > 5)
statementCorrect if (a)
statementCorrect if (1)
statementCorrect if a < 5
statementMissing parentheses IF (a < 5)
statementWrong 'if' keyword if (a < 5) then
statementNo 'then' keyword if ()
statementMissing expression
Examples of the relationship between false/0 and true/1: (all statements print either 0 or 1)Note: The value of a relational expression is always either 0 (false) or 1 (true).
int a = 5;
int b = 0;
printf("Value of a > b is %i\n", a > b); /* 1, (true) */
printf("Value of a < b is %i\n", a < b); /* 0, (false) */
printf("Value of a == b is %i\n", a == b); /* 0, (false) */
printf("Value of a == a is %i\n", a == a); /* 1, (true) */
printf("Value of b == b is %i\n", b == b); /* 1, (true) */
printf("Value of a != a is %i\n", a != a); /* 0, (false) */
printf("Value of a > a is %i\n", a > a); /* 0, (false) */
printf("Value of b > b is %i\n", b > b); /* 0, (false) */
Output:
In fact, some compilers will warn about these kinds of things:Value of a > b is 1 Value of a < b is 0 Value of a == b is 0 Value of a == a is 1 Value of b == b is 1 Value of a != a is 0 Value of a > a is 0 Value of b > b is 0
with warnings like:a == a a != a a > a etc...
warning: self-comparison always evaluates to true [-Wtautological-compare] warning: self-comparison always evaluates to false [-Wtautological-compare]
Logical operators: (the precedence is accurate as well)
Boolean Truth Tables:
Operator Meaning ! logical NOT (negation)
(unary operator)&& logical AND || logical OR
Notes about these operators:
a b a && b a || b false false false false false true false true true false false true true true true true
a b a && b a || b 0 0 0 0 0 1 0 1 1 0 0 1 1 1 1 1
For example, what is the output of this program? (Hint: Put parentheses around the sub-expressions first.)
#include <stdio.h> int main(void) { int a; int b; a = 5; b = 3; if (a > b && b > 0 && ++a == 6) printf("1. The value of a is %i\n", a); a = 5; if (a > b && b > 5 && ++a == 6) printf("2. The value of a is %i\n", a); a = 5; if (a > b || b > 5 || ++a == 6) printf("3. The value of a is %i\n", a); a = 5; if (a > b && b > 5 || ++a == 6) printf("4. The value of a is %i\n", a); a = 5; if (a > b || b > 5 && ++a == 6) printf("5. The value of a is %i\n", a); return 0; }
Here is a video that explains what's happening.
if ( ( (a > b) && (b > 0) ) || (++a == 6) )
printf("1. The value of a is %i\n", a);
In fact, the GNU compiler will actually warn you about the lack of parentheses to get you to make your
intentions clearer. (When mixing || and &&)
This is the warning from #4 above:
warning: suggest parentheses around '&&' within '||' [-Wparentheses]
Note: Remember, the logical operators, || and && are different from the other operators we've seen. These operators enable short-circuit evaluation so it is possible that a portion of the expression could be skipped entirely. This means that if there are any side-effect operators in the part of the expression that is skipped, those side-effects will NOT occur.
More on the if Statement
We've seen the simplest form of the if statement:where statement is exactly one statement. If you want to execute multiple statements, you need to include curly braces around them:if ( expression ) statement
if ( expression )
{
statements
}
The statements (plural) means more than one statement. Example:
/* single statement */
if (a > b)
printf("a = %i, b = %i\n", a, b);
/* compound statement */
if (a > b)
{
printf("a = %i, ", a);
printf("b = %i\n", b);
}
Note that there is no semicolon after the closing curly brace. (But each statement inside the braces ends
with a semicolon.) This is a classic beginner's mistake (especially if you come from Python):
/* doesn't do what you might think */
if (a > b)
printf("a = %i, ", a);
printf("b = %i\n", b);
And, again, today's compilers will suspect you're unsure of what you're doing:
warning: this 'if' clause does not guard... [-Wmisleading-indentation]
if (a > b)
^~
note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
printf("b = %i\n", b);
^~~~~~
Also, it doesn't hurt to put a single statement inside curly braces:
/* Braces unnecessary, but legal. */
if (a > b)
{
printf("a = %i, b = %i\n", a, b);
}
This is also legal:
/* Pointless, but legal. */
if (a > b)
{
}
However, without the braces, you can't have an empty statement. You'll need at least a semicolon:
/* Pointless again, but legal. */
if (a > b)
;
Watch out for this common beginner's error which claims that 0 is greater than 5:
int a = 5;
int b = 0;
if (b > a); /* Trailing semicolon! */
printf("b is greater than a\n");
Fortunately, most compilers will alert you to this mistake. (You may have to enable extra warnings.):
warning: if statement has empty body [-Wempty-body]
if (a == 4);
^
note: put the semicolon on a separate line to silence this warning
or
warning: suggest braces around empty body in an 'if' statement [-Wempty-body]
Another common beginner's mistake is this:
if (a = b) /* Assignment, not equality */
printf("a is equal to b\n");
but, again, the compiler (Clang here) comes to the rescue:
warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
if (a = b)
~~^~~
note: place parentheses around the assignment to silence this warning
if (a = b)
^
( )
note: use '==' to turn this assignment into an equality comparison
if (a = b)
^
==
If you add redundant parentheses, it will prevent the compiler from complaining:
if ((a = b))
printf("a is equal to b\n");
Realize, of course, that the above is still incorrect. The compiler just doesn't
warn you about it so you should only do this if it is truly what you mean.
This reads as: "If expression is true, execute statement1, otherwise, execute statement2. This is mutually exclusive. Either statement1 or statement2 will get executed, but not both (or neither).if ( expression ) statement1 else statement2
Either of the statements (or both) can be compound as well:
|
|
|
Example:
int average = 85;
char grade;
if (average >= 70)
{
grade = 'P';
printf("You passed. Your average is %i%%.\n", average);
}
else
{
grade = 'F';
printf("You didn't pass. Your average is %i%%\n", average);
}
Examples (assume average is 85):
| Non-nested | Nested (cascading) | Nested (no formatting) | |
|---|---|---|---|
if (average >= 90) grade = 'A'; if (average >= 80) grade = 'B'; if (average >= 70) grade = 'C'; if (average >= 60) grade = 'D'; if (average < 60) grade = 'F'; |
|
if (average >= 90) grade = 'A'; else if (average >= 80) grade = 'B'; else if (average >= 70) grade = 'C'; else if (average >= 60) grade = 'D'; else grade = 'F'; |
Can you see why the non-nested version will possibly execute slower than the nested version (besides being incorrect)?
The proper way to format nested if statements in this class:
Remember that the compiler doesn't care about formatting and will actually see this, all on one line:if (average >= 90) grade = 'A'; else if (average >= 80) grade = 'B'; else if (average >= 70) grade = 'C'; else if (average >= 60) grade = 'D'; else grade = 'F';
In fact, can you take out all of the spaces as well? If not, which ones can you take out?if (average >= 90) grade = 'A'; else if (average >= 80) grade = 'B'; else if (average >= 70) grade = 'C'; else if (average >= 60) grade = 'D'; else grade = 'F';
Example: if(average>=90)grade='A';else if(average>=80)grade='B';else if(average>=70)grade='C';else if(average>=60)grade='D';else grade='F';
if (average < 90)
if (average < 60)
printf("Failing\n");
else
printf("An A student!\n");
If we change the formatting, we can see the problem more clearly.
if (average < 90)
if (average < 60)
printf("Failing\n");
else
printf("An A student!\n");
Again, compilers don't need any formatting, but humans do.
if (average < 90)
{
if (average < 60)
printf("Failing\n");
}
else
printf("An A student!\n");
The rule for matching up if and else is:
The else matches the closest (previous) if that hasn't already been matched.You override this behavior through the use of braces, as shown above.
Fortunately, again, most compilers will notice your "misleading formatting" and will say so if you do something like this:
if (average < 90)
if (average < 60)
printf("Failing\n");
else
printf("An A student!\n");
Compiler warning:
warning: suggest explicit braces to avoid ambiguous 'else' [-Wdangling-else]
if (average < 90)
^
The switch Statement
The switch statement is similar to nested if ... else ... statements. The most common form of the switch statement looks like this:
switch ( expression )
{
case constant_expression1 :
statements1
break;
case constant_expression2 :
statements2
break;
. . .
case constant_expressionN :
statementsN
break;
}
An example showing both a nested if ... else ... statement and a switch statement. The result is
the same. However, when you have a large number of conditions, the switch statement may execute faster.
| Nested if | switch |
|---|---|
|
|
Notice that if the value of year is not one of the values tested, nothing will be printed. If you want a catch-all condition, you would use an else clause in the if statement. For the switch statement, use a default:
| Nested if | switch |
|---|---|
|
|
Notes:
| if | switch |
|---|---|
|
|
error: case label does not reduce to an integer constant
case b:
^~~~
error: case label does not reduce to an integer constant
case c:
^~~~
error: case label does not reduce to an integer constant
case d:
^~~~
| if | switch |
|---|---|
|
|
| Warnings | Warnings suppressed |
|---|---|
|
|
switch2.c:74:12: warning: this statement may fall through [-Wimplicit-fallthrough=]
fresh++;
~~~~~^~
switch2.c:75:5: note: here
case 2:
^~~~
switch2.c:80:13: warning: this statement may fall through [-Wimplicit-fallthrough=]
junior++;
~~~~~~^~
switch2.c:81:5: note: here
case 4:
^~~~
fall through fallthrough FALL THROUGH FALLTHROUGH fall thru fallthru FALL THRU FALLTHRU
Comparing if/else with switch
This example shows how a compiler may be able to optimize a switch statement better than if/else:
For example, how many comparisons will be made if a is 128 in the above code? Suppose a is 13 using the numbers below:
if/else switch if (a == 1) { /* do something */ } else if (a == 2) { /* do something */ } else if (a == 3) { /* do something */ } else if (a == 4) { /* do something */ } /* Many, many more conditionals */ else if (a == 128) { /* do something */ }switch (a) { case 1: /* do something */ break; case 2: /* do something */ break; case 3: /* do something */ break; case 4: /* do something */ break; /* Many, many more cases */ case 128: /* do something */ break; }
if vs. switch - A Digipen Exclusive!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Boolean Types
As was stated before, C doesn't have a boolean type. Instead, it uses 0 to represent false and 1 (or non-zero) to represent true.Using one and zero, the meaning isn't clear:
int value = 1;
if (value == 1)
{
/* do something if value is true */
}
if (value == 0)
{
/* do something if value is false */
}
We can "create" our own boolean values and type:
And use these types in our programs:#define FALSE 0 #define TRUE 1 #define BOOL int
What the compiler sees after preprocessing:
Explicit comparisons Implicit comparison BOOL value = TRUE; if (value == TRUE) { /* do something if value is true */ } if (value == FALSE) { /* do something else if value is false */ }BOOL value = TRUE; if (value) { /* do something if value is true */ } if (!value) { /* do something else if value is false */ }
Explicit comparisons Implicit comparison int value = 1; if (value == 1) { /* do something if value is true */ } if (value == 0) { /* do something else if value is false */ }int value = 1; if (value) { /* do something if value is true */ } if (!value) { /* do something else if value is false */ }