Input and Output

Input and output in C can be done through streams. A stream can be thought of as a continuous sequence of characters coming into or out of the computer. For instance, when you enter a number into one of your programs, say, 12.34, the stream of characters '1', '2', '.', '3', '4', '\n' is read in by the scanf function and assembled into a float or double for your program to compute with. Input streams may be read from; output streams may be written to.

Standard Input and Standard Output

Two important streams are standard input and standard output. They are represented in C programs by the names stdin and stdout, respectively. Some functions automatically use one of these streams, for instance printf and scanf.

Redirection

In most operating systems, standard input is usually the keyboard and standard output is the text display. Input functions like scanf use standard input, while output functions like printf use standard output. Both of these streams can be redirected, i.e., they can be made to use different objects than the keyboard and screen. At the command prompt, redirection of standard input to a file is done using the < sign and redirection of standard output to a file is done using the > sign. For instance, suppose your program is called foo and it accepts some input and prints some output. Normally, you would just invoke it by typing:
	foo
at the command prompt. Input would be taken from the keyboard and output printed to the screen. However, suppose you want foo to accept input from a file called bar instead of from the keyboard. Then you would type
	foo < bar
Suppose you want input from the keyboard but output to a file called baz. Then you would type
	foo > baz
Maybe you want both input and output redirected. Then you could type:
	foo < bar > baz
Redirection is typically done when a great deal of information needs to be processed by a program, more than the user is willing to type or read from the screen. It can also be used to record the output of a program to a file for later inpection. There are other kinds of redirection we will discuss later...

Some Stream Functions

getchar and putchar

Streams are simply continuous sequences of characters. They can be used at the lowest level with functions that simply get or put a character from a stream. Two functions for doing this with standard input and standard output are getchar and putchar, respectively. (Extra information you didn't want to know: getchar and putchar aren't really functions; they are preprocessor macros, but the distinction is irrelevant at this point.) putchar prints a single character to the standard output. For example, the following program prints the letter 'h' on the standard output:
#include <stdio.h>

int main () {

	/* print 'h' on stdout */

	putchar ('h');
	return 0;
}
getchar reads a single character from the standard input, returning the character read. For example, this program reads a single character from the standard input into a character variable:
#include <stdio.h>

int main () {
	char	c;

	/* read a char from stdin into c */

	c = getchar ();
	return 0;
}
These functions are sometimes useful, as we will see later, but their smarter cousins scanf and printf provide more functionality. (Theoretically, you could write all your programs with getchar and putchar, but it would be quite tedious writing code to do numeric conversions that scanf and printf do automatically.)

scanf and printf

We have already seen several instances of printf and scanf. These functions (and their friends, fprintf, fscanf, sprintf, and sscanf) are the workhorses of C input and output. They handle all kinds of formatted input and output.

The format of a printf statement is this:
printf (format-string,expr1, expr2,...);
The format-string is a character string constant describing how the output will look. It can be as simple as "Hello, World!\n" or can have embedded tokens giving the format with which to print the expressions that are the arguments expr1, expr2 etc. For example,
	printf ("An order of %i items will cost $%0.2f.\n", num_items, cost);
where num_items is an int and cost is a float. It will print out something like
An order of 20 items will cost $12.34.
depending on the values of the variables. The %i token means that the first argument after the format string is an int. The %0.2f token says that the second argument is a float, and to print two significant digits past the decimal point. Your book has a table of printf and scanf format specifiers in Table 2.6 on page 52.

Expressions can also be used in printf statements, for example:
	printf ("An order of %i items will cost $%0.2f.\n", 
		num_items, cost_per_item * num_items);
where cost_per_item is a float. The multiplication expression will be evaluated and the result passed as an argument to printf. You can use as many of these tokens as you like in a single statement; just make sure the tokens match up with order and number of arguments given.

The following table gives a partial description of printf tokens with examples:
Token	Meaning			Examples  Comments
%f	print floating point	"%f" 	  unformatted float
				"%0.3f"   print 3 digits after decimal
				"%6.2f"   6 chars total, 2 after decimal
%i	print int, decimal	"%i" 	  unformatted int
				"%5i" 	  5 digits, with leading spaces
				"%0.5i"   5 digits with leading 0s.
%d	same as %i
%x	print int, hexadecimal	"%x"
%c	print character		"%c"	
%li	print long 		"%li"	  use for variables of type long
%s	print string		"%s"	  print a string
				"%10s"	  10 chars of a string, leading spaces
%%	print percent sign	"%%"


