Input and Output

(read chapter 5.)

Using printf()

printf can take different numbers and types of parameters. E.g.:

  printf("%c %d %lf\n", 'a', 1, 3.7);

format control

A format string or format control sequence is a special character sequence starting with % that specifies how some value should be printed.

General form:

"%<flag><field><.precision><size prefix><conversion character>"

only % and <conversion character> are required.

Conversion characters (<conversion character>) specify what type of value is being printed. The following table from the book (p. 111) shows the type of value specified by the character. We've seen the d, c and lf characters.

Conversion Characters
character type of value being printed
d, i, u integer
o octal integer
x, X hexadecimal integer
f floats and doubles
e, E exponential notation
g, G shortest of f, e, E
c character
s string
p void *
n int *
% %

The flag (<flag>) specifies whether the value printed should be left justified, if the sign for non-negative numbers should be printed, etc. The following table is from p. 111 of the text.

Flags
flag meaning
- left justify
+ print sign for non-negative numbers
<space> print a blank before positive values
# indicate hexadecimal and float numbers
0 use 0's instead of leading spaces

The field size (<field>) is an integer specifying the minimum number of characters to be printed. E.g.:

  printf("start %5d end", 2);
prints:
start     2 end
(5 characters, right justified)

Example:

  printf("start %-5d end", 2);
prints:
start 2     end
(5 characters, left justified)

Ther precision field (<.precision>) is an integer specifying the precision of printing:

The <size prefix> can be any of:

size prefix meaning
h short
l long
L long double

Example:

  printf("%5.2lf\n", 3.14159);

prints:

 3.14

It is better to use %lf than %f for printing doubles, because some input/output functions require it.

Escape characters are used to print characters that have a special meaning in C.

escape character prints
%% %
\" "
\' '
\\ \
\n newline
\t tab

E.g. to print a \:

  printf("\\");

E.g. to test if variable ch contains a ':

  ch =='\''

Return to Table of Contents

Using scanf()

scanf() can read multiple values in one call:

  scanf("%d %lf", &i, &d);

reads an int, then a double.

Quiz: Why are the last two parameters passed by address?

Blanks in the format control string tell scanf() to skip over whitespace in the input. Whitespace is any sequence of tab, blank and newline characters. In the above call to scanf(), the int and double can be separated by whitespace. So, this scanf() will read an int and a double even if the user of the program types arbitrary spaces, tabs, and newlines between the numbers.

Format control uses the same conversion characters and size prefixes as printf(). However, scanf() is picker than printf() because the programmer must use "%lf" when reading a double.

Other input and output functions (from <stdio.h>):

  int putchar(int ch);
writes a single character to the screen.

  int getchar(void);
  int puts(char *str);
writes a string (sequence of characters) to the screen.

  char *gets(char *str);
reads a string from the keyboard (up to a \n character).

Type char * is the type of strings. A variable str of type string of length at most n - 1 is declared as follows:

  char str[n];

The last character in a string is always '\0' - the string termination character. Example:

  char str[81]; /* declares a string 
                   variable called str
                   of length at most 80 */

  gets(str); /* reads a string from the
                keyboard and puts it into
                str */

  /* prints the string str to the screen */
  puts(str);
  puts("\n");

See ~taw2/pub/stringtest.c.

scanf() can also be used to read strings:

  scanf("%s", str);
Note that strings are an address type.

scanf() only reads up to the first space, tab or newline character in the input from the keyboard, while gets() reads up to the first newline. If the string read is longer than the size of the string variable used, your program will probably crash.

Return to Table of Contents

Text Files

C programs can read from and write to text files. File pointers are used to refer to files:

  FILE *fptr; /* declares fptr to be
                 a file pointer */

The function fopen() associates a file pointer with a text file. This must be done before the file pointer is used:

   fptr = fopen("input.txt", "r");

This makes fptr refer to the file input.txt in the current working directory, and says that the pointer can only be used to read from the file.

The prototype of fopen() is:

FILE *fopen(char *filename, char *mode); 

The filename can be an absolute path. The mode specifies how the pointer can be used to access the file:

mode access
"r" read only
  • can't be used to write to the file
  • the file must exist
"w" write only
  • create the file if it doesn't exist
  • delete the file's contents if it does exist
"a" append
  • add to the end of the file
  • doesn't delete contents if the file exists
  • creates the file if it doesn't exist
"r+" read and write access
  • the file must exist
  • contents are not erased
"w+" read and write access
  • contents erased if the file exists
  • file created if it doesn't exist
"a+" append and read access - just like append, except that the pointer can also be used to read from the file

