Chapter 3

advertisement
CHAPTER 3
Types, Operators, and Expressions; While and For
Reference: Brooks, Chapter 3 (3.2 - 3.3)
 It is possible to mix data types in arithmetic expressions in C
 The following example is perfectly legal in C
/*
* File : main.c
* Author: Robert C. Carden IV
*/
#include <stdio.h>
void main(void)
{
int
hours;
double speed, distance;
printf("Enter the number of hours: ");
scanf("%d", &hours);
printf("Enter the speed in MPH: ", &speed);
scanf("%lf", &speed);
distance = hours * speed;
printf("You travelled %.2f miles "
"at %.2f MPH in %d hours\n",
distance, speed, hours);
}
 In this example, we are multiplying an integer with a double
 C mandates that all expressions be computed using operand of the same
data type
 In this example, C has rules for converting one or both numerical
operands to a common type
 Since double is considered to be a higher type than int, the integer
operand is converted (promoted) to double and double multiplication is
performed
Copyright (c) 1999 by Robert C. Carden IV, Ph.D.
2/6/2016
Types, Operators, and Expressions
Implicit type conversions


Performed when an operator has operands of different types
The operands are converted to a common type
General rules





In general, the only automatic conversions are those that convert a
narrower operand into a wider one without losing information.
Assignments of a wider type to a narrower type loses information but is
allowed.
A char is treated as a small integer.
They may be used freely within arithmetic expressions.
The following example shows how characters and integers are used
freely within expressions.
/*
* ctoi: if ch is a numerical character, return
*
the numerical equivalent
*
if ch is not, return -1
*/
int ctoi(char ch)
{
int digit = -1;
if (ch >= '0' && ch <= '9')
{
/*compute integer value*/
digit = ch - '0';
}
return(digit);
}
3-2
Types, Operators, and Expressions
Implicit type conversions -- example
/**
** lower: convert c to lower case (ASCII only)
**
** For portability reasons, we pass in
** characters as integers. See later
** discussion on this point.
**/
int
lower(int c)
{
if (c >= 'A' && c <= 'Z')
/*
* uppercase letter -- convert it
* to lower case
*/
return c + 'a' - 'A';
else
/* not an uppercase letter */
return c;
}



This function works for ASCII but fails for EBCDIC.
In ASCII, corresponding upper and lower case letters are a fixed distance
apart as numeric values
Letters are also contiguous
3-3
Types, Operators, and Expressions
Portable character functions and macros
example functions
isdigit(int c)
isupper(int c)
toupper(int c)
tolower(int c)




semantics of function or macro
returns 1 <=> c is a digit
returns 1 <=> c is uppercase
converts c to uppercase
converts c to lowercase
To overcome this common problem, the header <ctype.h> is available
(and required under ANSI).
This header defines a family of functions and macros for doing character
tests and conversions that are independent of the character set
Each installation will provide its own <ctype.h> to do whatever is
necessary
Now we can rewrite our lower function using these macros:
#include <ctype.h>
int lower(int c)
{
if ( isupper(c) )
return tolower(c)
else
return c;
}





The C language does not specify whether variables of type char are
signed or unsigned quantities.
The C definition guarantees that any character in a machine's
standard character set will never be negative.
For portability, if you use characters as integers to store non-character
data, specify whether it is signed or unsigned.
When passing or receiving characters to and from functions, people often
use int to store characters.
Problems sometimes arise when users must be able to store an arbitrary
character and EOF (-1) in a character variable. In the EBCDIC character
set, it already needs all 256 possible values but adding EOF requires 257.
3-4
Types, Operators, and Expressions
Type conversions -- A.6, p.198, K&R


The following conversions are performed in an arithmetic expression of
mixed types
 If either operand is long double, the other is converted to long
double
 Otherwise, if either is double, convert the other to double
 Otherwise, if either is float, convert the other to float
[Integral promotions]
 Otherwise if either is unsigned long int, convert the other to
unsigned long int
 Otherwise, if one operand is long int and the other is unsigned
int, the effect depends on whether long int can represent all values
of an unsigned int; if so, the unsigned int operand is converted
to long int; if not, both are converted to unsigned long int
 Otherwise, if one operand is long int, convert the other to long
