Size: 5723
Comment:
|
Size: 7034
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 51: | Line 51: |
Usage: ./count integer prompt$ ./count !t#q Usage: ./count integer prompt$ ./count 10 |
Usage: ./countc integer prompt$ ./countc !t#q Usage: ./countc integer prompt$ ./countc 10 |
Line 136: | Line 136: |
==== User prompting ==== You can still use a 'user prompt' when you use ''stdin'' but it messes up the output. {{{#!cplusplus // counts+.c // reads an integer from stdin and counts // prompts the user #include <stdio.h> #include <stdlib.h> int main(void) { int num; printf("Please input a number: "); // this line added to counts.c if (scanf("%d", &num) != 1) { fprintf(stderr, "Usage: a number expected\n"); return EXIT_FAILURE; } for (int i=1; i<=num; i++) { printf("%d ",i); } printf("\n"); return EXIT_SUCCESS; } }}} results in {{{ prompt$ ./counts+ Please input a number: 10 1 2 3 4 5 6 7 8 9 10 }}} where the program prints the user prompt, the user types in ''10'', and the program then outputs the count to ''10''. Great. If you instead use a pipe as input, then you do not see what the input is {{{ prompt$ echo "10" | ./counts+ Please input a number: 1 2 3 4 5 6 7 8 9 10 }}} You see here that the ''10'' generated by the ''echo'' does not appear on the screen: you just see the output of the program. |
|
Line 151: | Line 188: |
''fprintf()'', which stands for ''file-printf'', writes to a file, which could be ''stderr' | ''fprintf()'', which stands for ''file-printf'', writes to a file, which could be ''stderr'' |
Line 156: | Line 193: |
* you could argue over whether it should go to ''stderr'' (hence be just a ''printf'') | * you could argue over whether it should go to ''stderr'' (maybe just a ''printf'' would have been enough) |
Line 164: | Line 201: |
Like ''stdin'', we can re-direct ''stdout'' to a file | Like ''stdin'', we can re-direct ''stdout'' to a file. |
Line 174: | Line 211: |
The following does the same thing: | If you create a data file ''input.txt'' that contains the string ''10'', then the following will generate the same output text file. |
Line 179: | Line 216: |
This also does the same thing: | As we saw before, you can let ''echo'' generate data and use that in a pipe. This also generates the same output text file. |
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
You can still use a 'user prompt' when you use stdin but it messes up the output.
1 // counts+.c
2 // reads an integer from stdin and counts
3 // prompts the user
4 #include <stdio.h>
5 #include <stdlib.h>
6
7 int main(void) {
8 int num;
9 printf("Please input a number: "); // this line added to counts.c
10 if (scanf("%d", &num) != 1) {
11 fprintf(stderr, "Usage: a number expected\n");
12 return EXIT_FAILURE;
13 }
14 for (int i=1; i<=num; i++) {
15 printf("%d ",i);
16 }
17 printf("\n");
18 return EXIT_SUCCESS;
19 }
results in
prompt$ ./counts+ Please input a number: 10 1 2 3 4 5 6 7 8 9 10
where the program prints the user prompt, the user types in 10, and the program then outputs the count to 10. Great.
If you instead use a pipe as input, then you do not see what the input is
prompt$ echo "10" | ./counts+ Please input a number: 1 2 3 4 5 6 7 8 9 10
You see here that the 10 generated by the echo does not appear on the screen: you just see the output of the program.
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