Contents
C I/O
Program input
There are 3 main sources of input for programs:
- from the command line
you get access to data on the command line by using argc and argv[][]
from standard input (also called stdin)
stdin can be the keyboard, a data file, or the output of another program
- from an 'internally-defined' file
open a file, use fscanf(), and don't forget to close the file
1. command line
To read from the command line:
include argc and argv in your parameter list for main().
use sscanf() to read the arguments (it stands for 'string scanf()')
the first argument of a sscanf() is a string
Here is a program that counts from 1 to num, where num is provided by the user on the command line
1 // countc.c
2 // reads an integer from the command line and counts
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 int main(int argc, char *argv[]) {
7 int num = 0;
8 if (argc < 2 || sscanf(argv[1], "%d", &num) != 1) { // num is defined here
9 fprintf(stderr,"Usage: %s integer\n", argv[0]);
10 return EXIT_FAILURE;
11 }
12 for (int i=1; i<=num; i++) {
13 printf("%d ", i);
14 }
15 printf("\n");
16 return EXIT_SUCCESS;
17 }
Notice the program prints a 'Usage' message if an integer argument is missing (discussed in next session)
To execute the program:
prompt$ dcc -o countc countc.c prompt$ ./count Usage: ./countc integer prompt$ ./countc !t#q Usage: ./countc integer prompt$ ./countc 10 1 2 3 4 5 6 7 8 9 10
2. standard input
To read from standard input (usually called simply stdin)
a scanf() is used (instead of sscanf())
a scanf() misses the string argument of a sscanf()
so where does num comes from?
... the default 'channel' stdin
1 //counts.c
2 // reads an integer from stdin and counts
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 int main(void) {
7 int num;
8 if (scanf("%d", &num) != 1) {
9 fprintf(stderr, "Usage: a number expected\n");
10 return EXIT_FAILURE;
11 }
12 // the rest of the program is exactly the same as the command-line version
13 for (int i=1; i<=num; i++) {
14 printf("%d ",i);
15 }
16 printf("\n");
17 return EXIT_SUCCESS;
18 }
Notice the Usage message this time is simpler than the command-line version above
... because we did not declare argc and argv, and so cannot use argv[0] this time!!
- we could have if we wanted to of course
There are many ways to 'test' a program that reads stdin.
- Using the keyboard
prompt$ dcc -o counts counts.c prompt$ ./counts 10 1 2 3 4 5 6 7 8 9 10
where the integer 10 was typed on the keyboard by the user, and the program generates the count from 1 to 10.
Using a data file, input.txt say, which contains the integer 10 (followed by a newline).
prompt$ more input.txt 10 prompt$ ./counts < input.txt 1 2 3 4 5 6 7 8 9 10
Using a pipe command. A pipe command joins the stdout of a program to the stdin of another program. If we have a program called write10.c:
then we can pipe its stdout to the stdin of our counting program
prompt$ dcc -o write10 write10.c prompt$ dcc -o counts counts.c prompt$ ./write10 | ./counts 1 2 3 4 5 6 7 8 9 10
But you can actually generate a string much more easily in UNIX using echo
prompt$ echo "10" | ./counts 1 2 3 4 5 6 7 8 9 10
==== User prompting ====Using stdin usually means you do not have a user prompt.
3. A file
A program can open and close, and read from, and write to, a file that is 'internally' defined.
This is generally done when you have large volumes of stored data, or complex data or non-printable data.
- these rarely happen in this course
Program output
There are two standard output 'channels', standard output stdout and standard error stderr.
- both are normally defined as the screen
printf() writes to stdout, hence the screen
fprintf(), which stands for file-printf, writes to a file, which could be stderr
for example, in countc.c the 'Usage' message went to stderr:
1 fprintf(stderr,"Usage: %s integer\n", argv[0]);
you could argue over whether it should go to stderr (maybe just a printf would have been enough)
stderr is normally reserved for serious errors
There is convention here:
standard input is scanf(),
from a string is sscanf(), and it has an 'extra' first argument that is a string
standard output is printf(),
to a file is fprintf(), and it has an 'extra' first argument that is a 'channel' (file)
Like stdin, we can re-direct stdout to a file. For example:
dcc -o counts counts.c ./counts > output.txt 10
(where the integer 10 is input by the user) will result in the count from 1 to 10 going to the file output.txt
If you create a data file input.txt that contains the string 10, then the following will generate the same output text file.
./counts < input.txt > output.txt
As we saw before, you can let echo generate data and use that in a pipe. This also generates the same output text file.
echo "10" | ./counts > output.txt
Input/output design considerations
The vast majority of program can be written just using these i/o system calls
- scanf() to read from stdin - sscanf() to read from the command line - printf() to write to stdout - fprintf() to write to stderr