Chapter 3 Types, Operators, and Expressions; While and For Reference: Brooks, Chapter 3 2 3)


Reference: Kelley & Pohl, Chapter 4 (4.17)



Download 283.95 Kb.
Page2/3
Date07.08.2017
Size283.95 Kb.
#28159
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[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;



}



Download 283.95 Kb.

Share with your friends:
1   2   3




The database is protected by copyright ©ininet.org 2024
send message

    Main page