Reference: Kelley & Pohl, Chapter 4 (4.17)
· Consider the following statement that sets z to the max of a and b:
-
if (a > b)
z = a;
else
z = b;
|
· The conditional expression operator may be used instead.
· The ternary operator ?: may be used thus:
expr1 ? expr2 : expr3
· Thus, our example may be rewritten:
-
· The right hand side is an expression which has the value of max(a,b). In fact, the ternary expression is often used in macros, e.g.,
· #define MAX(A,B) (((A) > (B)) ? (A) : (B))
· Also, because ?: is an expression, if expr2 or expr3 are of different types, the result is an expression of the highest type. This activity is often called “type promotion.”
· That is, in the code fragment:
-
Double d = 10.23;
Float f = 3.1416;
int i = 10;
...
x = (d > 0) ? f : i;
|
the resulting type of the right-hand side of the assignment to x is float because a mixed expression with float and int becomes float (expr2 is float, expr3 is int).
· The precedence of ?: is just above the assignment operators.
· It associates right to left.
The conditional operator
Recall that the conditional operator ?: has the following syntax:
conditional_expression
|
::=
|
expr1 ? expr2 : expr3
|
expr1
|
::=
|
expression
|
expr2
|
::=
|
expression
|
expr3
|
::=
|
expression
|
· Also, recall that this operator has the semantics that expr1 is evaluated first.
· Then if expr1 is nonzero (true), expr2 is evaluated and that is the value of the conditional expression as a whole.
· Otherwise, expr1 is zero (false), and expr3 is evaluated making it the value of the conditional expression as a whole.
· Consequently, the conditional operator can be used to perform the work of an if-else statement.
· Note that this can quickly get out of hand if you’re not careful…
example
if-else construct
|
equivalent conditional
|
if (y < z)
x = y;
else
x = z;
|
x = (y < z)
? y
: z;
|
if (a > 0)
z = 1;
else if (a < 0)
z = -1;
else
z = 0;
|
z = (a > 0)
? 1
: ((a < 0) ? -1 : 0);
|
if (a > b)
if (a > c)
z = a;
else
z = c;
else if (b > c)
z = b;
else
z = c;
|
z = (a > b)
? ((a > c) ? a : c)
: ((b > c) ? b : c);
|
The conditional operator -- example
· In the following example, assume that the following declarations are in scope:
char a = 'a'; /* a has an ASCII value of 97 */
char b = 'b'; /* b has an ASCII value of 98 */
int i = 1;
int j = 2;
double x = 7.07;
|
· Then, the following table illustrates the effect of the conditional operator.
· Exercise: explain why the first expression is an int rather than char
Expression
|
Equivalent Expr
|
Value
|
Type
|
i==j ? a-1 : b+1
|
(i==j) ? (a-1) : (b+1)
|
99
|
int
|
j%3==0 ? i+4 : x
|
((j%3)==0) ? (i+4) : x
|
7.07
|
double
|
j%3 ? i+4 : x
|
(j%3) != 0 ? (i+4) : x
|
5.0
|
double
|
Comma operator
· When used within an expression, the comma ',' operator, or sequencing operator, is defined thus:
"A pair of expressions separated by a comma is evaluated left to right, and the type and value of the result are the type and value of the right operand."
· The comma operator has the lowest possible precedence (lower than assignment statements).
· The comma operator associates from left to right.
f (a (), (b (), c ()));
/* call f with two parameters */
· A better way to do this might be the following:
b ();
f (a (), c ());
note
· The commas that separate function arguments, variables in declarations, etc., are not comma operators, and do not guarantee left to right evaluation.
example
· The statement
-
is exactly equivalent to writing
-
· Comma operators are commonly used within for loops to initialize more than one looping index, e.g.:
-
for (i = 0, j = 1, k = 2;
i < n;
i++, j++, k++) {
...
}
|
Precedence and order of evaluation
Operator
|
Associativity
|
Order of Evaluation
|
()
|
left to right
|
-
|
! ++ --
(unary) + -
(indirection) *
& ( type ) sizeof
|
right to left
|
-
|
* / %
|
left to right
|
-
|
+ -
|
left to right
|
-
|
< <= >= >
|
left to right
|
-
|
== !=
|
left to right
|
-
|
&&
|
left to right
|
left to right
sequence point after first argument
short circuit
|
||
|
left to right
|
left to right
sequence point after first argument
short circuit
|
?:
|
right to left
|
first operand eval
sequence point after first argument
|
=
+= -=
*= /= %=
|
right to left
|
-
|
,
|
left to right
|
left to right
sequence point after first argument
|
ANSI notes on the comma and other operators in C
· The ANSI draft, page 55, states the following about the comma operator:
"The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its evaluation."
· It is also important to note that the comma operator yields an expression and does not yield an lvalue. Thus, the following is incorrect:
int k;
int j;
(j = 10, k = 20) = 40;
· In other places it states that as && and || guarantee left to right evaluation, there is also a sequence point after evaluating the first operand.
· In general, a semicolon ';' denotes a sequence point, i.e. it is the point at which everything must synch up.
· Up until that point, all subexpressions can be conceptually evaluated in parallel.
Precedence, associativity, and order of evaluation
· Precedence, associativity, and order of evaluation are orthogonal concepts, e.g.,
10 * 20 + 20 / 5 + 15 … ((10 * 20) + (20 / 5)) + 15
· Most operators do not have an order of evaluation specified
· This “underspecification” allows compilers to optimize your code
· Only logical and '&&', logical or '||', the ternary operator '?:', and the comma ',' operator explicitly specify order of evaluation and define sequence points
· Also, note that the ternary operator associates right to left.
Order of evaluation -- pitfalls
· With the exception of &&, ||, ?:, and the comma operator, C does not specify the order in which operands of an operator are evaluated.
example
· The code fragment
-
may evaluate f() followed by g(), or it may choose to evaluate g() followed by f().
· Adding parentheses changes nothing, e.g.:
x = (f ()) + g ();
· The only way to guarantee order of evaluation is to split this up into several statements
x1 = f ();
x2 = g ();
x = x1 + x2;
Order of evaluation -- pitfalls (2)
· Similarly, the order in which arguments to a function are evaluated is not specified.
printf ("%d %d\n", ++n, power (2, n)); /* wrong */
|
· Different results will occur depending on whether ++n is evaluated before or after power(2,n) is evaluated.
· Changing the ++n to n++ can still lead to unpredictable results
· The underlying problem is that we have a potential “race condition”
· Other types of race conditions occur in concurrent programs
The while statement
Reference: Brooks, Chapter 4 (4.4)
-
The syntax of a while statement is as follows.
while_statement
|
::=
|
While (expression) statement
|
-
Generally, statement is a compound statement
The while statement (2)
Some examples are
int x = 0;
int i = 0;
while (i < n)
{
x = x + i; /* x++ */
i = i + 1; /* i++ */
}
|
int c;
while ((c = getchar ()) != EOF) {
/* Only works for ASCII,
better to use islower (c). */
if (c >= 'a' && c <= 'z')
++lowercase_letter_cnt;
++total_cnt;
}
|
but not
while (++i < LIMIT) do {
/* syntax error: do is not allowed */
j = 2 * i + 3;
printf ("%d\n", j);
}
|
· In general, given a sequence of statements of the form
-
while (expression)
statement
next statement
|
the first expression is evaluated.
· If it is nonzero (true), then statement is executed repeatedly until expression becomes zero (false).
· When expression becomes false, control is passed to next statement.
Example -- computing factorials
#include
int main (void)
{
int i, n;
double factorial;
printf ("Enter a positive integer: ");
scanf ("%d", &n);
factorial = 1.0;
i = 1;
while (i <= n)
{
factorial = factorial * i;
// factorial *= i;
i = i + 1;
// i++;
}
printf ("%d factorial = %.2f\n", n, factorial);
return 0;
}
|
-
Whenever you write a while loop, be sure you determine how it will terminate
-
A common error would be to omit the increment of i
-
The result would be an endless loop
-
Another common error is to forget to initialize i before the beginning of the loop
-
In this case, the behavior is unpredicatable
Example -- computing factorials (2)
The main code fragment
factorial = 1.0;
i = 1;
while (i <= n)
{
factorial = factorial * i;
i = i + 1 ;
}
may be rewritten more concisely as follows
factorial = 1.0;
i = 1;
while (i <= n)
factorial *= i++;
but not as follows
factorial = 1;
i = 1;
while (i < n)
factorial *= i;
The last example is an infinite loop. The looping variable i is never modified and thus never becomes >= n
Example - Fibonacci Numbers
-
The Fibonacci sequence is a sequence of numbers where the current number is the sum of the previous two numbers in the sequence
-
The first two numbers in the sequence is 1
-
The next number is 1 + 1 = 2
-
The next number after that is 1 + 2 = 3
-
Here are the first 10 numbers of the sequence:
1 1 2 3 5 8 13 21 34 55
-
Now we write code to generate N Fibonacci numbers and compute their sum
prev1 = prev2 = 1; /* first two numbers */
sum = 2; /* sum of the first two numbers */
count = 2; /* calculate 3rd number on */
while (count < N)
{
int curr = prev1 + prev2;
sum += curr;
prev1 = prev2; /* advance prev1 */
prev2 = curr; /* advance prev2 */
count++;
}
-
If N=10, how many iterations does this loop execute? What is the final value of count when N=10?
-
If N=5, what are the final values of curr, sum, prev1, and prev2?
example -- binary search
/* binsearch: find x in v[0] <= ... <= v[n-1]
-- return index of x in a sorted array of numbers
*/
int binsearch (int x, int v[], int n)
{
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (x < v[mid]) /* smaller */
high = mid - 1;
else if (x > v[mid]) /* larger */
low = mid + 1;
else /* we found it */
return mid; /* return the index */
}
return -1; /*NOT FOUND*/
}
|
exercise
Identify the statements within each if or while construct.
Example @@
· Because C allows side effects within expressions, some or possibly all of the work may be performed as part of the test.
· The following example illustrates a case where all of the work is done during the test.
#include
#include
int skip_spaces (void)
{
int c;
while ((c = getchar ()) != EOF && isspace (c))
/* null */;
return c;
}
|
· The while loop read characters one at a time and stops either when it hits end-of-file or when the character is no longer a whitespace character.
· The null statement ; is the body of the loop.
The FOR statement (1)
-
The syntax of a for statement is as follows.
for ( initialization-expression ;
condition ;
next-expression )
statement
next statement
Example -- computing factorials
factorial = 1;
i = 1;
while (i <= n)
{
factorial *= i;
i++;
}
|
factorial = 1;
for (i = 1; i <= n; i++)
{
factorial *= i;
}
|
Share with your friends: |