Title: Introduction to C Lecture 3: Flow of Control
1Introduction to CLecture 3 Flow of Control
2Relational, equality and logical operators
- Relational operators are
- lt , gt less, greater than
- lt, gt less (greater) than or equal to
- Equality operators are
- , ! equal (not equal) in a
question (e.g. if (x 5)...) - Logical operators are
- ! not
- logical and
- logical or.
- As weve said before, when using multiple
operators you should use brackets (a) to make
sure your code is clear, and (b) to avoid the
need to know the order in which these operators
act. - Warning A common error is to use instead of
this will then set the value instead of
comparing it...
3Relational operators
- The operators gt, lt, lt, gt are all binary they
take two expressions as operands and yield either
0 or 1 (int). E.g. - a lt 3 yields 1 if true, 0 if false.
- Note that this is another example of the whole
expression having a value (which is entirely
distinct from the value of a). - Often a lt b is implemented as a - b lt 0, i.e. b
is subtracted from a and the answer compared with
zero. - Â Consider the expression
- 3 lt j lt 5
- which is false, mathematically, if j 7 for
example. In C, however, it is evaluated as - (3 lt j) lt 5 / note left-to-right association /
- and since 3 lt j is true, this is equivalent to
- 1 lt 5
- which is also true. The expression as a whole
therefore is true, and yields 1. The correct way
to do the test 3 lt j and j lt 5 is - (3 lt j) (j lt 5)
- and this is true only if both operands of are
true. (Strictly speaking you could leave out the
brackets, as lt happens before , but if you put
the brackets in you dont have to worry about
it).
4Relational operators Floating-point numbers
- Warning
- When dealing with floating-point numbers, watch
for rounding error dont ask - if (x 0.0) ...
- if x is floating-point, as some rounding error
may have left it being a small, but non-zero,
value instead, try something like - eps 1.0e-30
- if (fabs(x) lt eps) .....
5Logical operators
- These are (and), (or) and ! (not). Note
that you can apply ! to arithmetic expressions
if the expression is zero, the result will be 1
if the expression is non-zero, the result will be
zero. This means that, whereas in ordinary
logic not (not x) would yield the result x,
the expression !!5 / equivalent to !(!5)
/in C yields 1. - Â
- Another common mistake is the use of instead of
the former is a bitwise operation, which we
will come to in due course. Â - In evaluating and , the process stops as
soon as the outcome is known so if, for example,
you write while (cnt lt 3 (k gt 10)
/ do something... /then, when the
expression cnt lt 3 is false, k will not be
incremented, so if you were relying upon that
happening, you will be in trouble....
6Exercise
- Give equivalent simplified logical expressions of
the following (i.e. get rid of the initial
not). - !(a gt b)
- !(a lt b c lt d)
- !(a 1 b 1)
- !(a lt 1 b lt 2 c lt 3)
- Â
7Compound statements
- A group of statements in braces is a compound
statement when a declaration (e.g. int x) is
included with it, it is called a block. A
compound statement is itself a statement. It is
usual to indent statements within braces, making
it easier to read e.g. -
- if (a 1)
- b 2
- c 3
- e d c
-
-
- If you use tabs, emacs knows the standard
indentation rules and will do it for you.
8Expression statements
- Expression statements are expressions followed by
a semicolon these have to be evaluated
(including side effects) before proceeding to the
next step. Examples include - a b / assignment statement /
- a b c / legal, but not useful /
- / empty statement sometimes necessary
in if constructs etc / - printf(d\n, a) / a function call /
9if and if-else
- General form is
- if (expr)
- statement
- If expr is nonzero, statement is executed.
Example - if (c )
- blank_cnt
- printf(Found another blank.\n)
-
- Â
- An obvious extension is if-then-else
- if (c gt a c lt z)
- lc_cnt
- else
- other_cnt
- printf(c is not a lowercase letter.\n, c)
-
Note that you cannot use if (i ! j) i
1 j 2 else i - j The
semicolon makes an empty statement, and the else
then has nowhere to attach to.
10if-then-else contd
- Note also that if can itself be part of an if
statement - if (a 1)
- if (b 2)
- printf(\n)
- this is called nesting. An else attaches to
the nearest if thus - if (a 1)
- if (b 2)
- printf(\n)
- else
- printf(\n)
- is not correctly formatted the machine will read
it as - if (a 1)
- if (b 2)
- printf(\n)
- else
- printf(\n)
-
- Â
11While loops
- Format is while (expr) statement
- Examples
or - Be careful to avoid infinite loops! Consider
- while (--n)
- / do something /which would normally
stop when n reaches zero but if n is negative to
start with, the loop will be infinite. You could
instead say - while (--n gt 0)
- / do something /which would guard
against this possibility. - Here we can see an occasion when an empty
statement might be useful. Consider - while ((c getchar()) )
- / empty statement /
- which skips blank characters in the input stream.
Incidentally, the semicolon could go on the same
line as the while, but putting it on the next
line makes it clearly visible as an empty
statement otherwise it will look at first glance
as though the following lines of code are part of
the while loop.
while ((c getchar()) ! EOF) / read
from file... /
while (i lt n) factorial i
12While loops example (cnt_char.c)
- / Count blanks, digits, letters, newlines and
others / - include ltstdio.hgt
- int main(void)
-
- int blank_cnt 0, c, digit_cnt 0, letter_cnt
0, nl_cnt 0, other_cnt 0 - Â while (( c getchar() ) ! EOF)
- if (c ' ')
- blank_cnt
- else if (c gt '0' c lt '9')
- digit_cnt
- else if (c gt 'a' c lt 'z' c gt 'A' c
lt 'Z') - letter_cnt
- else if (c '\n')
- nl_cnt
- else
- other_cnt
-
- printf("10s10s10s10s10s10s\n\n",
- "blanks", "digits", "letters", "lines",
"others", "total")
13While loops example (cnt_char.c)
- / Count blanks, digits, letters, newlines and
others / - include ltstdio.hgt
- int main(void)
-
- int blank_cnt 0, c, digit_cnt 0, letter_cnt
0, nl_cnt 0, other_cnt 0 - Â while (( c getchar() ) ! EOF)
- if (c ' ')
- blank_cnt
- else if (c gt '0' c lt '9')
- digit_cnt
- else if (c gt 'a' c lt 'z' c gt 'A' c
lt 'Z') - letter_cnt
- else if (c '\n')
- nl_cnt
- else
- other_cnt
-
- printf("10s10s10s10s10s10s\n\n",
- "blanks", "digits", "letters", "lines",
"others", "total")
To execute this program, using its source file
for data, we give the command cnt_char lt
cnt_char.c and we get printed out onto the screen
a table of the numbers of blanks, letters etc.
14for loops
- Like while, the for statement is used for
looping. The construction - for (expr1 expr2 expr3)
- statement
- next statement
- is equivalent to
- expr1
- while (expr2)
- statement
- expr3
-
- next statement
- provided that expr2 is present (and provided that
there is no continue statement in the body of the
for loop, in which case expr3 would not be
evaluated).
15For loops Example
- for (i 1, factorial1 i lt n i)
- factorial i
- In this case, i is set to 1 initially the loop
iterates as long as i is lt n and at the end of
each iteration, i is incremented. This
construction transparently keeps all control of
the looping together at the top. Any of the
statements may be absent, but the two semicolons
must be present e.g. - i 1
- factorial 1
- for ( i lt n )
- factorial i
- i
-
- is equivalent to the above. If the condition
(i.e. the second expression) is missing, it is
regarded as being always true. For complete
brevity, we could write - for (i 1, factorial1 i lt n factorial i,
i)which does the same thing all in one line.
16Do loops
- do is like while, except that the condition is
tested at the bottom of the loop instead of the
top. Example - do
- printf(Input a postive integer )
- scanf(d, n)
- if (error (n lt 0))
- printf(\n ERROR input was not a positive
integer!\n) - while (error)
- Â
- Â Â Â Â Â Note the use of the error construction (n
lt 0) is 0 or 1 then error is set to 0 or 1
accordingly, but also the expression as a whole
and if the expression is non-zero, the if test
is true. - A do loop is always carried out at least once, as
the condition is not tested until the end. They
are not very common, and it is usual to include
the body of the loop in even when not needed.
17Example Fibonacci numbers
- Fibonacci numbers are defined recursively by
- f0 0, f1 1, fi1 fi fi-1 for i 1,
2.... - The sequence is
- 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
233... - They have many interesting uses and properties.
For example, the sequence of quotients - qi fi / fi-1 for i 2, 3....
- converges to the golden mean (1 sqrt(5))/2.
- Let us write a program to generate Fibonacci
numbers and quotients, in file fibonacci.c.
18Fibonacci numbers contd
- include ltstdio.hgt / Print Fibonacci numbers
and quotients / - define LIMIT 46
- Â
- int main(void)
-
- long f0 0, f1 1, n, temp
- Â
- printf("7s19s29s\n7s19s29s\n7s19s29s\n",
- / headings /
- " ", "Fibonacci", "Fibonacci",
- " n ", " number", " quotient",
- "-------", "---------", "---------")
- printf("7d19d\n7d19d\n", 0, 0, 1, 1) /
First 2 cases / - for (n 2 n lt LIMIT n)
- temp f1
- f1 f0
- f0 temp
- printf("7ld19ld29.16f\n", n, f1, (double)
f1/f0) -
19Fibonacci numbers contd
- include ltstdio.hgt / Print Fibonacci numbers
and quotients / - define LIMIT 46
- Â
- int main(void)
-
- long f0 0, f1 1, n, temp
- Â
- printf("7s19s29s\n7s19s29s\n7s19s29s\n",
- / headings /
- " ", "Fibonacci", "Fibonacci",
- " n ", " number", " quotient",
- "-------", "---------", "---------")
- printf("7d19d\n7d19d\n", 0, 0, 1, 1) /
First 2 cases / - for (n 2 n lt LIMIT n)
- temp f1
- f1 f0
- f0 temp
- printf("7ld19ld29.16f\n", n, f1, (double)
f1/f0) -
Variables are declared to be of type long
because some of those printed are too large to be
stored in a 2-byte int (not usually a problem on
modern machines). n doesnt have to be long it
could just as well be int.
20Fibonacci numbers contd
- include ltstdio.hgt / Print Fibonacci numbers
and quotients / - define LIMIT 46
- Â
- int main(void)
-
- long f0 0, f1 1, n, temp
- Â
- printf("7s19s29s\n7s19s29s\n7s19s29s\n",
- / headings /
- " ", "Fibonacci", "Fibonacci",
- " n ", " number", " quotient",
- "-------", "---------", "---------")
- printf("7d19d\n7d19d\n", 0, 0, 1, 1) /
First 2 cases / - for (n 2 n lt LIMIT n)
- temp f1
- f1 f0
- f0 temp
- printf("7ld19ld29.16f\n", n, f1, (double)
f1/f0) -
After printing the heading and the first 2
cases, n is initialized to 2, and the loop runs
until it reaches the predefined LIMIT.
21Fibonacci numbers contd
- include ltstdio.hgt / Print Fibonacci numbers
and quotients / - define LIMIT 46
- Â
- int main(void)
-
- long f0 0, f1 1, n, temp
- Â
- printf("7s19s29s\n7s19s29s\n7s19s29s\n",
- / headings /
- " ", "Fibonacci", "Fibonacci",
- " n ", " number", " quotient",
- "-------", "---------", "---------")
- printf("7d19d\n7d19d\n", 0, 0, 1, 1) /
First 2 cases / - for (n 2 n lt LIMIT n)
- temp f1
- f1 f0
- f0 temp
- printf("7ld19ld29.16f\n", n, f1, (double)
f1/f0) -
- The sequence of the main loop is
- 1. Save f1, the current number, in a temporary.
- 2. Add f0 and f1, and store the value in f1, the
new Fib. number. - 3. Store the temporary in f0, so that f0
contains the previous number. - 4. Print out, then repeat process.
22Fibonacci numbers contd
- include ltstdio.hgt / Print Fibonacci numbers
and quotients / - define LIMIT 46
- Â
- int main(void)
-
- long f0 0, f1 1, n, temp
- Â
- printf("7s19s29s\n7s19s29s\n7s19s29s\n",
- / headings /
- " ", "Fibonacci", "Fibonacci",
- " n ", " number", " quotient",
- "-------", "---------", "---------")
- printf("7d19d\n7d19d\n", 0, 0, 1, 1) /
First 2 cases / - for (n 2 n lt LIMIT n)
- temp f1
- f1 f0
- f0 temp
- printf("7ld19ld29.16f\n", n, f1, (double)
f1/f0) -
Note the need for temporary storage if
instead we had written f1 f0 f0 f1
then each time through the loop f0 would not
contain the previous number.
23Fibonacci numbers contd
- include ltstdio.hgt / Print Fibonacci numbers
and quotients / - define LIMIT 46
- Â
- int main(void)
-
- long f0 0, f1 1, n, temp
- Â
- printf("7s19s29s\n7s19s29s\n7s19s29s\n",
- / headings /
- " ", "Fibonacci", "Fibonacci",
- " n ", " number", " quotient",
- "-------", "---------", "---------")
- printf("7d19d\n7d19d\n", 0, 0, 1, 1) /
First 2 cases / - for (n 2 n lt LIMIT n)
- temp f1
- f1 f0
- f0 temp
- printf("7ld19ld29.16f\n", n, f1, (double)
f1/f0) -
Because variables are of type long, printf
uses ld (notice l here is lowercase L, not digit
1).
24Fibonacci numbers contd
- include ltstdio.hgt / Print Fibonacci numbers
and quotients / - define LIMIT 46
- Â
- int main(void)
-
- long f0 0, f1 1, n, temp
- Â
- printf("7s19s29s\n7s19s29s\n7s19s29s\n",
- / headings /
- " ", "Fibonacci", "Fibonacci",
- " n ", " number", " quotient",
- "-------", "---------", "---------")
- printf("7d19d\n7d19d\n", 0, 0, 1, 1) /
First 2 cases / - for (n 2 n lt LIMIT n)
- temp f1
- f1 f0
- f0 temp
- printf("7ld19ld29.16f\n", n, f1, ((double)
f1)/f0) -
(double) f1 / f0turns f1 into a
double, and then floating-point (instead of
integer) arithmetic is done. Note 5/4 1 in
integer arithmetic, for example, and 1.25 in
floating-point.
25goto statements
- goto causes an unconditional jump to a labelled
statement. Example - if (k lt 0) goto error
- ....
- error
- printf(An error has occurred - goodbye!\n)
- exit (1)
-
- Â Â Â Â Â General rule dont use them! Jumping
around in code like this rapidly makes it
incomprehensible. (You might be excused on very
rare occasions, such as to jump out of a very
deeply nested inner loop if some test fails but
it should never be necessary).
26Break, and continue
- break causes an exit from the innermost
enclosing loop - while (1)
- scanf(lf, x)
- if (x lt 0.0)
- break / exit loop if x is negative /
- printf(f\n, sqrt(x))
-
- / break jumps to here /
- continue causes the current iteration of a loop
to end, and the next to begin immediately - for (i 0 i lt TOTAL i)
- c getchar()
- if (c gt 0 c lt 9)
- continue
- / .... process other characters /
- / continue transfers to here to begin next
iteration / -
- continue can only be used in loops, of course.
Both break and continue should be avoided in
general, except that break is useful in switch
statements...
27switch
- switch is a generalization of a multiple if-else
statement. Example - switch (c)
- case a
- a_cnt
- break
- case b
- case B
- b_cnt
- break
- default
- other_cnt
-
- The controlling expression in () after switch
(here c) must be of integral type (which includes
characters). After the expression is evaluated,
it is matched to each case in turn, and when a
match is found (or if the default label is
reached), execution starts at that point.
Warning the case statements are just labels if
there is no break statement, execution falls
through to the statements in the next case.
This is a common cause of bugs. The default case
is optional, and is usually of course at the end.
- Â
28Conditional operator
- The conditional operator ? is ternary, i.e. it
takes three arguments. Usage - expr1 ? expr2 expr3
- If expr1 is true, then expr2 is evaluated, and
that is the value of the statement as a whole.
If expr1 is false, then expr3 is evaluated, and
that is the value of the statement as a whole. - Thus, this can do the work of an if-else
statement. Example - if (y lt limit)
- x z1
- else
- x z-1
- can be rewritten as
- x (y lt limit) ? z1 z-1
- Â
-
29For your homework
- Please make sure code is in your lect2, lect3
etc directory. If you have problems with it,
please ask me - Please remember to hand in a hard copy to my
pigeonhole by 5 pm each Weds