int
 Otherwise, if either operand is unsigned int, convert the other to
unsigned int
 Otherwise both operands have type int, i.e. smaller operands are
promoted to int.
Under ANSI, unsigned-ness of operands is not propagated.
3-5
Types, Operators, and Expressions
Type conversion - the distance program
void main(void)
{
int
hours;
double speed, distance;
printf("Enter the number of hours: ");
scanf("%d", &hours);
printf("Enter the speed in MPH: ", &speed);
scanf("%lf", &speed);
distance = hours * speed;
printf("You travelled %.2f miles "
"at %.2f MPH in %d hours\n",
distance, speed, hours);
}




The mixed mode expression in question is hours * speed
Variable hours is of type int
Variable speed is of type double
Because they are of different types, an arithmetic type conversion must
be applied
1. Neither variable is of type long double so that rule does not apply
2. Variable speed is of type double and since hours is not, hours shall
be promoted to double and double (floating point) multiplication
shall be performed
 No information is lost here because of the nature of double
 Note from earlier discussions that double has a 53 bit mantissa (on our
Intel systems)
 By the same token, int is 32 bits and can easily fit into the integer part of
the double
 The result of this expression is a double and the variable it is being
assigned to is double
 These are the same so no conversion for the assignment is required
3-6
Types, Operators, and Expressions
Type conversion - the distance program using floats
void main(void)
{
int
hours;
float speed, distance;
printf("Enter the number of hours: ");
scanf("%d", &hours);
printf("Enter the speed in MPH: ", &speed);
scanf("%lf", &speed);
distance = hours * speed;
printf("You travelled %.2f miles "
"at %.2f MPH in %d hours\n",
distance, speed, hours);
}








The mixed mode expression in question is hours * speed
Variable hours is of type int
Variable speed is of type float
Because they are of different types, an arithmetic type conversion must
be applied
1. Neither variable is of type long double so that rule does not apply
2. Neither variable is of type double so that rule does not apply
3. Variable speed is of type float and since hours is not, hours shall be
promoted to float and float (floating point) multiplication shall be
performed
In this example, information might be lost if hours is a fairly large
integer
Note from earlier discussions that float has a 24 bit mantissa (on our
Intel systems)
By the same token, int is 32 bits and may not be able to fit into the
integer part of the float
The excess, low order digits in the floating point number will be
truncated
 The result of this expression is a float and the variable it is being
assigned to is float
 These are the same so no conversion for the assignment is required
3-7
Types, Operators, and Expressions
Integer constants revisited - some subtle points

The type of integer constant is the first of the corresponding list in which
its value can be represented (ANSI draft, section 3.1.3.2)
unsuffixed decimal:
unsuffixed octal or hexadecimal:
suffixed by letter u or U:
suffixed by letter l or L:
suffixed by both u or U and l or L:
int, long, unsigned long
int, long, unsigned long
unsigned int,
unsigned long
long, unsigned long
unsigned long
 In LIMITS.H, we see:
#define LONG_MIN
#define LONG_MAX
#define ULONG_MAX
(-2147483647L - 1)
2147483647L
0xffffffffUL
 Consider the rather arcane definition of LONG_MIN
 Suppose we had rewritten it as
#define LONG_MIN
-2147483648L
 This would not work at all
 First, the compiler would determine the type of the constant
2147483648L
 Because it is suffixed with an L, the compiler may choose the first of
long and unsigned long which can represent this integer
 However, this integer requires a full 32 bits and cannot be represented as
a long
 Therefore, it must be an unsigned long
 Then, we negate the unsigned long 2147483648
 That will produce another unsigned long and not the minimum signed
long number
3-8
Types, Operators, and Expressions
Mixed mode expressions - evaluating from the bottom up
#include <stdio.h>
void main(void)
{
double result1, result2;
result1 = 2.56 + (3
/ 2);
result2 = 2.56 + (3.0 / 2);
printf("result1 = 2.56+(3 /2) = %.2f\n", result1);
printf("result2 = 2.56+(3.0/2) = %.2f\n", result2);
}
 The example above illustrates a very common pitfall in C
 Many people are aware that integer division truncates and would expect
