Input/Output
Last modified Monday, 06-Mar-2023 14:30:50 UTC.
- Input and output are not part of C but are provided by standard
library functions in stdio.h.
- Input and output are performed via streams.
- A stream is a file or a physical device (e.g., printer or
monitor) which is manipulated with a pointer to the stream.
- There is an internal C data structure, FILE, which
represents all streams and is defined in stdio.h.
A FILE is a struct, defined in stdio.h.
Stream IO uses a FILE *.
- Stream I/O is buffered.
A fixed size block is read from or written to a file via some
temporary storage area (the buffer).
This leads to efficient I/O but data written to a buffer does not
appear in a file (or device) until the buffer is flushed
(see fflush below).
Any abnormal exit of code can cause problems.
- Streams have to be opened before use, and closed after use.
- Streams may be considered to transfer either text or binary
data.
- Predefined Streams
- UNIX has 3 predefined streams (in stdio.h):
- stdin - initially associated with the keyboard
- stdout - initially associated with the screen
- stderr - initially associated with the screen
Their type is FILE *.
- Predefined streams are automatically open.
- They all use text as the method of I/O.
- stdin and stdout can be used with files, programs,
and I/O devices such as keyboard, console, etc.
stderr normally goes to the console or screen.
- The stdin and stdout streams may have their
input/output devices redirected (> < >>) or piped (|) from
the command line, or associated with other devices by the program.
This is why stderr exists, so that error messages can
continue to be displayed on the screen, even if output is
redirected to a file.
Basic stdin and stdout IO
- Character input and output
- int getchar(void) returns the next input character from the
standard input each time it is called.
getchar returns EOF (defined in stdio.h)
when end of file is encountered.
- int putchar(int c1) puts c1 onto the standard
output stream.
putchar returns EOF on error.
- FileCopy.c
- Program to copy a text file character by character
- Not all characters are printable. C provides library
functions, declared in ctype.h, which determine the
nature of a character.
- Line input and output
- char *gets(char s1[]) reads the next input line into the
character array s1, replacing the terminating \n
with \0.
It returns the address of s1[], or NULL if an
error occurs.
- Warning, beep, beep ... you are responsible for making sure
that the character array is big enough for the input.
- Achtung, achtung ... users are not reliable, and may enter
more than you expect.
- Aandag asseblief ... use fgets instead.
- int puts(char s1[]) writes out s1 and a
\n.
Returns a non-negative int, or EOF if an error
occurs.
- FileCopyByLine.c
- Program to copy a text file line by line
- Formatted output - printf.
- int printf(char control[],<arg1>,arg2>,.....);
- printf converts, formats and prints its arguments on the
standard output stream under the control of the control
argument.
- printf returns the number of characters printed, or a
negative value on error.
- The control string contains characters to be printed as is and
conversion specifications which specify how the following
arguments should be printed.
- Each conversion specification starts with a % and ends
with a conversion character.
- There must be the same number of conversion specifications as
following arguments, unless an * is used for width or precision
(see below).
- Between the % and the conversion character there may be (in
order) :
- Flags (in any order)
- - = left justification.
- + = always print with a sign (otherwise only - is
printed).
- space = if first character is not a sign, then a space
is printed instead. Only one of + or space can be
specified.
- 0 = in numeric output, specifies padding with 0.
- # = alternate output form.
- number = minimum field width. A greater width is used if
necessary, padded otherwise.
- . = Separates minimum field width from precision
- second number = maximum number of characters to be printed
from a string, or the number of decimal places for
float and double, or the minimum number
of digits for an integer.
- l = long int,
h = short int,
L = long double.
- A width or precision may be specified by *, which takes its
value from the next argument.
- The conversion characters are :
- d,i = int -> decimal
- o = int -> octal
- x,X = int -> hexidecimal
- u = int -> unsigned
- c = int -> character
- s = char[] -> character string
- e,E = double -> real scientific
- f = double -> real decimal
- g,G = double -> a combination
of f and e
- p = void * -> pointer
- n = int * -> puts number of characters
written so far into the argument, no argument is converted.
- % = no argument converted, prints a %.
- If the character after the % is not a conversion character
the behaviour is undefined.
- Formatted input - scanf.
File IO
- Opening more streams
- Files are opened via the standard function fopen which
returns a pointer to a FILE.
- FILE *fopen(char *name,char *mode)
- The available modes are :
- "r" - read. The file must exist.
- "w" - write. The file is re-created destroying
any old version.
- "a" - append. If the file exists the new data is
appended, otherwise a new file is created.
- "r+" - update (read and write)
- "w+" - update. The file is re-created.
- "a+" - update, with writes (without positioning)
being appended.
- "b" - binary mode. No conversion of newline
sequences, etc. Used in conjunction with one of the above.
- Returns NULL if an error occurs. An error code is
stored and can be retrieved with ferror.
- Characters are input from a file using :
- int fgetc(FILE *file)
- Returns the next character in the file. On end-of-file or
error EOF is returned.
- Has an equivalent macro implementation getc.
- getchar() is getc(stdin) => same values
returned.
- Characters are output to a file using :
- int fputc(char c1,FILE *file)
- Returns c1 if successful, EOF if an error
occurs.
- Has an equivalent macro implementation putc.
- putchar(c1) is putc(c1,stdout) => same
values returned.
- int fclose(FILE *file) is used to close files.
Returns EOF on error, and 0 otherwise.
- EOF is defined in stdio.h, and is returned when
an error occurs on an input operation.
End-of-file is one such (common) error, but it is better to use
feof to test whether a genuine end-of-file has been reached.
- FileCopyByName.c
- Program that copies named files
- And don't forget, stdin, stdout, and
stderr are all FILE *s, so they can be used
where ever a FILE * is expected.
- Other file output functions.
- fputs - writes a string to a file
- int fputs(char *s1,FILE *file)
- Outputs upto but not including the first \0.
- Returns non-negative if successful, EOF otherwise.
- int *puts(char *s1) outputs to stdout.
- fprintf - writes formatted output to a file.
- int fprintf(FILE *file,char *control,<arg1>,...)
- See printf for details
- Returns number of characters written, negative if an error
occurs.
- printf is fprintf(stdout,...) =>
same values returned.
- fwrite - writes data in binary mode to a file.
- size_t fwrite(void *buffer,size_t size,size_t number,FILE *file)
- Writes number items of size bytes from memory
starting at buffer, out to file.
- Returns number if successful, number written otherwise.
- Other file input functions.
- fgets - gets a line of characters from a file.
- char *fgets(char *s1,int size,FILE *file)
- Gets a maximum of size-1 characters (upto and
including a \n) and appends \0.
- Returns s1 or NULL if at end-of-file or
on error.
- char *gets(char *s1) reads from stdin.
- fscanf - reads formatted data from file
- int fscanf(FILE *file,char *control,<arg1>,...)
- See scanf for details
- Returns number of items matched if successful, EOF
otherwise.
- scanf is fscanf(stdin,...) => same values
returned.
- fread - reads data in binary mode from a file.
- size_t fread(void *buffer,size_t size,size_t number,FILE *file)
- Reads number items of size bytes into memory
starting at buffer, from file.
- Returns number if successful, number read otherwise.
- SavePeople.c
- Program that uses file output functions to save people
-
SaveRetrievePeople.c
- Program that uses file input functions to retrieve people
- File positioning functions
- ftell - returns current file position
- long ftell(FILE *file)
- Returns the current position as an offset from the
beginning of the file in bytes, or -1L on error.
- fseek - moves to a random byte in a file.
- int fseek(FILE *file,long offset,int origin)
- Moves to the byte in the file offset bytes from
origin, where origin can be :
- SEEK_SET - beginning of file (non negative offset)
- SEEK_CUR - current position in file
- SEEK_END - end of file.
- For text files, the offset must be 0, or the offset must be
a value returned by ftell and the origin
SEEK_SET.
- Returns 0 if successful, non-0 otherwise.
-
SaveRetrievePerson.c
- Program that uses file seek to retrieve one person
- rewind - resets a file to its start
- void rewind(FILE *file)
- Rewinds both input and output files.
- rewind(file) is fseek(file,0L,SEEK_SET)
- Other file handling functions.
- ungetc - puts one character into a stream
- int ungetc(int c1,FILE *file)
- Only one character (not EOF) may be pushed back onto a
stream.
- Returns c1 if successful, EOF otherwise.
- fflush - flushes output buffers to OS.
- int fflush(FILE *file)
- Returns 0 if successful, EOF otherwise.
- fflush does not flush OS to disk - use sync()
for that.
- remove - deletes a file
- int remove(char *file_name)
- Removes the file, returning non-zero if unsuccessful.
- rename - renames a file
- int rename(char *old_name,char *new_name)
- Changes the name of a file, returning non-zero if
unsuccessful.
- File error handling functions.
- feof - detects end-of-file condition
- feof(FILE *file)
- Returns non-0 on end-of-file, 0 otherwise.
- ferror - detects i/o errors
- int ferror(FILE *file)
- An error indicator is set when an error occurs for each
file, and can be retrieved by ferror.
Does not clear the error.
- Returns non-0 if an error has occured, 0 if no error since
last fopen or clearerr.
- clearerr - clears error codes.
- void clearerr(FILE *file)
- Other less common functions are
- tmpnam, mktemp for creating non-existent file names
- tmpfile, mkstemp for creating temporary files
- setvbuf and setbuf for controlling buffering
- freopen for duplicating access to already open files,
especially the std ones.
- fgetpos for recording the current file position, portable to
non-UNIX systems
- fsetpos for moving to a position recorded by
fgetpos
Miscellaneous IO
- In-memory format conversion.
- int sprintf(char string[],char control[],<arg1>,...)
puts output into string.
- int sscanf(char string[],char control[],<arg1>,...)
takes input from string.
- Using a variable number of arguments as arguments
- int vprintf(char control[],va_list arg)
- int vsprintf(char string[],char control[], va_list arg)
- These are the same as printf and sprintf, except
that the variable argument list is replaced by arg, which
has been initialised with va_start, and possible moved with
va_arg.
Exercises
- Use sprintf and sscanf to implement
void itoa(int input,char output[]) and
int atoi(char input[]), which convert from
integer to string and vice versa.
- Write
int int_print(int number_of_arguments,int format,<arg1>,...)
which prints the ints passed to it in one of decimal, octal
or hex. The number of ints to print is given in
number_of_arguments, and the format in format - one
of the characters d, D, o, O,
x, X. int_print should return the number of
ints printed, or -1 on error.
- Write a program listing program. Your program should read text
from a text file specified as a command line argument, and
output the file to stdout. #include directives should be
replaced by the contents of the file to be included, recursively.
- Write an encryption program that will encrypt any sort of
file. The program takes two command line arguments - the name
of the file to be encrypted and an encryption string. The
program encrypts the file by exclusive-ORing successive bytes
of the file with successive characters of the encryption
string, looping back to the start of the string each time all
the characters in the encryption string have been used up.
This encryption technique is convenient as it is self
cancelling.
- Write a program to copy one named file into another named file.
The two file names are given as the first two arguments to the program.
Copy the file a block (512 bytes) at a time.
- Write a program that prints the last n lines of a text file.
The file name must be specified on the command line.
By default is 5, but the program must allow an optional argument so that
n can be set to another value, so that
prompt> last -n file.txt
prints out the last n lines, where n is any integer.
- Write a program to compare two files and print out the lines where they
differ.
- Write a program to print the lines of a file which contain a
word given as the program argument (a simple version of grep
UNIX utility).
- Write a program to list the files given as arguments, stopping
every 20 lines until a key is hit (a simple version of more
UNIX utility).
Exam Style Questions
- Any of the short exercises.
- What are the three predefined IO streams in UNIX, and what devices are
they associated with by default?
- Why should fgets be used in preference to gets?
- What is the exact output from the following code? Indicate spaces
with an upsidedown triangle.
int i1 = 27;
float f1 = 13.13;
float f2 = -45.45;
char data[] = "Bonzai!";
printf("%3d %7.3f %-10s %f %o\n",i1,f1,data,f2,i1);
- What are the values of the variables after the following code is executed
with input 56789 1234 45a72?
int i1;
float f1;
char name[50];
scanf("%2d %f %*d %2s",&i1,&f1,name);