Skip to content

11.4 Increments Short-Circuit Conditionals Loop Control

intro-to-computer-science-gtiit-04-2024.pdf

Today's Topics

  • Increment and decrement operators
  • The ||​ and &&​ operators: short circuit evaluation
  • The conditional operator ? :
  • Break and continue statements

Increment and Decrement Operators

  • The increment operator ++​ and the decrement operator --​ are unary operators.
  • Unlike +​ and -​ which are binary operators.
  • They can be used as prefix and postfix.
  • Suppose var​ is a variable of type int​:

  • Both ++var​ and var++​ are valid expressions

  • ++var​ uses ++​ as a prefix operator
  • var++​ uses ++​ as a postfix operator

Increment and Decrement Operators

  • Increment and decrement operators can only be applied to variables, not to constants or ordinary expressions.

image

Increment and Decrement Operators

  • Expressions ++i​ and i++​ have an effect and a value.

  • Effect: They cause the value stored in i​ to be incremented by 1.

  • Value: The result of the evaluation of the expression.
  • ++i​ causes the stored value of i​ to be incremented, with the expression having as associated value its new (incremented) value, stored in i​.
  • i++​ causes the stored value of i​ to be incremented too, but the expression has as associated value its original value of i(prior to the increment) .
int a, b;
int c = 0;
a = ++c;
b = c++;
printf("%d %d %d", a, b, ++c);  /* 1 1 3 is printed */

Increment and Decrement Operators (continued)

  • --i​ and i--​ work in a similar way.
  • The operators ++​ and --​ cause the value of a variable in memory to be changed.

  • We say that operators ++​ and --​ have side effects: not only do these operators yield a value, they also change the stored value of a variable in memory.

  • Not all operators do this. For example, the expression (a + b)​ leaves the values of variables a​ and b​ unchanged.

Increment and Decrement Operators

  • Often, using ++​/--​ in either prefix or postfix position will produce the same result.

  • I.e., statements: ++i;​ and i++;​ are often equivalent to i = i + 1;

  • ...unless they are used inside a condition or a greater expression!
  • In simple situations, ++​ and --​ provide a short notation for incrementing and decrementing a variable.
  • In other situations, careful attention must be paid as to whether prefix or postfix position is desired.

Because pre or post have a subtle difference: pre is do the plus then use the variable. post is use the variable then do the plus


Increment and Decrement Operators (continued)

Notice the difference between these two loops (assume i​ contains some positive value):

while (i--)
    printf("%d ", i);

while (--i)
    printf("%d ", i);
  1. while (i--):

    • The i--​ is a postfix decrement, meaning the current value of i​ is used in the loop before i​ is decremented.
    • If i​ starts as a positive number, the loop will print values from i - 1​ down to 0​.
    • The loop stops when i​ reaches 0​ because the condition i--​ evaluates to false​ (0), which causes the loop to terminate.
    • Example: If i​ starts at 3​, it will print 2 1 0​ before exiting, since i​ becomes -1​ after printing 0​, making the condition false​ and stopping the loop.
  2. while (--i):

    • The --i​ is a prefix decrement, meaning i​ is decremented first, then the loop checks if the new value is non-zero.
    • This will result in the loop starting from i - 1​, skipping the initial value of i​.
    • The loop also stops when i​ reaches 0​ because the condition --i​ evaluates to false​ (0), causing the loop to terminate.
    • Example: If i​ starts at 3​, it will print 2 1​ and exit before reaching 0​, since --i​ evaluates to 0​ and ends the loop.

Short-Circuit Evaluation

  • In the evaluation of operands of &&​ and ||​, the evaluation process starts from the left and stops as soon as the outcome TRUE or FALSE is known.
  • Consider the evaluation of the expression: expr1 && expr2

  • If expr1​ has value zero/FALSE, then evaluation of expr2​ does not occur.

  • Consider the evaluation of the expression: expr1 || expr2

  • If expr1​ has value non-zero/TRUE, then evaluation of expr2​ does not occur.


Short-Circuit Riddle

int a = 0, b = 0, x;

x = 0 && (a = b = 777);
printf("%d %d %d\n", a, b, x);

x = 777 || (a = ++b);
printf("%d %d %d\n", a, b, x);
int a = 0, b = 0, x;

(x = 0) && (a = b = 777);
printf("%d %d %d\n", a, b, x);

(x = 777) || (a = ++b);
printf("%d %d %d\n", a, b, x);

Explanation of Output

  1. First Part (x = 0 && (a = b = 777);):

    • The &&​ (logical AND) operator short-circuits if the left side is 0​ (false).
    • Since x = 0​ is false​, the expression (a = b = 777)​ is not evaluated.
    • As a result, a​ and b​ remain 0​, and x​ is assigned the value 0​.
    • The printf​ statement will print: 0 0 0​.
  2. Second Part (x = 777 || (a = ++b);):

    • The ||​ (logical OR) operator short-circuits if the left side is non-zero (true).
    • Since x = 777​ is non-zero (true), the expression (a = ++b)​ is not evaluated.
    • Therefore, a​ and b​ remain 0​, and x​ retains the value 777​.
    • The printf​ statement will print: 0 0 777​.

Expected Output

For the first code segment:

0 0 0
0 0 777

Second Code Segment (Alternate Syntax)

The second segment has similar logic but with explicit assignments:

Explanation

  1. First Part ((x = 0) && (a = b = 777);):

    • Again, &&​ short-circuits if the left side is 0​.
    • (x = 0)​ is false​, so (a = b = 777)​ is not evaluated.
    • a​ and b​ remain 0​, and x​ is 0​.
    • The printf​ statement will print: 0 0 0​.
  2. Second Part ((x = 777) || (a = ++b);):

    • The ||​ operator short-circuits if the left side is non-zero.
    • (x = 777)​ is non-zero (true), so (a = ++b)​ is not evaluated.
    • a​ and b​ remain 0​, and x​ is 777​.
    • The printf​ statement will print: 0 0 777​.

Expected Output for the Second Segment

For the second code segment:

0 0 0
0 0 777

In summary, both code segments will print the following output:

0 0 0
0 0 777

However, parentheses matter if they change the grouping of operations. For example:

  • Without parentheses: x = 0 && y​ means x​ gets the result of 0 && y​.
  • With parentheses: (x = 0) && y​ still evaluates the same way, but (x = (0 && y))​ might have a different meaning in a larger expression.

Short-Circuit Exercise (Harder)

In the following code, assume that the values of i​ and j​ are not changed in the body of the loop.

printf("Input two integers: ");
scanf("%d", &i);
scanf("%d", &j);
while (i*j < 0 && ++i != 7 && j++ != 9) {
    // do something...
}

Question: Can this ever lead to an infinite loop?

For the loop to execute continuously, this condition must always be true:

  1. i * j < 0​: This checks if i​ and j​ have opposite signs. If i​ and j​ start with opposite signs and their values are not modified outside of the loop, this part of the condition will continue to be true.

  2. ++i != 7​: This increments i​ and checks if it is not equal to 7. If i​ is initially less than 7, i​ will eventually reach 7, making this condition false and allowing the loop to exit. However, if i​ starts at 7 or greater, this condition will be true until i​ reaches 7, potentially allowing the loop to continue indefinitely if the other conditions are true.

  3. j++ != 9​: This checks if j​ is not 9, then increments j​ after the check. If j​ starts below 9, it will eventually reach 9, making this condition false and stopping the loop. However, if j​ is initially 9 or greater, this condition will remain true, potentially leading to an infinite loop if the other conditions are also met.

Conclusion:

If i​ starts at or above 7 and j​ starts at or above 9 (with i​ and j​ having opposite signs), the loop can run indefinitely because neither ++i != 7​ nor j++ != 9​ will ever break the condition.


The Conditional Operator

The conditional operator ? :​ is a ternary operator. It takes as operands three expressions:

expr1 ? expr2 : expr3

where expr1​, expr2​, and expr3​ are expressions. In the above construction:

  • expr1​ is evaluated first.

  • If expr1​ is non-zero (true), then expr2​ is evaluated, and the result of the evaluation is the value of the conditional expression.

  • If expr1​ is zero (false), then expr3​ is evaluated, and the result of this evaluation is the value of the conditional expression.

The Conditional Operator

In many situations, the conditional operator enables us to write more concise and readable programs:

if (y < z)
    x = y;
else
    x = z;

is equivalent to

x = (y < z) ? y : z;

The Conditional Operator

int main() {
    int input;
    printf("How many cherries do you want?\n");
    scanf("%d", &input);
    printf("So you want %d cherr%s.\n", input, (input == 1) ? "y" : "ies");
    return 0;
}

The Break and Continue Statements

  • Normally, loops can only exit when the loop condition is false.
  • Also, the whole body of the loop is executed at each iteration.
  • break​ and continue​ provide ways of exiting a loop or jumping to the condition of the loop directly from any place within the loop body.

  • break:

    • A break​ causes the innermost enclosing loop to be exited immediately.
    • continue:

    • A continue​ makes execution jump to the loop condition.


Break Statement. An Example

A typical use of break​. What would otherwise be an infinite loop is made to terminate upon a given condition tested by the if​ expression:

while (1) {
    scanf("%d", &x);
    if (x < 0)
        break;  /* exit loop if x is negative */
    printf("%d", x*x);
}
/* break jumps here */

Break Statement. Another Example

printf("Please enter a number between 0 and 100\n");
while (1) {
    scanf("%d", &x);
    if (x >= 0 && x <= 100)
        break;
    printf("Sorry. Please enter a number between 0 and 100\n");
}

The Continue Statement

The continue​ statement stops the current iteration and causes the next iteration of the loop to begin immediately.

  • It can only be used inside iteration statements.
int i = 0;
while (i < TOTAL) {
    c = getchar();
    if (c >= '0' && c <= '9')
        continue;
    /* process other characters */
    ++i;
}
#include <stdio.h>

int main() {
    for (int i = 1; i <= 10; i++) {
        if (i % 2 == 0) {  // Check if the number is even
            continue;       // Skip the rest of the loop for even numbers
        }
        printf("%d ", i);   // Print only odd numbers
    }
    return 0;
}

Ending Remarks

  • We covered a number of important topics today:

  • C expressions have a value and may have side effects.

  • Some widely used operators (e.g., increment/decrement) have side effects, so we must be careful when using them in expressions.

    • (In particular, when used as part of expressions with short-circuit operators)
    • Some control statements allow us to alter the normal control flow in loops (break​, continue​).

    • They should usually be avoided, as they lead to programs with poor structure and are difficult to reason about.

    • In some situations, they can help us write cleaner and more readable code.

    • But this is rare!