# Reference: Kelley & Pohl, Chapter 4 (4.17)

 Page 2/3 Date 07.08.2017 Size 283.95 Kb.
1   2   3

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:

 z = (a > b) ? a : b;

· 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
 x = (i++, j++, k++);

is exactly equivalent to writing

 i++; j++; x = k++;

· 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
 x = f () + g ();

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 <= ... <= 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; }