Operators and decisions
Starting out11 min readLesson 4 of 5
4.1 Arithmetic operators
+, -, *, /, and % work on numbers. % is the remainder and accepts integers only.
Precedence follows the usual rules from maths: *, /, and % bind tighter than + and -. Parentheses override precedence, and adding them when a reader might pause costs nothing.
The increment operator ++ adds one, and -- subtracts one. count++ is a common statement in loops. ++count and count++ differ only when their value is used inside a larger expression, which is a place to slow down and add parentheses.
#include <stdio.h>
int main(void)
{
int a = 7;
int b = 2;
int total = 11;
printf("a * b + 3 = %d\n", a * b + 3);
printf("a * (b + 3) = %d\n", a * (b + 3));
printf("total / b = %d\n", total / b);
printf("total %% b = %d\n", total % b);
return 0;
}Output
a * b + 3 = 17 a * (b + 3) = 35 total / b = 5 total % b = 1
4.2 Comparison and logic
Comparison operators produce 1 for true and 0 for false:
==equal to!=not equal to<,>,<=,>=for ordering
A common beginner bug is writing if (x = 3) where if (x == 3) was meant. The first form assigns 3 and then tests the result, which is true, so the branch always runs. GCC and Clang warn about an assignment inside a condition.
Logical operators combine tests:
&&is true when both sides are true||is true when at least one side is true!flips true to false and false to true
&& and || short-circuit, so the right side is not evaluated when the result is already known. if (count != 0 && total / count > 2) avoids a division by zero for that reason.
#include <stdio.h>
int main(void)
{
int age = 20;
int has_ticket = 1;
printf("age >= 18: %d\n", age >= 18);
printf("age < 13: %d\n", age < 13);
printf("both: %d\n", age >= 18 && has_ticket);
printf("either: %d\n", age >= 18 || has_ticket);
return 0;
}Output
age >= 18: 1 age < 13: 0 both: 1 either: 1
4.3 The if statement
An if statement runs its block when the condition is nonzero. The optional else runs when the condition is zero. An else if chain tests conditions in order and stops at the first true one.
Indentation does not decide which if an else belongs to; braces do. Use braces even for a single statement, because a later edit that adds a second statement should not silently change which branch it belongs to.
A condition in C is any expression. Zero counts as false and every nonzero value counts as true. That is why if (1) is valid and why if (count) is a common shorthand for if (count != 0).
#include <stdio.h>
int main(void)
{
int score = 84;
if (score >= 90) {
printf("Grade A\n");
} else if (score >= 80) {
printf("Grade B\n");
} else if (score >= 70) {
printf("Grade C\n");
} else {
printf("Keep going\n");
}
return 0;
}Output
Grade B
4.4 The conditional operator
For two outcomes, C has a compact form: condition ? value_if_true : value_if_false. It is an expression, so it can sit on the right side of an assignment.
int larger = a > b ? a : b; reads as "if a is greater than b, use a, otherwise use b".
Use it when both results are short expressions. A chain of nested conditional operators is hard to read, and an if statement is clearer there.
#include <stdio.h>
int main(void)
{
int a = 12;
int b = 25;
int larger = a > b ? a : b;
int smaller = a < b ? a : b;
printf("larger: %d\n", larger);
printf("smaller: %d\n", smaller);
printf("difference: %d\n", larger - smaller);
return 0;
}Output
larger: 25 smaller: 12 difference: 13
4.5 The switch statement
switch compares one integer expression against a list of case labels. Each label must be a constant that fits the switched type.
Control falls through from one case to the next until a break or the end of the block. Supply break unless the fall-through is deliberate, and add default to handle values you did not list.
switch works with int and char. It does not accept strings, because a string is an array and case labels must be integer constants.
#include <stdio.h>
int main(void)
{
char command = 's';
switch (command) {
case 'n':
printf("New file\n");
break;
case 's':
printf("Save file\n");
break;
default:
printf("Unknown command\n");
break;
}
return 0;
}Output
Save file
4.6 Mistakes to watch for
if (score = 60)assigns 60 and tests the result, so the branch runs for every nonzero assignment. Use==for a test.if (score > 60);puts a semicolon right after the condition. The branch body is then an empty statement, and the next line runs whatever the score is.&and|are bitwise operators, while&&and||are logical ones. On plain 0 and 1 values the results often look alike, and they differ on other integers. The logical operators also short-circuit, and the bitwise ones do not.
GCC's -Wall warns about an assignment used as a condition, and -Wextra warns about the empty body.
#include <stdio.h>
int main(void)
{
int score = 70;
if (score > 90); /* empty statement */
printf("This line always runs.\n");
return 0;
}Output
This line always runs.