If a file can't be opened (i.e. if the program tries to open a file that doesn't exist for read access), fopen() will return the special pointer NULL (a constant declared in <stdio.h>). Always check for this:

#include <stdio.h>

  char fname[41];
  FILE *fptr = NULL;

  while (fptr == NULL) {
    printf("Enter a filename: ");
    scanf("%s", fname);
    /* strings are an address type */
    fptr = fopen(fname, "r");
  }

When a program is finished using a file, it should be closed using the fclose() function.

Prototype:

  int fclose(FILE *fptr);

Example:

  fclose(fptr);
where fptr is the same file pointer that was used in the call to fopen().

Return to Table of Contents

Reading and Writing Text Files

The functions fprintf() and fscanf are used to write to and read from text files.

Note that a file must be open (from using fopen()) before it can be read or written, because these functions need the file pointer.

Just as for scanf(), spaces can be used in the format string for fscanf() to tell fscanf() to skip over whitespace in the file.

Example: the following call to fscanf() reads two integers from a file. The integers can be preceded, separated and followed by any amount of whitespace.

  int i, j;
  FILE *fptr;
  
  /* fptr is opened here */

  fscanf(fptr, " %d %d ", &i, &j);

Example: summing 10 integers from the text file input.txt in the current working directory:

#include <stdio.h>

FILE *openfile(void);

main () {
  
  FILE *fptr;
  int i, num, sum = 0;

  fptr = openfile();

  for (i = 1; i <= 10; i++) {
    fscanf(fptr, " %d ", &num);
    sum += num;
  }
  fclose(fptr); 
  /* don't forget this */
  printf("The sum is %d.\n", sum);
}  

FILE *openfile(void) {
 /* prompt for a filename
    open the file for read access
    repeat until successful open
 */

  char fname[41];
  FILE *fptr = NULL;

  while (fptr == NULL) {
    printf("Enter a filename: ");
    scanf(" %s ", fname);
    fptr = fopen(fname, "r");
  }
  return (fptr);
}

Note that there is no error recovery in case the file contains less than 10 integers.

Return to Table of Contents

Standard Files

In UNIX, keyboard input and screen output are treated as files. The standard input file (input from the keyboard) is called stdin, and the standard output file (to the screen) is called stdout.

Example:

  int i;
  FILE *infile, *outfile;

  infile = stdin;
  outfile = stdout;

  /* the following 3 statements are equivalent */
  scanf("%d", &i);
  fscanf(stdin, "%d", &i);
  fscanf(infile, "%d", &i);

  /* the following 3 statements are equivalent */
  printf("%d", i);
  fprintf(stdout, "%d", i);
  fprintf(outfile, "%d", i);

There is also a standard file called stderr, which is usually associated with the screen. Often, C programs written for UNIX write error messages to this file, not stdout.

Example: redirection (>) in UNIX associates stdout with a file rather than the screen. Executing:

gcc myprog.c > comperrs
will not put error messages from the compiler into comperrs, because gcc writes errors to stderr, not stdout.

The operator >& associates stderr with a file. Executing:

gcc myprog.c >& comperrs
will write error messages from the compiler into file comperrs.

Return to Table of Contents

File Processing

The function feof() is useful for checking when the end of a file has been reached. Prototype:

  int feof(FILE *fptr);

If the end of file associated with fptr has been reached, the call:

  feof(fptr);
returns a nonzero value. Otherwise, it returns 0. This is useful for processing an entire input file.

If a call to fscanf() reaches the end of a file without finding anything but whitespace, fscanf() returns a special constant EOF (defined in stdio.h). This is useful for handling files that contain nothing but whitespace and files that end in whitespace.

Example: ~taw2/pub/fileadd.c.

The format of a file must be known in advance in order to write a program that reads the file.

while loops of the following form handle empty files and files with trailing whitespace correctly:

  int notEOF = !EOF;
  FILE *fptr;

  /* open file with fptr */

  while ((!feof(fptr)) && (notEOF != EOF)) {
    notEOF = fscanf(fptr, ...);
    if (notEOF != EOF) {
      /* process data item */
    }
  }

A do while loop is difficult to use safely with files.

Return to Table of Contents

UNIX Input and Output

redirection

Pipes

| (vertical bar) associates the output of one program with the input of another.

Examples:

prog1 | more
lets the user look at the output of the executable prog1 one page at a time. stdout from prog1 becomes stdin for more.

ls -l | more
lets the user look at a long listing of the current working directory a page at a time.

cat in.dat | myprog
is equivalent to:
myprog < in.dat

cat atextfile | grep foo | wc
will give the number of occurrences of foo in file atextfile.

Return to Table of Contents