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 typeint
: -
Both
++var
andvar++
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.
Increment and Decrement Operators
-
Expressions
++i
andi++
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 ofi
to be incremented, with the expression having as associated value its new (incremented) value, stored ini
. -
i++
causes the stored value ofi
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
andi--
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 variablesa
andb
unchanged.
Increment and Decrement Operators
-
Often, using
++
/--
in either prefix or postfix position will produce the same result. -
I.e., statements:
++i;
andi++;
are often equivalent toi = 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);
-
while (i--)
:- The
i--
is a postfix decrement, meaning the current value ofi
is used in the loop beforei
is decremented. - If
i
starts as a positive number, the loop will print values fromi - 1
down to0
. - The loop stops when
i
reaches0
because the conditioni--
evaluates tofalse
(0), which causes the loop to terminate. - Example: If
i
starts at3
, it will print2 1 0
before exiting, sincei
becomes-1
after printing0
, making the conditionfalse
and stopping the loop.
- The
-
while (--i)
:- The
--i
is a prefix decrement, meaningi
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 ofi
. - The loop also stops when
i
reaches0
because the condition--i
evaluates tofalse
(0), causing the loop to terminate. - Example: If
i
starts at3
, it will print2 1
and exit before reaching0
, since--i
evaluates to0
and ends the loop.
- The
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 ofexpr2
does not occur. -
Consider the evaluation of the expression:
expr1 || expr2
-
If
expr1
has value non-zero/TRUE, then evaluation ofexpr2
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
-
First Part (
x = 0 && (a = b = 777);
):- The
&&
(logical AND) operator short-circuits if the left side is0
(false). - Since
x = 0
isfalse
, the expression(a = b = 777)
is not evaluated. - As a result,
a
andb
remain0
, andx
is assigned the value0
. - The
printf
statement will print:0 0 0
.
- The
-
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
andb
remain0
, andx
retains the value777
. - The
printf
statement will print:0 0 777
.
- The
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
-
First Part (
(x = 0) && (a = b = 777);
):- Again,
&&
short-circuits if the left side is0
. -
(x = 0)
isfalse
, so(a = b = 777)
is not evaluated. -
a
andb
remain0
, andx
is0
. - The
printf
statement will print:0 0 0
.
- Again,
-
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
andb
remain0
, andx
is777
. - The
printf
statement will print:0 0 777
.
- The
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
meansx
gets the result of0 && 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:
-
i * j < 0
: This checks ifi
andj
have opposite signs. Ifi
andj
start with opposite signs and their values are not modified outside of the loop, this part of the condition will continue to be true. -
++i != 7
: This incrementsi
and checks if it is not equal to 7. Ifi
is initially less than 7,i
will eventually reach 7, making this condition false and allowing the loop to exit. However, ifi
starts at 7 or greater, this condition will be true untili
reaches 7, potentially allowing the loop to continue indefinitely if the other conditions are true. -
j++ != 9
: This checks ifj
is not 9, then incrementsj
after the check. Ifj
starts below 9, it will eventually reach 9, making this condition false and stopping the loop. However, ifj
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), thenexpr2
is evaluated, and the result of the evaluation is the value of the conditional expression. - If
expr1
is zero (false), thenexpr3
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
andcontinue
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.
- A
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!