📄 07.txt
字号:
CS 1355
Introduction to Programming in C
Monday 2006.10.2 (Week 4)
Lecture notes (at http://r638-2.cs.nthu.edu.tw/C/notes/07.txt)
Chapter 4: C Program Control
- case sensitivity
- for loop
- switch statement
Case sensitivity
- in C, upper case and lower case letters are different.
if, If, IF, and iF are all different!
=> if is a keyword, but If, IF, iF are identifiers
=> different upper/lower case letters are considered different.
- other programming language may be case-insensitive
For-loop:
- another way to write loops
=> while loop: condition test
=> for loop: 3 parts
- initialization
- condition test (just like while loop)
- loop control update
For example: repeat 10 times
for (int i = 0; i < 10; i++) {
printf("%d\n", i);
}
This is equivalent to
int i = 0; /* initialization */
while (i < 10) /* condition test*/ {
printf("%d\n", i);
i++; /* update */
}
General structure:
for (/* initialization */ ; /* condition test */; /* update */) {
statement
}
So, why write it as a for loop?
- because it is easy to forget initialization or update
- particularly useful for "counter-controlled loops"
Important point:
- the initialization, condition test, and update are all expressions!!!
Specifically,
i = 0 is called an "assignment expression"
i < 10 is a comparison expression
i++ is a post-increment expression
- An expression has a value
Assignment operator as an expression
- assignment ( = ) is a binary operator
- an asignment expression has the value being assigned!!
- it is a "right associative" operator,
- the precedence of assignment expression is lower than
all other arithmetic operators
- so,
i = 0
first evaluates the RHS as 0,
assigns 0 to i,
then the (i = 0) expression has the value 0.
- This means, you can do multiple assignments
int x, y, z;
x = y = z = i = 0;
=> This is evaluated in the order
x = (y = (z = (i = 0)))
that is, i = 0, then z = 0, then y = 0, then x = 0
hence right associative.
Comma operator as an expression
- a comma is a binary operator,
left associative,
lower precedence than the assignment operator
- if you have the comma expression
x , y
(where x and y are expressions)
then it evalutes x, and then evaluate y, and
the expression has the value of y
Example
int i = (1, 2, 3, 4, 5);
printf("%d\n", i);
=> this will print 5, because it is the last expression in the
comma-separated list of expressions
Combining comma and assignment expressions:
int a, b, c;
a = 3, b = 2, c = 4;
What does it do???
- Answer: comma (,) has lower precedence than assignment (=)
So, it evaluates
(a = 3), (b = 2), (c = 4)
Instead of
a = (3, (b = (2, (c = 4))))
a = b = c = 4
Why use comma-separated assignments?
Answer: multiple assignments in FOR loops
Example: Fibonacci number
f(0) = 1
f(1) = 1
f(2) = f(0) + f(1) = 2
f(3) = f(2) + f(1) = 3
f(4) = f(3) + f(2) = 5
f(5) = f(4) + f(3) = 8
f(6) = f(5) + f(4) = 13
f(7) = f(6) + f(5) = 21
Solution:
- use
- one variable f_1 for f(n-1), initialized to 0
- one variable f_2 for f(n-2), initialized to 0
- one variable f_n for f(n)
- each loop,
set f_2 = f_1,
set f_1 = f_n
set f_n = f_2 + f_1,
int main() {
int i, n;
scanf("%d", &n);
int f_1 = 0, f_2 = 0, f_n = 1;
for (i = 0; i < n; i++) {
f_2 = f_1;
f_1 = f_n;
f_n = f_1 + f_2;
}
printf("f(%d) = %d\n", n, f_n);
}
You could also write it as
int i, n, f_2, f_1, f_n;
scanf("%d", &n);
for (i = 0, f_1 = 0, f_2 = 0, f_n = 1;
/* initialize multiple variables */
i < n; /* test the loop condition */
i++, f_2 = f_1, f_1 = f_n, f_n = f_1 + f_2
/* update multiple variables */) {
/* nothing more to do inside the loop in this case */
}
printf("f(%d) = %d\n", n, f_n);
This works the same, although somewhat contrived.
Other uses of FOR loops
- step down from 10 to 1
for (i = 10; i >= 1; i--) {
printf("%d\n", i);
}
- go from 10, 15, 20, 25, 30, 35, ... 100
for (i = 10; i <= 100; i += 5) {
printf("%d\n", i);
}
- step from 1, 2, 4, 7, 11, 16, 22, 29, 37, 46, 56, 67, 79, ...
scanf("%d", &n);
for (i = 1, f_n = 1; i < n; f_n += i++) {
}
Example from book: computing compound interest
#include <stdio.h>
#include <math.h>
int main() {
double amount;
double principal = 1000.0;
double rate = 0.05;
int year;
printf("%4s%21s\n", "Year", "Amount on Deposit");
for (year = 1; year <= 10; year++) {
amount = principal * pow(1.0 + rate, year);
printf("%4d%21.2f\n", year, amount);
}
}
How this works
- double: a double-precision floating point (64 bits, rather than 32 bits)
- <math.h>: another standard library, with all math routines
(check /usr/include/math.h)
- %s -- format for string
%4s format for string, right align (pad space on the left)
%-4s format for string, left align (pad space on the right)
- %f -- floating point
%21.2f -- 21 positions total, 2 digits after decimal
Question:
- last time, %f was for float type;
- but this time, we use double type instead of float type.
Is this ok??
Answer:
- yes. In fact,
C compiler converts all float to double type when
passing it as a parameter!!
- so, both float and double are treated as double.
=============
SWITCH statement
- it's somewhat like if/else-if/else-if/.../else
- restriction:
- compare one expression to see if it is equal to a constant
int main() {
char letter;
scanf("%c", &letter);
switch (letter) {
case 'A':
printf("score is 90..100\n");
break;
case 'B':
printf("score is 80..89\n");
break;
case 'C':
printf("score is 70..79\n");
break;
case 'D':
printf("score is 60..69\n");
break;
case 'F':
printf("score is 0..59\n");
break;
default:
printf("%c is not a valid letter grade\n", letter);
}
}
How it works:
- this is similar to
if (letter == 'A') {
printf("score is 90...100\n");
} else if (letter == 'B') {
printf("score is 80...89\n");
} else if (letter == 'C') {
...
} else {
printf("%c is not a valid letter grade\n", letter);
}
However, there are some differences.
1) you should have a "break" statement at the end of each case.
- break => exits the switch statement.
- actually, break can also exit a for-loop or a while-loop, too.
the meaning of break depends on the context (the innermost
statement that encloses it)
2) Restrictions on the case value
case 'A':
case 'B':
...
- the cases must be constant scalar values!! (int, char)
- CANNOT be string!!
- CANNOT be floats!!
- CANNOT be a variable or non-constant expression!
Example:
case x + 22:
- if x is a variable, then this is bad!!
- but if x is another integer literal, then it is ok
3) default:
- it will match all other cases,
similar to an "else" statement.
Fundamental difference between an if-statement and a switch-statement:
- switch is like a goto statement!!
- meaning: it jumps to the matching case as a label
- several cases can label the same location
- it continues stepping sequentially, until it reaches a break!
So, what if we took out the break statements?
switch (letter) {
case 'A': printf("score is 90..100\n");
case 'B': printf("score is 80..89\n");
case 'C': printf("score is 70..79\n");
case 'D': printf("score is 60..69\n");
case 'F': printf("score is 0..59\n");
default: printf("%c is not a valid letter grade\n", letter);
}
This means
if (letter == 'A') {
printf("score is 90..100\n");
printf("score is 80..89\n");
printf("score is 70..79\n");
printf("score is 60..69\n");
printf("score is 0..59\n");
printf("%c is not a valid letter grade\n", letter);
}
...
(because cases are only labels, not "else if" statements!)
this is probably not what you want!!
So, remember to put break;
But, why do it this way?
- Reason: it can be useful for multiple matches.
- For example
switch (letter) {
case 'A':
case 'a':
printf("score is 90..100\n");
break;
case 'B':
case 'b':
printf("score is 80..89\n");
break;
...
}
- You can have several labels that mark the same spot.
This is saying
if letter is either 'A' or 'a', then do the same thing
- in terms of IF statements,
if (letter == 'A' || letter == 'a') {
printf("score is 90..100\n");
} else if ...
Example from the book
1 #include <stdio.h>
2 int main() {
3 int grade, aCount = 0, bCount = 0, cCount = 0,
4 dCount = 0, fCount = 0;
5 while ( (grade = getchar()) != EOF) {
6 switch(grade) {
7 case 'A': case 'a': ++aCount; break;
8 case 'B': case 'b': ++bCount; break;
9 case 'C': case 'c': ++cCount; break;
10 case 'D': case 'd': ++dCount; break;
11 case 'F': case 'f': ++fCount; break;
12 case '\n': case '\t': case ' ': /* ignore blanks */
13 break;
14 default: /* catch all other characters */
15 printf("invalid grade %c\n", grade);
16 break; /* not necessary */
17 }
18 }
19 printf("A: %d\nB: %d\nC: %d\nD: %d\nF: %d\n",
20 aCount, bCount, cCount, dCount, fCount);
21 }
How to run this:
% ./a.out
A BACDFD ADa bacaFA
ABDDFFA ffaab
^D
A: 11
B: 4
C: 2
D: 5
F: 6
%
- enter letters,
A a B b C c D d F f => these are valid letters
ok to include blank, tab, return
- when finished, in the unix shell environment, type
[Return] Control-D
- Note: Control-D means hold down the [Control] key, then type [D]
Also written as ^D
- In DOS environment, it's ^Z
=> but in unix shell, ^Z means "stop-job"
suspends a program ("pause")
later can resume by typing "fg" or "%" in the shell prompt
- You can also redirect input from a file
% ./a.out < file
=> No need to type ^D in this case!
End-of-file is like a univeral sentinel
So.. how does this work:
1) grade is decalred as an int, not a char!!
2) while ((grade = getchar()) != EOF)
two parts:
- grade = getchar()
=> getchar() is a routine defined in <stdio.h>
it reads the next character from standard input
The return value of getchar() is the ASCII code for the character.
(see lecture 3 about character literals!)
But if we reach end-of-file, then it returns -1
=> not a valid ASCII code!
=> This is why it is important for grade to be an int, not a char,
because int is 4 bytes (can represent EOF),
but char is 1 byte (can represent only ASCII code, not EOF)
EOF = End-of-File
The name EOF is defined in <stdio.h> (see the file /usr/include/stdio.h)
#define EOF (-1)
- (grade = getchar()) itself is an assignment expression!!
it has the value of grade after assignment.
It can be used for comparison purpose
- So, we can compare
((grade = getchar()) != EOF)
This is like
4.5 grade = getchar();
5 while (grade != EOF) {
...
17.5 grade = getchar();
18 }
Writing it with assignment expression is shorter, no need for
duplicate statement
Actually, scanf() returns an integer, too!
- it returns the number of items successfully scanned
according to the %d %f %c etc format,
- it also returns EOF when reaching end-of-file
Example:
- prompts user for two ints,
- adds them, until end-of-file
#include <stdio.h>
int main() {
int x, y, z;
int n;
while (( printf("x y? "), (n = scanf("%d%d", &x, &y))) != EOF) {
z = x + y;
printf("%d + %d = %d\n", x, y, z);
}
}
Note:
- printf is also an expression!!
it is the LHS of a comma operator;
(n = scanf()...) is the RHS of a comma operator
=> comma operator evaluates both LHS and RHS, and returns RHS as its value!
- so, the while statement tests (LHS, RHS) != EOF
or effectively RHS != EOF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -