Title: CS 1312
1CS 1312
- Introduction to
- Object Oriented Programming
- Lecture 26
- C Input/Output
- Miscellaneous Topics
2Agenda
Streams -- What are they? Reading from the
keyboard -- safety first More printf fun --
more than meets the eye Reading/writing
files Misc. C Trivia -- Enough already!
3First there was I/O...
4Input 1
- Jacquard uses punched cards to control loom
- Hollerith at MIT develops punched card technology
to do census - CTR
- IBM
- Fixed length records
5The formerly ubiquitous punched card
6Input 2
- Telephone
- Telegraph
- Wireless
- Teletype
- Paper Tape
- Paper tape wastes no space. It appears to be a
stream of data arriving as input or leaving as
punched output.
7Streaming Input
- Paper tape
- Input from keyboard
- Input from modem
- Others?
8Well, yes...
- Even devices like disk drives which inherently
are not stream oriented devices can be made to
act that way through software techniques.
9By default
- A C program will have several streams defined
by default. - By some remarkable coincidence they are similar
to the streams in Java (in, out, err) - C Defaults
- stdin
- stdout
- stderr
10stdin, stdout, sterr
- By default stdin is reading from the keyboard.
- stdout is writing to the screen
- stderr is also writing to the screen
- Why do we have two output streams?
- In a nutshell...its possible to redirect the
output streams. (What was done when using dat/ans
files.) - So we can redirect stdout into a file and still
see error messages sent to stderr - Very clever!
11printf
- In Java we had an easy choice
- System.out.println (Hello World)
- System.err.println (Something is terribly
wrong!) - In C the normal printf command is by default
hooked up to just stdout - printf (Hello World\n)
12Buffers?
- Whether a device is inherently stream oriented
(like a keyboard) or being forced to emulate
stream behavior doesnt matter. - Modern computer systems store stream data in
buffers. - When you ask for some it gets it out of the
buffer. - This normally solves a speed mismatch problem and
makes things much more efficient.
Almost anything can be used as a stream, or a
source of input a keyboard, a network
connection, a file--even a string in memory.
13Aha!
Weve already seen (a little) how streaming
objects can be used to incrementally read
information.
BufferedReader br FileReader fr new
FileReader(strFileName) br new
BufferedReader(fr) String strLine null while
( (strLine br.readLine() ) ! null) //
handle new line of input in strLine
Here, the bulk of the file remains resident on
disk, and we use a buffer to read lines from
disk. The stream object is expressed a
FileReader, wrapped in a BufferedReader for
greater flexibility.
14Reading from the Keyboard
In C, we can use the putchar and getchar()
methods to move single characters to the console,
from the keyboard. The prototypes for these
methods int getchar(void) int putchar(int
c) These are included in stdio.h, used in just
about every C program. Both of these methods
return EOF, usually defined at -1, if theres
an error. Note that getchar returns an int,
which we might cast to a char. Why would anyone
in their right mind have a function called
getchar return an int?
15Example Echo
Did you know you can do this with printf? Now you
do.
include ltstdio.hgt int main (void) int ch
printf(Enter some text, or
Control-d (unix) or Control-z (win)
to exit\n) / ECHO INPUT BACK / do
ch getchar() printf(c,
(char)ch) while (ch ! EOF) return
0
We cast the return value.
EOF signals the end of file. This is Ctrl-D on
unix, or Ctrl-Z on windows.
16Test Run Shocker!
Enter some text, or Control-d (unix) or Control-z
(win) to edit A A This is a test This is a
test Hey, it echoes entire lines. What
gives? Hey, it echoes entire lines. What gives?
This works, and seems to print out entire lines.
But getchar() was supposed to give us just one
char. What gives?
17getchar()s dirty past
In its original Unix form, getchar() did not
return a character until someone hit return.
This is called line-buffering input. ANSI-C
defines getchar() to have this behavior. For
historical reasons, getchar() works this way!
Half-duplex time-sharing!!! If more than one
character was entered, the extra characters are
buffered for subsequent calls to getchar().
H
O
W
?
Enter
Entire line of sample input
The H key is return from the first call to
getchar(), and the rest of the line is buffered,
and returned on subsequent calls.
18Dangerous string inputs
Well, reading a single char can be tedious. How
can we read an entire string? Were about to
cover the most dangerous technique for string
input in C. Were showing you this for
historical reasons, and to help prevent
problems. Use this technique only for the good
of mankind.
Actually if you use this technique you probably
wont be doing mankind any good.
19gets How NOT to get strings
The gets() method reads a string of characters,
and places them at the address pointed to by its
argument. Lets hope you made enough room for
the input. The prototype for gets() is char
gets(char str) Here, str should be a char
array--a buffer--where you want the input
stored. Normally, you do something like
char buffer256 / some sufficient number /
gets(buffer) / we failed to check
the return value
gets() returns EOF on error / If you dont
provide enough room for the input, the user
overwrites portions of memory, including,
perhaps, your own code.
20Demonstration
include ltstdio.hgt int main (void) char
buf16 printf("Please enter no more than 15
characters\n") gets(buf) printf("You
entered s", buf) return 0 gcc -o ovflo
ovflo.c (Compiler warns about gets!!!) ovflo Plea
se enter no more than 15 characters Now is the
time for all good men to come to the
aid... Segmentation fault
The gets() method is the source of numerous
security problems. Even the compiler warns
against its use. When the C compiler says its
dangerous, you can believe it.
21Summary of getchar(), gets()
gets() returns many chars can use backspace to
correct cant return a \n security hazard
get your box rooted
getchar() returns a char no backspace
allowed cant return \n line-buffers
Dont use gets( )... unless you are an expert !
How can we read a string safely? To do this
right, we need to understand how format
specifiers work. We should start with some
simple printf examples.
22Questions?
23Formatting Console I/O
We already know the trick about printing numbers
in C.
int num 12 printf (Number d \n, num)
The d format specification means that a number
argument should be placed in the output. The
c format specification means a char should be
used.
24Format specifications (partial list)
c character d signed decimal
integers i signed decimal integers (historical
version) e scientific notation (e) f
decimal floating point g uses smaller of f
or e o unsigned octal s string
chars u unsigned decimal ints x
unsigned hex (lowercase letters) X unsigned
hex (uppercase) p displays a pointer n
arg is int pointer into which chars printed
so far is placed a percent
sign
For our purposes there are a few useful
formatting specs.
25Pointers on Pointers (again)
Remember the confusion over pointers? Now you
can print out information that will help you
understand how they work.
include ltstdio.hgt int main (void) int px
int x 0, 1, 2, 3, 4, 5, 6, 7, 8 px
x printf ("Pointer holds address p\n", px)
px printf ("After increment, pointer holds
address p\n", px) return 0
What will print out? Lets see ...
26C\TYC\Klassgttype ptrprnt.c include
ltstdio.hgt int main (void) int px int x
0, 1, 2, 3, 4, 5, 6, 7, 8 px x printf
("Pointer holds address p\n", px) px
printf ("After increment, pointer holds "
"address p\n", px) return
0 C\TYC\Klassgtgcc ptrprnt.c C\TYC\Klassgta P
ointer holds address 0x256f4f4 After increment,
pointer holds address 0x256f4f8 C\TYC\Klassgt
So pointer arithmetic really does work! Weve
proved it.
27Minimum Field Specifications
But printf has many other depths. We can
specify a minimum field value for numbers. For
example, we can use int num printf (5d,
num) And this guarantees that the num will
take up five spaces. This helps us align columns
very easily. We can also int num printf
(05d, num) to pad the extra spaces with
zeros. This is useful for spread sheets.
28Recall . . .
include ltstdio.hgt / Calculate temp conversion
table / int main (void) int fahr, celc
int min, max, step min -40 max
50 step 5 fahr min while
(fahr lt max) celc 5
(fahr-32)/9 printf ("d\td\n",
fahr, celc) fahr fahr step
Since tabs are not reliable for output
formatting, we can replace this with the minimum
field width specifiers instead.
Lets replace this with
printf (5d5d\n, fahr, celc)
29Ahhh.
C\TYC\Klassgtcelc_old -40 -40 -35 -37 -30
-34 -25 -31 -20 -28 -15 -26 -10
-23 -5 -20 0 -17 5 -15 10
-12 15 -9 20 -6 25 -3 30
-1 35 1 40 4 45 7 50 10
C\TYC\Klassgtcelc_new -40 -40 -35 -37 -30
-34 -25 -31 -20 -28 -15 -26 -10 -23
-5 -20 0 -17 5 -15 10 -12 15
-9 20 -6 25 -3 30 -1 35 1
40 4 45 7 50 10
No ragged edges. This is much easier in C than
Java!
Well, almost easier than Java. Theres a library
you can use to get printf services in
Java Search for jprintf
30Other printf magic
Left justification printf (-d\n,
num) Precision Specification printf
(.4f\n, 123.45678) /
prints out 123.4568, rounded! / Range of
strings printf (5.10s\n, str) /
prints at least 5, and no more than 10 chars
/ Variable field width printf (0d\n, i,
num)
field width is a variable
31C\TYC\Klassgtramp 0 1 02 003 0004 00005 000006 000
0007 00000008 000000009 000000009 00000008 0000007
000006 00005 0004 003 02 1 0
include ltstdio.hgt int main (void) int i
for (i0 i lt 10 i) printf ("0d\n", i,
i) while (i--) printf ("0d\n", i, i)
return 0
Text formatting is easy, and powerful, in C.
32Back to Reading From Stdin
All of these format specifications are swell, but
what does this have to do with safely reading
input? The procedure scanf() takes in many of
these format specifications, and writes the
keyboard input to a variable. Heres the
prototype int scanf (const char format,
...) Example int x printf (Enter a
number\n) scanf (d, x)
This means a variable number of parameters.
Strange, eh?
We give scanf the address of the variable to save
the input into
We want an int from the input
33scanf
scanf() will stop reading further when a
non-numeric character is found.
int x printf (Enter a number\n) scanf (d,
x)
scanf() can also read in strings, which it breaks
on white space, and then null terminates for you
char buff64 printf (Enter a name\n) scanf
(63s, buff)
Because of the field width specification, we can
prevent buffer overflows. Here, scanf() will not
copy more than 63 chars into our buffer.
34scanf() and scansets
We can also limit the types of characters that
scanf() will accept XYZ A-Z
2468 Example char
cLetters26 printf (Enter capital
letters) scanf (A-Z, cLetter)
Only characters in the brackets will be allowed
as input
Ranges may be used
Scanf() will then copy any input matching the
valid set into the buffer.
35The power of scanf
include ltstdio.hgt int main (void) char
cAxis2 char buff256 cAxis0 '\0'
buff0 '\0' printf ("Enter axes to rotate,
X, Y and/or Z ") scanf ("1XYZ255s",
cAxis, buff) if (cAxis0) printf ("Valid
input s\n", cAxis) else printf ("Invalid
input.\n") if(strlen(buff)gt0) printf
("You entered extra information s\n", buff)
The user can only enter letters from the set X, Y
or Z. Any additional input is captured into the
extra string buffer--up to 256 characters--and
then printed back at the user in an error
message. We take care to set default values to
null.
36More features? Wow.
Scanf() can also be conditioned to skip over
characters. For example, if you have four ints,
each separated by a semicolon, you can
use int x, y, w, h scanf (dddd,
x, y, w, h) The non-white-space characters
in the control string causes scanf() to discard
the characters. Thus, given this
Result
Text line of input
x y w h
103 45 300 75
1034530075
37Sometimes...
- ...in the halls of the CoC you will hear people
say that scanf is broken. - And it does appear that there may occasionally be
strange behaviors seen especially across certain
complex terminal I/O systems - It doesnt help that Unix, Windows and Macs all
have different ways of terminating lines!
38fgets -- an even better way
Instead of using gets() or getchar(), we can
instead use fgets(). The signature of fgets()
appears as char fgets (char s, int size,
FILE stream) The fgets() reads in
at most one less character than indicated by the
size parameter. Then, fgets() returns a pointer
to a buffer where it has stored these values. If
a new line is read, it is stored in the buffer.
The nice thing about fgets() is that it
terminates your strings with \0 for you! This
way, you can limit the amount of input youll
accept from the user (and avoid those
embarrassing buffer overflows).
39(No Transcript)
40Upclose...
Size buffer to hold the characters, and the \0
termination!
include ltstdio.hgt int main (void) char
buff11 char msg buff printf ("This
program accepts only 10 characters at a time.\n"
"Please enter some text ") msg
fgets (msg, 11, stdin) printf ("From what
you've typed, I accepted only\ns\n", msg)
return 0
As noted in the first slides, theres a stream
called standard in. Its defined as a FILE
(more on this later), but to access it you merely
use stdin
41char question21 printf (Any
questions?) scanf (20s, question)
Note the buffer sizing!
42File I/O
ANSI-C also supports file I/O. We can get a
handle on a file stream by using a FILE pointer
type FILE fp The stdio.h header defines
this type for us. We then just open a file
with fp fopen (data.txt, r) / We fail
to check return values here /
The data.txt refers to a file on disk, called
data.txt. The r means we want to read from a
text file (and not write, etc.)
43File I/O
Arsenal of file I/O related calls fopen()
-- open file fclose() -- close file fputc()
-- write char to file fgetc() -- grab
char from file fseek() -- seek to specified
byte in file fprintf() -- print to file
stream fscanf() -- scanf() for a file
stream feof() -- check if end-of-file
reached ferror() -- if error has
occurred remove() -- nuke a file
Some of the more commonly used procedures. Some
of these weve already seen.
44Opening a File
Java required a series of try/catch exceptions to
handle potential problems in reading a file. C
could care less, but its a good idea. You have
to check the FILE yourself.
FILE fp fp fopen (data.txt, r) if (NULL
fp) printf (Cannot open file.\n)
exit(1)
The parameters used to indicate the mode in
opening a file include
r open text file for reading w create
text file for writing a append to text
file rb open binary file for reading wb
create binary file for writing ab append to
binary file
r open text file for read/write w
create text file for read/write a append or
create text file for appending rb open
binary file for read/write wb create binary
file for read/write ab append or create
binary file for read/write
45Reading From a File
At the very least, we can read a character from a
file
include ltstdio.hgt int main (void) FILE fp
char c fp fopen(data.txt", "r") if
(NULL fp) printf ("Unable to open
file\n") exit(1) do
c(char)getc(fp) printf(c, c) while
(c!EOF) fclose(fp) return 0
Be sure to close a file when done reading. This
is done for you on exit(), but NOT when theres
an abort(). So, close your files when done
reading!
46fscanf and files
Weve already seen scanf(), and its flexibility
in reading keyboard input. fscanf() merely
provides the same functions for file I/O. Its
similar to fgets(), shown in the previous
slides. See how a stream, a keyboard, and disk
can all be treated as input streams?
47Questions?
48Misc C Points
There are a few loose ends 0) Default
values 1) Access to struct members 2)
Debugging tips (besides use Java instead) 3)
FYI on KR C coding style
49Default Values
Recall
Here, we define a structure for a node in a
linked list, and make a head node.
typedef struct node_tag struct
node_tag next int data node
node head
What if we want to allocate a new node?
Is that all?
head.next (node) malloc(sizeof(node))
head.next.next NULL head.next.data 0
You have to NULL terminate your own nodes!
(There is no default value for pointers, like
Javas default null value for references.)
50In Fact
In fact, dont ever trust any default values in
C you must set them yourself
typedef struct node_tag struct
node_tag next int data node
node head head.next NULL head.data 0
This is important because all of our recursion
techniques will terminate on NULL. If we dont
set the pointers to NULL, well never find the
end of the linked list!
51Access to Structs
Recall typedef struct node_tag int
data struct node_tag next node
void do_something(node curr)
(curr).next (node)malloc(sizeof(node))
((curr).next).next NULL int main
(void) node head do_something
(head)
Normally, to access members of a struct pointer,
we would have to use the operator to
dereference the pointer, and then get the field
value from the struct. This gets ugly.
Note the nesting of dereferencing operators
Is there a better way?
52The -gt operator
Recall typedef struct node_tag struct
node_tag next int data node void
do_something(node curr) curr-gtnext
(node)malloc(sizeof(node)) curr-gtnext-gtnext
NULL int main (void) node head
do_something (head)
We can instead use the -gt operator, which takes
the place of a dereference, and the . for
getting to field values.
Equivalent (curr).next curr-gtnext
53Debugging
There are debugging tools that other classes will
emphasize. For now, you can start using lint--
a tool that will examine your source code and
report potential problems. You can type lint
or lclint to invoke this tool. The output
might be a little cryptic, but it will focus your
attention on potential problems.
54373373 01d Sk00l C H4ck1nG
Trans elite old school C hacking
55K R Style Function Declaration
Normally, we see function declared and coded like
this
float get_average(int a, int b, int c)
float f (float) (abc)/3 return f
Some of the grizzled old unix hackers still use
KR style, the compilers still recognize
FYI You might see this style of coding from
time to time. It works just the same.
float get_average(a, b, c) int a, b, c
float f (float) (abc)/3 return f
56Questions?
57(No Transcript)