UP | HOME

Conditionals
COP-3223H

Table of Contents

Conditionals

  • Same instructions always run
  • No way to vary instructinos during execution

Examples

  • Guessing game
  • Determine min or max values
  • Check whether magic of nine succeeded (result is 9)

if statements

if (CONDITION) {   // if the condition is true
  INSTRUCTIONS     // run these instructions
}
// either way, continue running from here
  • If the condition is true during execution, run the instructions
  • Otherwise, don't run the instructions.

Desktop calculator language version?

Notice the condition is inverted

if (a < b) { INSTRUCTIONS }
REST_OF_PROGRAM

becomes

if a >= b goto skiplabel
INSTRUCTIONS
skiplabel:
REST_OF_PROGRAM

Comparison operators

Operator Description
a == b Test for equal
a != b Test for not equal
a < b Test for less-than
a > b Test for greater-than
a <= b Test for less-than-or-equal
a >= b Test for greater-than-or-equal

https://www.gnu.org/software/c-intro-and-ref/manual/c-intro-and-ref.html#Numeric-Comparisons

Comparison operators have lower precedence than arithmetic, so be careful when writing them. Wrapping them in parentheses is good practice.

https://www.gnu.org/software/c-intro-and-ref/manual/c-intro-and-ref.html#Binary-Operator-Grammar

Game: Guessing game

#include <stdio.h>

int main(int argc, char **argv) {
  int x;

  scanf("%d", &x);

  if (3 == x) {
    printf("you guessed right!\n");
  }
}

Under the hood

EXPRESSION BOOLEAN VALUE
0 False
Non-zero True
if (EXPRESSION) {  // if EXPRESSION is non-zero, run the instructions
}

C typically uses 1 for True

BOOLEAN VALUE EXPRESSION VALUE
False 0
True 1

This is not guaranteed and any non-zero value will work as true, i.e., run the instructions in an if statement.

Desktop calculator implementation

if (condition) {
  instructions;
}
next_instructions;
// compute the conditional expression's value
condition
// save the result of the conditional expression
store result
// skip the if-statement's body if 0, i.e., false
if result = 0 goto skiplabel
// evaluate the body if the result is non-zoer, i.e., true
instructions
skiplabel:
next_instructions

Guessing game: conditional value

#include <stdio.h>

int main(int argc, char **argv) {
  int x;

  scanf("%d", &x);

  printf("x is %d\n", x);

  int result;

  result = (3 == x);

  printf("result is %d\n", result);

  if (result) {
    printf("you guessed right!\n");
  }
}

Comparisons are operations

3 == 3 is

3 == 3 is 1 (non-zero is true)

3 == 1

3 == 3 is 0 (zero is false)

More examples
- 3 < 4 is 1 (non-zero is true)
- 3 < 1 is 0 (zero is false)
- 3 != 1 is 1 (non-zero true)
- 3 != 3 is 0 (zero is false)

How true and false work in C

  • Zero is false, don't run the conditional block
  • Non-zero is true, run the conditional block
#include <stdio.h>

int main(int argc, char **argv) {
  if (0) {
    printf("will if (0)'s block run?\n");
  }
  if (1) {
    printf("will if (1)'s block run?\n");
  }
  if (-1) {
    printf("will if (-1)'s block run?\n");
  }
  if (74832) {
    printf("will if (74832)'s block run?\n");
  }
}

C gotcha: assignment = vs. equality ==

Assignments are expressions

x = y = z;

This is right-associative, i.e., right-most assignment happens first.

Result of the expression is the assigned value.

x = (y = z);

Example: assignment expressions

#include <stdio.h>

int main(int argc, char **argv) {
  int x = 1;
  int y = 2;
  int z = 3;

  x = y = z;

  printf("%d\n", x);
  printf("%d\n", y);
  printf("%d\n", z);
}

Behavior of assignment

#include <stdio.h>

int main(int argc, char **argv) {
  int x = 1;
  int y = 2;
  int z = 3;

  x = (y = z);

  printf("x is %d\n", x);

  x = 1;
  y = 2;
  z = 3;

  if (y = z) {
    printf("y is %d\n", y);
  }
}

y = z evaluates to 3, which gets assigned to x. Similarly, the if statement testing y = z checks whether 3 is "true", i.e., non-zero, which it is, so the if block runs.

Example: assignment in conditionals

#include <stdio.h>

int main(int argc, char **argv) {
  int x;

  scanf("%d", &x);

  int result;

  result = (x = 3);

  printf("x = 3 results in %d\n", result);

  if (x = 3) {  // always true
    printf("x = 3 is always true\n");
  }

  result = (x = 0);

  printf("x = 0 results in %d\n", result);

  if (x = 0) {  // assignment
    printf("x = 0 is always false\n");
  }
}

Difference between equals and assignment

#include <stdio.h>

int main(int argc, char **argv) {
  int x;

  scanf("%d", &x);

  if (x == 3) {  // equality
    printf("you guessed right!\n");
  }

  if (x = 3) {  // assignment
    printf("you sure you guessed right?\n");
  }
}

C tip: put variable on the right-hand side

