Size: 5723
Comment:
|
Size: 7408
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. {{{#!wiki note User prompts are not used often in UNIX because: 1. the ''UNIX way'' is to use command line arguments 1. it doesn't fit well into ''stdin''/''stdout'' framework (as we saw above) }}} |
|
Line 141: | Line 184: |
This is generally done when you have large volumes of stored data, or complex data or non-printable data. | This is generally done when you have large volumes of stored data, or complex data (such as structs) or non-printable data. |
Line 146: | Line 189: |
There are two standard output 'channels', standard output ''stdout'' and standard error ''stderr''. | There are two standard output 'streams', standard output ''stdout'' and standard error ''stderr''. |
Line 149: | Line 192: |
''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'': {{{#!cplusplus fprintf(stderr,"Usage: %s integer\n", argv[0]); }}} * you could argue over whether it should go to ''stderr'' (hence be just a ''printf'') * ''stderr'' is normally reserved for __serious errors__ There is convention here: |
The general form for a print statement is ''fprintf(stream, ...)'', where stream can be stdout, stderr or a user-defined file. * the call ''printf(...)'' is the same as ''fprintf(stdout, ...)'' and is default to the screen but may be re-directed * a ''fprintf(stderr, ...)'' is usually reserved for serious errors * for example, in ''countc.c'' above the 'Usage' message went to ''stderr'': {{{#!cplusplus fprintf(stderr,"Usage: %s integer\n", argv[0]); }}} * you could argue over whether 'bad' usage is a serious error (maybe just a ''printf'' would have been enough) There is 'systematic' naming here: |
Line 160: | Line 203: |
* from a string is '''s'''''scanf()'', and it has an 'extra' first argument that is a string | * if you read from a string then use '''s'''''scanf()'', where the first argument is the string |
Line 162: | Line 205: |
* to a file is '''f'''''printf()'', and it has an 'extra' first argument that is a 'channel' (file) Like ''stdin'', we can re-direct ''stdout'' to a file |
* if you write to a file then use '''f'''''printf()'', where the first argument is a stream Like ''stdin'', we can re-direct ''stdout'' to a file. |
Line 174: | Line 217: |
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 222: |
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. |
Line 186: | Line 229: |
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'' |
{{{#!wiki note 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'' }}} |
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.
User prompts are not used often in UNIX because:
the UNIX way is to use command line arguments
it doesn't fit well into stdin/stdout framework (as we saw above)
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 (such as structs) or non-printable data.
- these rarely happen in this course
Program output
There are two standard output 'streams', standard output stdout and standard error stderr.
- both are normally defined as the screen
The general form for a print statement is fprintf(stream, ...), where stream can be stdout, stderr or a user-defined file.
the call printf(...) is the same as fprintf(stdout, ...) and is default to the screen but may be re-directed
a fprintf(stderr, ...) is usually reserved for serious errors
for example, in countc.c above the 'Usage' message went to stderr:
1 fprintf(stderr,"Usage: %s integer\n", argv[0]);
you could argue over whether 'bad' usage is a serious error (maybe just a printf would have been enough)
There is 'systematic' naming here:
standard input is scanf(),
if you read from a string then use sscanf(), where the first argument is the string
standard output is printf(),
if you write to a file then use fprintf(), where the first argument is a stream
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