The format of a scanf statement is similar:
scanf (format-string, & var1, & var2,...);
var1, var2, etc. are the variables to be read in. Note that now the arguments must be variables. (You can't easily read into an expression unless it is something special called an lvalue; more about this later.) Note also that the variables names are preceded by the ampersand (&). Arguments in C are passed by value, that is, the value of an argument is what the function sees, not the argument itself. To allow scanf to modify the variables, we must tell it the location in memory of the argument; the & operator does this. If you like, you may think of it as a magic incantation you must invoke to keep the demons of "Segmentation fault (core dumped)" away. Later we will see how to use & to help us write our own functions.

Analogous to printf, the format-string describes how the input should look. For example:
	scanf ("%d %f", &a, &x);
will read a decimal integer into the int variable a and a floating point value into the float variable x. There is a complication with scanf that doesn't show up with printf; remember how all arithmetic in C is done as double? Well, with printf, "%f" just means print out a double; any floating point value that's an argument to printf, even a single float variable by itself, will first be converted to double before being passed to printf. The same is not true with scanf, since all we are passing are memory locations (pointers). Thus, we must specify whether a float variable is long (double) or not (float). We do this for doubles by preceding the 'f' by an 'l', i.e., "%lf", for "long float." So, if a variable d is declared as double, we read it in with
	scanf ("%lf", &d);
Here are some tokens you can use with scanf. You can also use format specifiers as with printf, but usually you want the input format to be as loose as possible so a mistake in the input won't hurt your program.
Token	Meaning			Examples  Comments
%f	read floating point	"%f" 	  unformatted float
%lf	read double		"%lf"	  unformatted double
%i	read int, decimal	"%i" 	  unformatted int
%li	read long, decimal	"%li" 	  unformatted int
%d	same as %i
%x	read int, hexadecimal	"%x"
%c	read character		"%c"	
%s	read string		"%s"	  read a string (not until later)
scanf returns an integer value telling how many items were actually read successfully. You can check this value to see if it equals the number of variables you're reading; if not, an error has happened (e.g. some joker typed "hello" instead of an integer, or the end of file was reached).

Sometimes you have to do something called "flushing the input stream." This means reading characters from a stream until the next carriage return is found. This is useful if you want to read past extraneous characters, like carriage returns and ending spaces, that the user has typed in. The stream will be "flushed" to the next line, and all keystrokes (characters) received before that line will be ignored. Flushing the input stream looks like this:
	while (getchar () != '\n');
The while statement continues to execute until the condition within parentheses is false, so this code will continue to read characters one at a time from standard input until a carriage return is found. At this point, the next thing in the stream will be the first thing on the next line. Note that "flushing the stream" is not quite standard terminology and many C programs you will see will deal with this situation in different ways or not at all.

Other Streams

Later on we will see how to make our own streams. We can open files not on the standard input or output or even open other devices such as a printer, mouse, or tape drive. Once we have these stream variables, we can print to them with fprintf and read from them with fscanf. There are also many other functions for dealing with generic streams.

C defines another output stream called standard error, or stderr. It usually also goes to the text display, along with standard output. You can write to standard error using the fprintf function, e.g.
	fprintf (stderr, "The value of the variable is %i.\n", a);
The format string is the second argument to fprintf; the first is the name of the stream, stderr in this case. Standard error is usually used to write error messages to. It is not redirected even when standard output is, so you can have standard output go to a file but standard error still go to the screen. It is useful in debugging your programs; if you periodically write out the values of certain variables to standard error, you can keep track of what your program is doing and where it might be going wrong. Most programs like cc write their error messages to standard error; this is why, even if you type
	cc -o foo foo.c > stuff
you will still see the error messages on the screen; they are on standard error while only standard output is redirected to stuff. To redirect both standard error and standard output from the C-Shell (most of you are running the C-Shell for your prompt), use >& instead of just >. For example, to put a list of the error messages you get when compiling foo.c into a file called stuff, do this:
	cc -o foo foo.c >& stuff
You can also use fprintf to print to other streams. For example,
	fprintf (stdout, "something...", ...);
is equivalent to
	printf ("something...", ...);
When we learn how to open our own streams, this (and fscanf) will become more important.

Extra for Experts

You're not responsible for this stuff on a test, it's just nice to know... Here's even more on redirection at the command prompt. Suppose you want to send standard error and standard output from your program foo to a file bar. No problem, you just run your program like this:
	foo >& bar
But what if you want standard error to go to one file, say, baz, while standard input still goes to bar? Many people will tell you this is impossible in C-Shell. Indeed, one of the faults of C-Shell is that it doesn't directly provide this functionality. However, you can work around this "feature" with something like this:
	( foo > bar ) >& baz
The parentheses start a sub-shell that runs foo, sending the standard output to bar. The standard error, which is the only output that escapes the sub-shell, is redirected from there to baz.

Suppose you are using a shell other than C-Shell, such as the Bourne Shell, or Korn Shell. How do you redirect standard error? Use 2>. For example, the following:
	foo > bar 2> bar
does the same thing as the first example above, and this:
	foo > bar 2> baz
does the same thing as the second example.

Linux is a multitasking operating system. This means that more than one process can run at a time. Processes can communicate with each other via things called pipes. You can use this from the shell to allow your program to communicate with other programs. The standard output of one program becomes the standard input of another program. For example, the standard program more accepts input from the standard input and pages it to the screen. This means it prints it one screenful at a time, waiting for you to press the space bar until the next screenful is printed. If your program has a lot of output, you can page it by piping the output through more:
	foo | more
The | symbol acts like the >, except the target is another running program, not a file. In C-Shell, you can also pipe standard error in a way similar to redirecting it to a file. Suppose you want to see all your compiler errors one screenful at a time. Just enter:
	cc -o foo foo.c |& more
This pipes all the C compiler errors generated when compiling foo.c through more.

Let's have some more fun with this. The standard program ls lists the files in your directory; when called with the -l option, it will give a long listing that includes the size in bytes of each file in the fifth field. The program sort sorts lines from the standard input; with the +4 -rn option, it sort them by the fifth field (it starts counting at 0, so field #4 is the fifth field) in reverse numeric order. So the following:
	ls -l | sort +4 -rn
will give you a listing of all your files, sorted in decreasing order of their sizes. If you have lots of files, just do this:
	ls -l | sort +4 -rn | more
The files are listed, sorted, then the output is piped through more so you can easily page through the listing.