#include <stdio.h>

int main(int argc, char **argv) {
  int x;

  scanf("%d", &x);

  if (3 == x) {  // equality
    printf("you guessed right!\n");
  }

  if (3 = x) {  // assignment
    printf("you sure you guessed right?\n");
  }
}

What happens to this program?

Examples: comparison operators

Min and max

  • Given two numbers
  • Print the maximum of the two
    • or either if the number is the same
#include <stdio.h>

int main(int argc, char **argv) {
  int a;
  int b;

  printf("enter the first number: ");
  scanf("%d", &a);

  printf("enter the second number: ");
  scanf("%d", &b);

  if (a > b) {
    printf("the first number, a, is greater: %d\n", a);
  }

  if (b > a) {
    printf("the second number, b, is greater: %d\n", a);
  }

}

Magic of nine: check if done

  • Use an if statement to check whether we need to continue summing the digits
#include <stdio.h>

int main(int argc, char **argv) {
    int num;

  // read an integer from the user
  scanf("%d", &num);

  // print the number from the user
  printf("%d\n", num);

  int x;

  // multiply by nine
  x = num * 9;

  printf("%d\n", x);

  // get the ones, tens, and hundreds digits
  int ones_digit = x % 10;
  int tens_digit = (x / 10) % 10;
  int hundreds_digit = (x / 10 / 10) % 10;

  // sum the first three digits
  int sum = ones_digit + tens_digit + hundreds_digit;

  // print the sum
  printf("%d\n", sum);

  if (sum != 9) {
    printf("we need to continue summing the results digits\n");
  }
}

if-then-else statements

if (CONDITION) {   // if the condition is true
  IF_INSTRUCTIONS     // run these instructions
} else {
  ELSE_INSTRUCTIONS   // otherwise, run these instructions
}
// either way, continue running from here
  • If the condition is true during execution, run the instructions
  • Otherwise, don't run the instructions.

Desugaring if-then-else with if

How can we simulate if-then-else using if statements?

else means run if the condition is not true

if (a < b) {
  x = x + 1;
} else {
  x = x - 1;
}

is equivalent to

if (a < b) {
  x = x + 1;
}

if (a >= b) {  // else is like the opposite of the if condition
  x = x - 1;
}

In general:

  • Invert (negate) the condition of the if branch
  • Make another if statement using that opposite (inverted) condition

Meaning of else

Can both branches of an if-then-else statement be run?

No, because the semantics of an if-then-else statement are:

  • Check the condition
  • If it's non-zero (true), run the if branch's body, then continue running after the if-then-else statement
  • If it is zero, run the else branch's body, then also continue running after the if-then-else statement

First Boolean operator: negation

  • ! means negate the condition
  • Negate means swap the true and false values

Mutual exclusion of if-then-else branches

  • if-branch runs when (condition) is true
  • else branch runs when (! condition) is true
  • Can (condition) and (! condition) ever both be true at the same time?

Intuitively, no, because the (! condition) only runs when the condition branch does not run.

Negation truth table

CONDITION ! CONDITION
True False
False True

Negation truth table (C)

CONDITION ! CONDITION
1 0
0 1

Proof of mutual exclusion

CONDITION ! CONDITION Both CONDITION and ! CONDITION true?
1 0 No
0 1 No

We can show from the definition of negation as a truth table that the branches are mutually exclusive, because the conditions can never be true at the same time.

if-then-else as two if-statements

if (condition) {
} else {
}

is equivalent to

if (condition) {
}

if (! condition) {
}

Boolean logic

Example: bounds checking

Problem: write a program that checks whether some number x is between two numbers a and b (exclusive), where a is always less than b

  • Input: an integer
  • Output: "yes" when within bounds, "no" when not within bounds

Definition says a and b are not equal (a always less than b). If input number is the same as a or b, it is not within bounds, because bounds are exclusive

Do we have one comparison operation that can check this? No, but we can combine two conditions.

Boolean AND (conjunction)

&& is AND (think ampersands mean and in natural language).

if (first_condition && second_condition) {
}

These are double-ampersands && to distinguish from a single ampersand & which performs bitwise AND (i.e., perform AND on each of the corresponding bits in two binary numbers).

Semantics of AND

  • Evaluate each condition
  • When both are true, the result is true
  • If either or both are false, the result is false.

Solution: bounds checking

How do we write the bounds condition?

a < x && x < b
#include <stdio.h>
#include <assert.h>

int main(int argc, char **argv) {
  int a;  // lower bound
  int b;  // upper bound
  int x;  // number to check

  printf("enter the lower bound: ");
  scanf("%d", &a);

  printf("enter the upper bound: ");
  scanf("%d", &b);

  // we can quickly write assumptions to protect program from running without the assumptions we make
  assert(a < b);

  printf("enter the number to check: ");
  scanf("%d", &x);

  if (a < x && x < b) {
    printf("yes\n");
  } else {
    printf("no\n");
  }    
}

Truth table for AND

first second first && second
1 1 1
1 0 0
0 1 0
0 0 0

Bound checking improved

