Goals of this Lecture !
Help you learn about:"
The fundamentals of C"
Program structure, control statements, character I/O"
Deterministic finite state automata (DFA)"
Some expectations for programming assignments"
C Programming Examples!
Why?"
The fundamentals of C provide a foundation for the
systematic coverage of C that will follow"
A power programmer knows the fundamentals of C well"
DFA are useful in many contexts "
A very important context: Assignment 1"
How?"
1
Overview of this Lecture!
Through some examples"
Example #1: Echo!
Problem: Echo input directly to output"
Program design"
C programming examples"
Echo input to output"
Convert all lowercase letters to uppercase"
Convert first letter of each word to uppercase"
Include the Standard Input/Output header file (stdio.h)"
#include <stdio.h>"
Allows your program to use standard I/O calls"
Makes declarations of I/O functions available to compiler"
Allows compiler to check your calls of I/O functions"
Glossing over some details related to pointers "
which will be covered subsequently in the course"
Define main() function"
int main(void) { }
int main(int argc, char *argv[]) { }
Starting point of the program, a standard boilerplate"
Hand-waving: argc and argv are for input arguments"
3
Example #1: Echo (cont.)!
Putting it All Together!
#include <stdio.h>
Within the main program"
int main(void) {
int c;
Read a single character"
c = getchar(); "
Read a single character from the standard input
stream (stdin) and return it"
c = getchar();
putchar(c);
return 0;
Write a single character"
putchar(c); "
Write a single character to the standard output
stream (stdout)"
Why int instead
of char?"
Why return a
value?"
Read and Write Ten Characters!
Read and Write Forever!
Loop to repeat a set of lines (e.g., for loop)"
Infinite for loop"
Three expressions: initialization, condition, and increment"
E.g., start at 0, test for less than 10, and increment per iteration"
Simply leave the expressions blank"
E.g., for ( ; ; ) "
No initial value, no per-iteration test, no increment at end of iteration"
#include <stdio.h>
int main(void) {
int c, i;
#include <stdio.h>
int main(void) {
int c;
Why not this instead:"
for (i = 1; i <= 10; i++)!
for (i=0; i<10; i++) {
c = getchar();
putchar(c);
}
for ( ; ; ) {
c = getchar();
putchar(c);
}
return 0;
return 0;
When will this
be executed?"
How would you terminate
this program?"
8
Read and Write Until End-Of-File!
Many Ways to Do the Same Job!
Test for end-of-file"
for (c=getchar(); c!=EOF; c=getchar())
EOF is a global constant, defined in stdio.h"
The break statement jumps out of the innermost enclosing loop"
#include <stdio.h>
int main(void) {
int c;
for ( ; ; ) {
c = getchar();
if (c == EOF)
break;
putchar(c);
}
return 0;
}
" putchar(c);
Typical idiom in C, but
messy side-effect in
loop test"
while ((c=getchar())!=EOF)
do some stuff
putchar(c);"
done yet?
do more stuff
after the loop
9
Review of Example #1!
for (;;) {
c = getchar();
if (c == EOF)!
break;
!putchar(c);
}!
c = getchar();
while (c!= EOF){
! putchar(c);
c = getchar();
}
10
Example #2: Convert Uppercase!
Character I/O"
Which approach
is best?"
before the loop
Problem: Write a program to convert a file to all uppercase"
Including stdio.h
Functions getchar() and putchar()
Representation of a character as an integer"
Predefined constant EOF
Leave non-alphabetic characters alone"
Program design:"
Program control flow"
The for and while statements"
The break statement"
The return statement"
repeat in a loop
Read a character
If unsuccessful, break out of loop
If the character is lower-case, convert to uppercase
Write the character
Operators"
Assignment operator: = "
Increment operator: ++"
Relational operator to compare for equality: =="
Relational operator to compare for inequality: !="
"
"
11
12
ASCII!
Implementation in C!
American Standard Code for Information Interchange"
8
10
11
12
13
14
15
0 NUL SOH STX ETX EOT ENQ ACK BEL BS
HT
LF
VT
FF
CR
SO
SI
SUB ESC FS
GS
RS
US
16 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM
32 SP
"
&
'
48
<
>
64
80
96
112
DEL
Lower case: 97-122 and upper case: 65-90"
E.g., a is 97 and A is 65 (i.e., 32 apart)"
#include <stdio.h>
int main(void) {
int c;
for ( ; ; ) {
c = getchar();
if (c == EOF) break;
if ((c >= 97) && (c < 123))
c -= 32;
putchar(c);
}
return 0;
}
13
It works!!
14
Its a !
"
Submit"
Receive your grade with quiet confidence "
B-"
15
16
What? But it works !
Avoid Hard-coded Numbers!
#include <stdio.h>
int main(void) {
A good program is:"
Ugly. "
And works for
ASCII only"
int c;
Clean"
Readable"
Maintainable"
for ( ; ; ) {
c = getchar();
if (c == EOF) break;
It s not enough that your program works!"
if ((c >= 97) && (c < 123))
c -= 32;
putchar(c);
We take this seriously in COS 217"
}
Seriously == It affects your grade substantially"
return 0;
17
Improvement: Character Constants!
Improvement: Existing Functions!
#include <stdio.h>
Standard C Library Functions
int main(void) {
NAME
int c;
for ( ; ; ) {
c = getchar();
if (c == EOF) break;
if ((c >=
c +=
a ) && (c <=
Better. "
But still
assumes that
alphabetic
character codes
are contiguous"
ctype(3C)
Section 3C is for C
library functions"
ctype, isdigit, isxdigit, islower, isupper, isalpha, isalnum, isspace, iscntrl, ispunct, isprint,
isgraph, isascii - character handling
z ))
a ;
putchar(c);
}
return 0;
}
18
19
SYNOPSIS
#include <ctype.h>
int isalpha(int c);
int isupper(int c);
int islower(int c);
int isdigit(int c);
int isalnum(int c);
int isspace(int c);
int ispunct(int c);
int isprint(int c);
int isgraph(int c);
int iscntrl(int c);
int toupper(int c);
int tolower(int c);
DESCRIPTION
These macros classify charactercoded integer values. Each is a
predicate returning non-zero for true, 0
for false...
The toupper() function has as a
domain a type int, the value of which is
representable as an unsigned char or
the value of EOF.... If the argument of
toupper() represents a lower-case
letter ... the result is the corresponding
upper-case letter. All other arguments
in the domain are returned unchanged.
20
Using the ctype Functions!
Building and Running!
#include <stdio.h>
#include <ctype.h>
int main(void) {
int c;
for ( ; ; ) {
c = getchar();
if (c == EOF) break;
Returns non-zero"
if (islower(c))
c = toupper(c); (true) iff c is a lowercase"
character"
putchar(c);
}
return 0;
}
21
Run the Code on Itself!
% ls
upper.c
% gcc217 upper.c o upper
% ls
upper upper.c
% upper
We ll be on time today!
WE LL BE ON TIME TODAY!
^D
%
22
Output Redirection!
% upper < upper.c
#INCLUDE <STDIO.H>
#INCLUDE <CTYPE.H>
INT MAIN(VOID) {
INT C;
FOR ( ; ; ) {
C = GETCHAR();
IF (C == EOF) BREAK;
IF (ISLOWER(C))
C = TOUPPER(C);
PUTCHAR(C);
}
RETURN 0;
}
% upper < upper.c > junk.c
% gcc217 junk.c o junk
test.c:1:2: invalid preprocessing directive #INCLUDE
test.c:2:2: invalid preprocessing directive #INCLUDE
test.c:3: syntax error before "MAIN"
etc...
23
24
Review of Example #2!
Example #3: Capitalize First Letter!
Representing characters"
Capitalize the first letter of each word"
cos 217 rocks Cos 217 Rocks "
ASCII character set"
Character constants (e.g., A or a )"
Sequence through the string, one letter at a time"
Manipulating characters"
Print either the character, or the uppercase version"
Arithmetic on characters"
Functions like islower() and toupper()
Challenge: need to remember where you are"
Capitalize c in cos , but not o in cos or c in
rocks "
Compiling and running C code"
Compile to generate executable file "
Invoke executable to run program"
Can redirect stdin and/or stdout"
The program should do different things for the
same input letter, "
25
States!
c in cos (capitalize) versus c in rocks (dont)"
Depends on where it is right now"
"
Deterministic Finite Automaton!
Where am I?"
Deterministic Finite Automaton (DFA)"
States"
Im inside a word"
Ive seen the first letter of it but not yet the space after it"
If I see a letter now, I should not capitalize it"
Im not inside a word "
If I see a letter now, I should capitalize it"
State 1: Im not already inside a word"
State 2: Im already inside a word"
Inputs: cause state transitions"
(Actions: determined by state+input)"
Im in my car"
If I get a phone call I shouldnt take it"
Im in my room"
If I get a phone call I can take it"
Actions are not"
part of DFA formalism;"
but they re helpful"
letter"
(print uppercase equivalent)"
What am I doing?"
1"
Im awake, Im asleep, "
Program needs a way to keep track of states, and take
actions not only based on inputs but also on states"
26
27
not-letter"
(print)"
not-letter"
(print)"
2"
letter"
(print)"
28
Implementation Skeleton!
#include <stdio.h>
#include <ctype.h>
int main (void) {
int c;
for ( ; ; ) {
c = getchar();
if (c == EOF) break;
<process one character>
}
return 0;
}
Process one character:
case 1:
Process one character:"
Check current state"
Check input character"
Based on state and character, check DFA and execute: "
a transition to new state, or stay in same state"
the indicated action"
Note: same input can lead to different actions"
letter"
(print uppercase equivalent)"
1"
if input char is a letter {
print uppercase (since
first letter of new word);
move to state 2 (in word);
}
otherwise print char as is;
break;
#include <stdio.h>
#include <ctype.h>
int main(void) {
int c; int state=1;
for ( ; ; ) {
c = getchar();
if (c == EOF) break;
switch (state) {
case 1:
<state 2 input check and action>
letter"
(print)"
30
if input char is a letter {
print uppercase (since
first letter of new word);
move to state 2 (in word);
}
otherwise print char as is;
if (isalpha(c)) {
putchar(toupper(c));
state = 2;
} else putchar(c);
break;
case 2:
case 2:
default:
2"
Complete Implementation!
<state 1 input check and action>
break;
not-letter"
(print)"
not-letter"
(print)"
29
not-letter
letter
letter
1
2
not-letter
Implementation!
switch (state) {
Implementation Skeleton!
if input not a letter
change state to 1 (not in
word);
in any case, print char as is;
if (!isalpha(c)) state = 1;
putchar(c);
if input is not a letter
break;
<this should never happen>
31
}
}
return 0;
change state to 1 (not
in word);
in any case, print char;
32
Running Code on Itself
It works!!
"
% gcc217 upper1.c -o upper1
% upper1 < upper1.c
#Include <Stdio.H>
#Include <Ctype.H>
Int Main(Void) {
Int C; Int State=1;
For ( ; ; ) {
C = Getchar();
If (C == EOF) Break;
Switch (State) {
Case 1:
If (Isalpha(C)) {
Putchar(Toupper(C));
State = 2;
} Else Putchar(C);
Break;
Case 2:
If (!Isalpha(C)) State = 1;
Putchar(C);
Break;
}
}
Return 0;
}
Submit"
What did I get? What did I get?"
33
Your grade!
34
OK, That s a B!
"
Works correctly, but"
Mysterious integer constants ( magic numbers )"
B"
What now?"
States should have names, not just 1, 2
35
36
Improvement: Names for States!
Improvement: Names for States!
#include <stdio.h>
#include <ctype.h>
enum Statetype {NOT_IN_WORD,IN_WORD};
Define your own named constants"
int main(void) {
int c; enum Statetype state = NOT_IN_WORD;
for ( ; ; ) {
c = getchar();
if (c == EOF) break;
switch (state) {
case NOT_IN_WORD:
enum Statetype {NOT_IN_WORD,IN_WORD};
Define an enumeration type"
enum Statetype state;"
Define a variable of that type"
if (isalpha(c)) {
putchar(toupper(c));
state = IN_WORD;
} else putchar(c);
break;
case IN_WORD:
if (!isalpha(c)) state = NOT_IN_WORD;
putchar(c);
break;
37
It still works, no magic constants!
}
}
return 0;
38
Ask and you shall not receive !
"
Submit"
Can I have my A+ please? I have a party to go to."
B+"
39
40
10
Huh?!
Improvement: Modularity!
Works correctly, but"
No modularity"
What now?"
Should handle each state in a separate function
Each state handling function does the work for a given
state, including reading the input and taking the action
It returns the new state, which we will store in the state
variable for the next iteration of our infinite loop
41
Improvement: Modularity!
#include <stdio.h>
#include <ctype.h>
enum Statetype {NOT_IN_WORD,IN_WORD};
enum Statetype handleNotInwordState(int c) {...}
enum Statetype handleInwordState(int c) {...}
int main(void) {
int c;
enum Statetype state = NORMAL;
for ( ; ; ) {
c = getchar();
if (c == EOF) break;
switch (state) {
case NOT_IN_WORD:
state = handleNotInwordState(c);
break;
case IN_WORD:
state = handleInwordState(c);
break;
}
}
return 0;
}
42
Improvement: Modularity!
enum Statetype handleNotInwordState(int c) {
enum Statetype handleInwordState(int c) {
enum Statetype state;
enum Statetype state;
if (isalpha(c)) {
putchar(c);
putchar(toupper(c));
if (!isalpha(c))
state = IN_WORD;
state = NOT_IN_WORD;
else
else {
state = IN_WORD;
putchar(c);
return state;
state = NOT_IN_WORD;
}
return state;
}
43
44
11
Its a thing of beauty !
Seriously??!
"
No comments"
Should add (at least) function-level comments
A-"
45
Function Comments
46
Function Comment Examples
Bad main() function comment
Read a character from stdin. Depending upon the
current DFA state, pass the character to an
appropriate state-handling function. The value
returned by the state-handling function is the
next DFA state. Repeat until end-of-file.
A function s comment should:
Describe what the function does
Describe input to the function
Parameters, input streams
Describes how the function works!
Describe output from the function
Return value, output streams, (call-by-reference
parameters)
Good main() function comment
Read text from stdin. Convert the first
character of each "word" to uppercase, where a
word is a sequence of letters. Write the result
to stdout. Return 0.
Not describe how the function works
Describes what the function does from caller s point of view"
47
48
12
An A Effort!
An A Effort!
#include <stdio.h>
#include <ctype.h>
/*------------------------------------------------------------*/
enum Statetype {NOT_IN_WORD, IN_WORD};
/* handleInwordState: Implement the IN_WORD state of the DFA.
/* c is the current DFA character.
/*------------------------------------------------------------*/
/* handleNormalState: Implement the NOT_IN_WORD state of the DFA.
/* c is the current DFA character. Return the next state.
*/
*/
Return the next state.
*/
*/
/*------------------------------------------------------------*/
enum Statetype handleInwordState(int c) {
/*------------------------------------------------------------*/
enum Statetype state;
enum Statetype handleNotInwordState(int c) {
enum Statetype state;
if (isalpha(c)) {
putchar(c);
if (!isalpha(c))
putchar(toupper(c));
state = NOT_IN_WORD;
state = IN_WORD;
}
else
else {
state = IN_WORD;
putchar(c);
return state;
state = NOT_IN_WORD;
}
return state;
}
49
An A Effort!
Review of Example #3!
/*------------------------------------------------------------*/
/* main: Read text from stdin. Convert the first character
Deterministic finite state automaton"
*/
Two or more states"
Transitions between states"
Next state is a function of current state and current input"
Actions can occur during transitions"
/* of each "word" to uppercase, where a word is a sequence of */
/* letters. Write the result to stdout. Return 0.
*/
/*------------------------------------------------------------*/
int main(void) {
int c;
enum Statetype state = NOT_IN_WORD;
/* Use a DFA approach.
state indicates the state of the DFA. */
Expectations for COS 217 assignments"
for ( ; ; ) {
c = getchar();
if (c == EOF) break;
switch (state) {
case NOT_IN_WORD:
state = handleNotInwordState(c);
break;
case IN_WORD:
state = handleInwordState(c);
break;
}
}
return 0;
}
50
51
Readable"
Meaningful names for variables and values"
qqq is not meaningful. Nor are foo and bar"
Modular"
Multiple functions, each of which does one well-defined job"
Function-level comments"
Should describe what function does"
See K&P book for style guidelines specification"
"
52
13
Another DFA Example!
Yet Another DFA Example!
Question #4 from fall 2005 midterm
Identify whether or not a string is a floating-point number
Does the string have nano in it?"
banano "
nnnnnnnanofff "
banananonano "
bananananashanana "
Valid numbers"
n
n
S
a
No input shown on an
arc => any other input
53
-34 "
78.1 "
+298.3 "
-34.7e-1 "
34.7E-1 "
7. "
.7 "
999.99e99 "
Invalid numbers"
abc "
-e9 "
1e "
+ "
17.9A "
0.38+ "
. "
38.38f9 "
54
Summary !
Examples illustrating C"
Overall program structure"
Control statements (if, while, for, and switch)"
Character input/output (getchar() and putchar())"
Deterministic finite state automata (i.e., state
machines)"
Expectations for programming assignments"
55
14