3/2 to produce a result of 1
 Even more people, though, get confused when they cleverly observe that
the result is being assigned to a double and therefore conclude that the
entire expression is a double expression. Wrong.
 C evaluates expressions from the bottom up and determines the type and
value of each subexpression as it goes, each step of the way
 In the case of computing result1, C first considers 3/2
 Both operands are integers, therefore we do integer division and note
that the result is an int
 Notice at this point there is no concern or care about the larger
expression
 Notice that C does not care about the context
 Then C considers adding 2.56 to the integer result of computing 3/2
 Now we are adding a double to an int, the int result is promoted to
double, and the result is double
 Finally, we have a double which we are assigning to a double
 No conversion is necessary and the C compiler is happy with life
3-9
Types, Operators, and Expressions
Mixed mode expressions - evaluating from the bottom up
#include <stdio.h>
void main(void)
{
double result1, result2;
result1 = 2.56 + (3
/ 2);
result2 = 2.56 + (3.0 / 2);
printf("result1 = 2.56+(3 /2) = %.2f\n", result1);
printf("result2 = 2.56+(3.0/2) = %.2f\n", result2);
}
Here is the actual result of running this program:
3-10
Types, Operators, and Expressions
Explicit type conversion -- assignments


The expression x = y forces y to be converted into the type on the left
Consider the following C fragment:
float
int i;
f;
/* converts int to float */
f = i;
/*
* converts float to int,
* truncating fractional part
*/
i = f;


Converting float to int causes the truncation of the fractional part
Longer integers are converted to shorter ones or to chars by dropping the
excess high-order bits.
int
char
i;
c;
i = c; /* widen c to fit in i */
c = i; /* value originally in c is unchanged */
[Instructor: give examples on the board of these scenarios]
3-11
Types, Operators, and Expressions
Explicit type conversions -- coerced
 The cast operator is of the form
( <type-name> )
 It is a unary operator with the effect that it converts its operand to the
desired type.
 The cast operator is an operator equal in precedence to unary minus (-)
float f;
int
i, j;
f = i / j;
/* integer division */
f = (float) i / j; /* real division */
i = f % j;
i = (int) f % j;
/* syntax error */
/* f is converted to int */
 A cast is an expression: it involves a cast operator and an operand to be
cast
 It produces a value
 it does not modify the operand
 In the first example, it converts the int i to float
 The result of this is divided by j using floating point division
 In the second example, it converts the float back to int, truncating the
fractional part
 That integer result is then modulo with j
3-12
Types, Operators, and Expressions
Using casts to get the correct type of expression
#include <stdio.h>
void main(void)
{
result1 = 2.56 + (double) 3 / 2;
result2 = 2.56 + (double)(3 / 2);
printf("result1 = 2.56+(double)3 /2 = %.2f\n",
result1);
printf("result2 = 2.56+(double)(3/2) = %.2f\n",
result2);
}
 It is important to understand why the computation of result1 uses
floating point division while the computation of result2 uses integer
division
 Once again, all expressions are evaluated from the simplest, innermost
expression outward
3-13
Types, Operators, and Expressions
Increment and decrement operators

Unary operators ++ and -- increment and decrement their respective
operands
 highest precedence (same as unary -)
 right to left associativity
Operand
y = ++ x;
y = x ++;
y = -- x;
y = x --;
z++;





x
y
y
x
x
y
y
x
z
Equivalent C code
= x + 1; /*increment*/
= x;
/*use result*/
= x;
/*use value*/
= x + 1; /*increment*/
= x - 1;
= x;
= x;
= x - 1;
= z + 1;
When ++ or -- are placed before the operand, they are called preincrement and pre-decrement respectively.
 the return value of the expression is the new value of the operand
When ++ or -- are placed after the operand, they are called postincrement and post-decrement respectively
 the return value of the expression is the original value of the operand
Cannot apply ++ or -- to something cannot be an lvalue
 An lvalue is anything that can be updated, for instance on the left
hand side of an assignment statement
The expression
(a+b)++
is illegal.
However, the expression
x[i]++
is legal and equivalent to
x[i] = x[i] + 1
3-14
Types, Operators, and Expressions
ANSI Note (p. 39)
"Between the previous and next sequence point, an object shall have its
stored value modified at most once by the evaluation of an expression.
Furthermore, the prior value shall be accessed only to determine the value
to be stored."

Thus, if a variable is updated more than once within an expression
between two consecutive sequence points, the behavior is undefined.
example
i = 1;
i = ++i

+
1;
What gets assigned to i?
=
i
tmp2 <-- tmp1 + 1
schedule store tmp2 to i
+
tmp1 <-- i+1
schedule store tmp1 to i
(pre)++
1
i




Two assignments are being requested, but ANSI specifies that i shall
have its stored value modified at most once.
The resulting value of ++i will propagate through the expression, but
the store may or may not occur.
Consequently, the compiler may choose to allow the ++i to actually
store into i or let the assignment statement store into i.
Thus, only one update to i will win and thus i may be either 2 or 3.
3-15
Types, Operators, and Expressions
Example expressions

In the table below, assume that the following declarations are in scope.
int a = 1, b = 2, c = 3, d = 4;


The following table gives an expression, the equivalent fully
parenthesized expression, the value of the expression, and then the
subsequent values of a, b, c, and d after its evaluation.
Assume that these expressions are evaluated independent of each other.
Expression
a * b / c
a * b % c + a
++ a * b - c -7 - - b * ++ d
Equivalent Expr
(a * b) / c
((a * b) % c) + a
((++a) * b) - (c--)
7 - ((-b) * (++d))
Value
0
3
1
17
a
1
1
2
1
b
2
2
2
2
Illustration of third row
tmp2 = tmp1*b
-
tmp3 = c
schedule
store of
c-1 to c
tmp1 = a+1
schedule
store of
tmp1 to a
*
(pre)++
(post)--
b
a
3-16
c
c
3
3
2
3
d
4
4
4
5
Types, Operators, and Expressions
Assignment operators and expressions




In C, any expression can be a statement.
In Pascal, one uses an assignment statement.
In C, assignments are simply expressions.
As a result, it is perfectly legal to write the following meaningless code
in C.
3; /* valid */
4+5; /* valid */
Assignments are expressions



The return value of an assignment expression is the value that just got
assigned
The object getting updated by the assignment is called an lvalue
The object (expression) being assigned to it is called an rvalue
example
x = 5 + 7;

In this example, x is the lvalue, 5+7 is the rvalue, and the return value of
the entire expression is 12.
3-17
Types, Operators, and Expressions
Example of assignments being expressions

The following three statements
b = 2;
c = 3;
a = b + c;
may be written as one statement
a = (b = 2) + (c = 3);
=
schedule store tmp3 in a
tmp3 <-- tmp1 + tmp2
+
a
tmp1 <-- 2
schedule store
tmp1 in b
b
=
=
2
c
3-18
tmp2 <-- 3
schedule store
tmp2 in c
3
Types, Operators, and Expressions
example

Assignment operators associate right to left
Thus, the following expression
a = b = c = 0;
is equivalent to writing
a = (b = (c = 0));
which in turn is equivalent to writing
c = 0;
b = 0;
a = 0;


Note that because assignment statements associate right to left, variables
a, b, and c are all lvalues.

C also provides operators such as += and -= to write expressions such as
a += 2
instead of
a = a + 2
In Algol, the equivalent expression would be
a :=*+ 2


The following list contains all the possible assignment operators:
=
+=
-=
*=
/=
%=
3-19
>>=
<<=
&=
^=
|=
Types, Operators, and Expressions
Assignment operators

The semantics of a general assignment operator is specified by
variable op= expression
being equivalent to
variable = variable op (expression)

In the table below, assume that the following declarations are in scope.
int i = 1, j = 2, k = 3, m = 4;


The following table gives an expression, the equivalent fully
parenthesized expression, and the value of the expression.
Assume that these expressions are evaluated independent of each other.
Expression
j *= k + 3
i += j + k
j *= k = m + 5
Equivalent Expr
j *= (k + 3)
i += (j + k)
j *= (k=(m+5))
3-20
Equivalent Expr
j = j * (k + 3)
i = i + (j + k)
j = j * (k = (m + 5))
Value
12
6
18
Types, Operators, and Expressions
example

