Class 3 - Input - Output, Buffering, Utilities
Class 3 - Input - Output, Buffering, Utilities
Utilities
In this class we will complete a C introduction by more detailed covering of input and output,
buffering, and miscellaneous utilities.
Example 3.1. Write a program that takes the file's name as a parameter and displays its
contents to standard output (screen).
#include <stdio.h>
Comments:
1
Which below will NOT cause a problem when running this program?
Answer: Running the program with more than one argument will not cause a problem provided
the first argument is correct.
Example 3.2. Write a program that takes multiple file names from the command line,
concatenates their contents and writes it out into standard output.
#include <stdio.h>
Comments:
2
● Exceptions are handled by aborting the program with non-zero status
○ Note different return codes for incorrect number of arguments and failure to open
a file
● Both argc and argv are local variables for main and hence can be modified by the
program
● fclose closes the file pointer that is no longer needed, and releases this resource from
memory
● Operator --argc results in the counter argc decremented first, then being compared to
0
○ Note: the while loop results in (argc - 1) iterations
Answer: first option -- argv is a pointer to an element in an array. *argv dereferences it and
hence is an array's element, which itself is a pointer to the first element of a string. Note that
char ** argv is equivalent to char * argv[]. The former is passed to a function and hence
can be modified making the third option correct.
3.2 Buffering
The goal of buffering provided by the standard I/O library is to use the minimum number of read
and write calls. The library tries to do its buffering automatically for each I/O stream. Three types
of buffering are provided.
● Fully buffered
○ Actual I/O takes place when the standard I/O buffer is filled. The buffer is usually
obtained when the FILE pointer is allocated
○ The term flush describes the writing of a buffer.
● Line buffered
○ I/O is performed when a newline character is encountered on input or output. It is
typically used on a stream related to a terminal, such as standard input and
output.
● Unbuffered
3
○ The library does not buffer the characters.
○ For example, the standard error stream is usually unbuffered to display error
messages as quickly as possible.
In the next example we observe how buffering mode can be set and affect performance.
Example 3.3. Observe how changing the buffer size affects performance.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
if (argc != 3) {
printf("Usage a.out <file-path> <buffer-multiplier>\n");
return 1;
}
fp = fopen(argv[1], "w+");
if (fp == NULL) {
printf("Cannot open the file");
return 2;
}
4
printf("Written and read %d lines in %d ticks\n", count, clock() - start);
fclose(fp);
return 0;
}
Comments:
● The program creates and reads a file containing a predefined number of lines
○ The resulting file's size is ~ 5 MB
● It accepts the file's path and the standard buffer's size multiplier
○ Note the atoi function converting a string to an integer
● It uses setbuf function to override the standard buffer size of BUFSIZ
● The buffer is flushed at the write and read blocks
○ Note the use of fflush function
● Total file operations time is measures in clock ticks using the clock function
The following table shows file operations performance when changing the buffer size.
1 7028
2 6383
3 6209
4 6721
5 6982
10 6726
100 6063
As we can see performance improves initially, but then becomes less consistent. (Note: the
standard buffer size is 8K in these experiments)
What is the most likely reason for inconsistent performance improvements as the multiplier
increases?
5
Answer: as the buffer size increases a single operation to read/write from a disk to fill/release
the buffer becomes larger in size. This may be more likely to interfere with other processes on a
machine and become slower. Fewer read/write operations in theory should improve
performance. The second and fourth options are factually incorrect.
Answer: only the first fflush is necessary to ensure that all data is written to the file. The read
operation will flush the data automatically.
3.3 Utilities
The standard library provides a wide variety of functions. We demonstrate a few of those by
examples.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_NAME 50
int main() {
char input[MAX_NAME];
char output[MAX_NAME];
char * p;
6
/* Remove newline */
p = strchr(input, '\n');
* p = '\0';
Comments:
Exercise 3.1. Improve this program by verifying that the input string is a name in the right format.
(Hint: utilize isalpha and other functions as needed.)
Example 3.5. Calculate future value of an initial investment that is reinvested each year into a
1-year CD.
The key here is a 1-year CD rate which is unknown in the future. For example, assume you
want to invest $100 for 2 years in one year:
Below is an implementation:
7
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define LOWER_RATE 2
#define UPPER_RATE 10
int main() {
float amount;
unsigned int years;
printf("Enter amount, years: ");
scanf("%f", & amount);
scanf("%u", & years);
printf("FV=$%.2f for amount=$%.2f, years=%d\n", fv_one_path(amount, years),
amount, years);
return 0;
}
Comments:
8
● 3
● 2
● 1
● 0
Answer: 2. It first generates a random integer between 2 and 7, then divides it by 100 resulting
in numbers 0. 02, 0. 03, ...
Exercise 3.2. Modify the above program to compute an average future value over a given
number of paths.