Problem: write a program that checks whether some number x is between a and b (exclusive), where a is always less than b where a and b are not the same

  • Input: an integer
  • Output: "yes" when within bounds, "no" when not within bounds

What's the condition?

  • When a < b, a < x && x < b
  • When b > a, b < x && x < a

If we want to express several options among conditions, we can use OR

Boolean OR (disjunction)

|| is OR

if (first_condition || second_condition) {
}

| has also been used for OR-like operations in math, e.g., | for alternation in regular expressions

Semantics of OR

  • Evaluate each condition
  • If both are false, the result is false
  • If either (or both) are true, the result is true

Does this pattern look familiar?

AND has the same "shape", i.e., one condition is about both between the same, and the other condition is about either (or both) being the same, except the values are the opposite.

!(a && b) is the same as !a || !b

Solution: bounds checking improved

How do we write a single bounds condition?

(a < x && x < b) || (b < x && x < a)

Notice that a < x && x < b implies that a < b.

Alternatively, we could ensure the bounds conditions only apply to their individual cases with

    ((a < b) && (a < x && x < b))
||  ((b < a) && (b < x && x < a))
#include <stdio.h>
#include <assert.h>

int main(int argc, char **argv) {
  int a;  // lower bound
  int b;  // upper bound
  int x;  // number to check

  printf("enter the lower bound: ");
  scanf("%d", &a);

  printf("enter the upper bound: ");
  scanf("%d", &b);

  // we can quickly write assumptions to protect program from running without the assumptions we make
  assert(a != b);

  printf("enter the number to check: ");
  scanf("%d", &x);

  if ((a < x && x < b) || (b < x && x < a)) {
    printf("yes\n");
  } else {
    printf("no\n");
  }    
}

Truth table for OR

first second first || second
1 1 1
1 0 1
0 1 1
0 0 0

Boolean operations as if statements

OR

if (! condition) {
  INSTRUCTIONS;
}

if (condition) {
} else {
  INSTRUCTIONS;
}

AND

Both conditions must hold.

Equivalent to using two, nested if statements

if (first_condition && second_condition) {
  TRUE_INSTRUCTIONS
} else {
  FALSE_INSTRUCTIONS
}
if (first_condition) {
  TRUE_INSTRUCTIONS
} else {
  if (second_condition) {
    TRUE_INSTRUCTIONS
  } else {
    FALSE_INSTRUCTIONS
  }
}

Or

if ( first_condition || second_condition ) {
}

Only one condition needs to hold

Equivalent to nesting the second condition in the else of the first if-then-else

if (first_condition || second_condition) {
  TRUE_INSTRUCTIONS
} else {
  FALSE_INSTRUCTIONS
}
if (first_condition) {
  TRUE_INSTRUCTIONS
} else {
  if (second_condition) {
    TRUE_INSTRUCTIONS
  } else {
    FALSE_INSTRUCTIONS
  }
}

Game: 2-dimensional collision detection

Diagram, visually show the "collision" conditions on a 2d plane with x and y coordinates

Also, work on alignment conditions, e.g., same x bounds or same y bounds

Game: the price is right (Boolean logic)

  • Input the real price and two guesses
  • Pick the guess that is closest without going over

Prepare all conditions

Model with Boolean logic

Design the conditional branches

  • Input all three
    • Check that each is greater than 0
  • Check if both went over, both lost
  • Check if either went over, the other won
    • Use else branches
  • If both under, that with the smaller distance from price is the winner

else if, (nested else branches, sequence of possibilities)

C gotchas and tips

C gotcha: conditional expression precedence

In math:

! like -
&& like *
|| like +

In C:

Warning: Never rely on the relative precedence of ‘&&’ and ‘||’. When you use them together, always use parentheses to specify explicitly how they nest, as shown here:

if ((r != 0 && x % r == 0)
    ||
    (s != 0 && x % s == 0))

C gotcha: curly braces

The Apple goto fail vulnerability: lessons learned

the "accidental" goto fail bug NVD - CVE-2014-1266

solution: always use brackets

related: {} vs. ; confusion, if no {}, then you have ; because blocks contain statements

C gotcha: short-circuiting

int x;

x = 1;
printf("before: %d\n", x);
if (0 && (x = 3)) {  // assignment of x?
}
printf("after: %d\n", x);

x = 1;
printf("before: %d\n", x);
if (1 && (x = 3)) {  // assignment of x?
}
printf("after: %d\n", x);

C tip: always have an else branch

  • Mistakes in Boolean logic are easy to make
  • Have an else branch especially if you believe all cases have been covered already
    • Put an assert statement in the else branch you think will never be reached

Think of what the else branch would mean. Some exceptions: if the condition is very simple, part of a specific pattern, just debugging info, etc.

Simple anti-example: use if statement to check for input conditions, but fail to handle what happens when the input does not meet the conditions.

Another example-example: assume the input has specific bounds, write if condition that assumes those bounds. See the bounds checking assumption. You may have a number between a and b but the condition doesn't find it because it assumes a < b. An else branch would have helped you catch this error and reason about it.

Author: Paul Gazzillo

Created: 2026-02-05 Thu 10:14

Validate