The expression
x *= 5;
is equivalent to writing
x = x * 5;

Similarly, the expression
y = (x1 += 1) * (x2 -= 2);

is roughly equivalent to writing
x1 = x1 + 1;
x2 = x2 - 2;
y = x1 * x2;
Note, however, that because C does not enforce the order of evaluation
of the multiplicative operands, the first and second statements may be
interchanged
example -- computing the powers of two
/* some powers of two are printed */
#include <stdio.h>
int main (void)
{
int power = 1;
printf ("%6d",
power *= 2);
printf ("%6d",
power *= 2);
printf ("%6d",
power *= 2);
printf ("%6d",
power *= 2);
printf ("%6d",
power *= 2);
printf ("%6d",
power *= 2);
printf ("%6d\n", power *= 2);
}
The output of this program is
2
4
8
16
32
64
128
3-21
Types, Operators, and Expressions
Conditional expressions
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.
3-22
Types, Operators, and Expressions
The conditional operator
Recall that the conditional operator ?: has the following syntax:
conditional_expression
expr1
expr2
expr3




::=
::=
::=
::=
expr1 ? expr2 : expr3
expression
expression
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
if (y <
x =
else
x =
if (a >
z =
else if
z =
else
z =
if (a >
if
z)
y;
z;
0)
1;
(a < 0)
-1;
0;
b)
(a > c)
z = a;
else
z = c;
else if (b > c)
z = b;
else
z = c;
equivalent conditional
x = (y < z)
? y
: z;
z = (a > 0)
? 1
: ((a < 0) ? -1 : 0);
z = (a > b)
? ((a > c) ? a : c)
: ((b > c) ? b : c);
3-23
Types, Operators, and Expressions
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
j%3==0 ? i+4 : x
j%3 ? i+4 : x
(i==j) ? (a-1) : (b+1)
((j%3)==0) ? (i+4) : x
(j%3) != 0 ? (i+4) : x
99
7.07
5.0
int
double
double
3-24
Types, Operators, and Expressions
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.:
3-25
Types, Operators, and Expressions
for (i = 0, j = 1, k = 2;
i < n;
i++, j++, k++) {
...
}
3-26
Types, Operators, and Expressions
Precedence and order of evaluation
Operator
()
!
++ -(unary) + (indirection) *
&
( type )
sizeof
*
/
%
+
< <= >= >
==
!=
Associativity
left to right
Order of Evaluation
-
right to left
-
left to right
left to right
left to right
left to right
&&
left to right
||
left to right
?:
right to left
left to right
sequence point after
first argument
short circuit
left to right
sequence point after
first argument
short circuit
first operand eval
sequence point after
first argument
=
+= -=
*= /= %=
right to left
,
left to right
3-27
left to right
sequence point after
first argument
Types, Operators, and Expressions
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.
3-28
Types, Operators, and Expressions
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().
f()
g()
+
assign to x


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;
3-29
Types, Operators, and Expressions
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.
"%d %d\n"
n
2
n
fetch n
(pre) ++
power
schedule store
of <n+1> to n
printf


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
3-30
Types, Operators, and Expressions
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
while
condition
false
true
statement1
statement2
...
statementN
3-31
Types, Operators, and Expressions
The while statement (2)
Some examples are
int x
int i
while
{
x
i
}
= 0;
= 0;
(i < n)
= x + i; /* x++ */
= 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.
3-32
Types, Operators, and Expressions
Example -- computing factorials
#include <stdio.h>
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
3-33
Types, Operators, and Expressions
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
3-34
Types, Operators, and Expressions
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?
3-35
Types, Operators, and Expressions
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*/
}
low
mid-1
mid+1
mid
exercise
Identify the statements within each if or while construct.
3-36
high
Types, Operators, and Expressions
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 <stdio.h>
#include <ctype.h>
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.
3-37
Types, Operators, and Expressions
The FOR statement (1)
 The syntax of a for statement is as follows.
for ( initialization-expression ;
condition ;
next-expression )
statement
next statement
for
initializationexpression
condition
false
true
statement1
statement2
...
statementN
next-expression
3-38
Types, Operators, and Expressions
Example -- computing factorials
factorial = 1;
i = 1;
while (i <= n)
{
factorial *= i;
i++;
}
factorial = 1;
for (i = 1; i <= n; i++)
{
factorial *= i;
}
 A common programming mistake when one uses a while construct is to
either forget the initialization of the variables or to forget the increment
of the loop index
 The for construct puts both of those things at the top
 Programmers are less likely to forget these things
 A for loop is simply a more “general” while loop
for
initializationexpression
condition
false
true
statement1
statement2
...
statementN
next-expression
3-39
Types, Operators, and Expressions
Example - Fibonacci Numbers
 Here is the version which uses a while loop
prev1 = prev2 = 1; /*first two numbers*/
sum
= 2; /*sum of the first two numbers*/
count = 2; /*calculate 3rd number on*/
while (count++ < N)
{
curr = prev1 + prev2;
sum += curr;
prev1 = prev2; /*advance prev1*/
prev2 = curr; /*advance prev2*/
}
 Here it is again, but using a for loop
prev1 = prev2 = 1; /*first two numbers*/
for (sum = 2, count = 2; count < N; count++)
{
curr = prev1 + prev2;
sum += curr;
prev1 = prev2; /*advance prev1*/
prev2 = curr; /*advance prev2*/
}
 In this example, we use the comma operator to form a longer, more
complex initialization expression
 We could also use it for create longer next expressions
 The logic of the for loop is slightly different here, but we also got rid of
rather tricky code that the while loop was using
 The while version post-incremented a count whose initial value was 2
 The number of iterations is N-2
 The for version starts with count=3 and continues until it is N, thus
iteration (N-3)+1 times, i.e. N+2 times
3-40
Types, Operators, and Expressions
The FOR statement (2)



The for statement, like the while statement, is used to execute code
iteratively.
The for statement in C is designed to be a lot more general (and
potentially more powerful) than Algol-like languages.
The following table gives syntax of various for-like constructs and the
equivalent while construct.
for statement syntax
equivalent while syntax
expr1 ;
while (expr2) {
statement
expr3 ;
}
next statement
while (expr2) {
statement
expr3 ;
}
next statement
while (expr2)
statement
next statement
while (1) {
statement
expr3 ;
}
next statement
while (1)
statement
next statement
for (expr1; expr2; expr3)
statement
next statement
for ( ;expr2; expr3 )
statement
next statement
for ( ;expr2; )
statement
next statement
for ( ;;expr3 )
statement
next statement
for (;;)
statement
next statement
3-41
Types, Operators, and Expressions
The FOR statement (3)
More generally, the syntax is a follows:
for_statement
expr1
expr2
expr3




::=
::=
|
::=
|
::=
|
for (expr1 ; expr2 ; expr3) statement
initialization-expression
test-relation-expression
next-expression
The first optional expression within the for loop is the initialization
 It is done before the loop starts
The second optional expression is the test condition
 It is performed at the beginning of each iteration
 If it is nonzero (true), the body of the loop is performed
 If it is zero (false), the for loop terminates
The third optional expression is an expression which will be performed
as the last statement in the loop
In this context, the semicolons are expression separators
3-42
Types, Operators, and Expressions
The FOR statement (4)
example -- infinite loop
for ( ;; ) /* while (1) */
{
statements
}
example
for construct
int i, n, sum;
...
sum = 0;
for (i=1; i<=n; i++)
sum = sum + i;
expr1:
expr2:
expr3:
equivalent while construct
int i, n, sum;
...
sum = 0;
i = 1;
while (i <= n)
{
sum = sum + i;
i++;
}
i = 1
i <= n
i++
3-43
Types, Operators, and Expressions
The FOR statement (5)

The for statement is similar to the Pascal for loop or the Fortran DO
statement
However, in C, both the index and limit can be altered within the loop

example
int getlimit (int limit);
int getindex (int index);
void ugly (void)
{
int i = 0, limit = 100;
for (i = 0; i < limit; i++) {
i = getindex (i);
limit = getlimit (limit);
printf ("Hmmm: i=%d and limit=%d\n",
i, limit);
}
}

This type of thing is not a good idea…
 The loop index and limit are changed by an outsider
 The behavior can be very unpredictable
3-44
Download