C Input & Output
|
Note: You need to know all but the last example (self-replicating programs) for exams.
Then the ones we will seldom if ever use. (The unsigned types are too specialized. long is usually the same as int, so it is not needed. short is too short to be of much use. float has far too little precision to be recommended for use.)
Use of printf to print Pi |
---|
% cat pi.c #include <stdio.h> /* for printf */ #include <math.h> /* required for atan */ int main( ) { double pi = 4.0*atan(1.0); printf("Pi = %20.16f\n", pi); return 0; } % cc -o pi pi.c -lm # -lm for math library % pi # now execute pi Pi = 3.1415926535897931 |
The function printf must always have an initial argument that is a string (in double quotes, the control string). This is followed by zero or more variables or expressions, whose values are printed according to the control string: Ordinary characters in the string are printed as they are, but a conversion specifier triggers the output of the next value in the list following the initial control string. Each conversion specifier begins with a percent character (%), which is not printed itself. The conversion specifier above is %20.16f, which controls the output of the value of the variable pi. The % starts the conversion specifier. Then the 20 says to use 20 or more columns for output. The .16 specifies 16 digits to the right of a decimal point, and finally the f says to print a float or a double in a fixed decimal format. The last character in the string above is a newline (\n) which must be explicitly present to skip to a new line at the end.
Here are two tables: conversion specifiers and special excape sequences:
|
|
A minimum field width and decimal precision can used to create formatted output. Left or right justification can be managed as well. Here are a few examples, where an underscore stands for a blank:
|
|
Don't worry about g and G in this course (they combine features of both f and e).
Mismatch of specifier and type in printf |
---|
% cat pi2.c #include <stdio.h> /* for printf */ #include <math.h> /* required for atan */ int main( ) { int a = 314159, b = 271828; double pi = 4.0*atan(1.0); printf("%20.16i, %i, %i\n", pi, a, b); return 0; } % cc -o pi2 pi2.c -lm # compile on linux % pi2 # run on linux 0000001413754136, 1074340347, 314159 % cc -o pi2 pi2.c -lm # compile on a Sun % pi2 # run on a Sun 0000001074340347, 1413754136, 314159 % lint -err=warn -Ncheck=%all -Nlevel=4 -Xarch=v9 pi2.c name used but not defined atan pi2.c(6) function returns value which is always ignored printf function argument ( number ) type inconsistent with format printf (arg 2) double :: (format) int pi2.c(7) .c file has no corresponding .h file /home/wagner/public_html/CS2213/lectures/pi2.c |
Notice what has happened here. We expected the variable pi to be printed incorrectly, since it had the wrong specifier, but we expected the next two variables a and b, to be printed as 314159 and 271828, repectively. We see that pi is indeed printed as garbage, but a is also printed as garbage, and b is printed as if it had a's value. Also, running on a Sun gives different garbage than running under Linux. (In this case, just the first half of the storage is used up for the first print, and the printing is out-of-synch after that.) Notice that lint running on a Sun did correctly diagnose the error.
Use of scanf |
---|
% cat age.c #include <stdio.h> int main( ) { int age; double height; printf("Please enter age in years, and height in meters ---> "); scanf("%i %lf", &age, &height); printf("Age: %i years, height: %5.2f meters\n", age, height); return 0; } % cc -o age age.c % age Please enter age in years, and height in meters ---> 23 1.68 Age: 23 years, height: 1.68 meters % age Please enter age in years, and height in meters ---> 23 1.697 Age: 23 years, height: 1.70 meters % age Please enter age in years, and height in meters ---> 23 2 Age: 23 years, height: 2.00 meters % age Please enter age in years, and height in meters ---> 23.5 2 Age: 23 years, height: 0.50 meters % age Please enter age in years, and height in meters ---> xyz 1.68 Age: -1073744696 years, height: 5.12 meters |
Notice about the above program and its runs:
scanf Conversions | ||
---|---|---|
Variable type | Conversion specifier | |
int | %i, %d | |
long int | %li, %ld | |
float | %f, %e, %E, %g, %G | |
double | %lf, %le, %lE, %lg, %lG | |
char | %c |
A common mistake arises because printf uses %f for a double, but scanf uses %lf (percent-ell-eff) for a double Another common mistake is to leave the ampersand off the variable being stored into, usually producing a segmentation error when you execute. scanf ignores whitespace characters such as a newline in its format string.
Later the section on strings will present the functions sprintf and sscanf, which print to a string and scan from a string, respectively -- very useful when needed.
Open, study and execute fahrcels.c
A formal parameter that is meant to be the address of an int is declared with an extra *, that is, int *. To access the actual value at the address of this formal parameter, you use the dereference operator: another *. So if the formal parameter is declared int * mp (pointer to m), then *mp would refer to the actual value. Instead of scanf (which is a little complicated to show here), if we were trying to get values back for the variables above, say from a function myfetch, the program would look as follows:
Addresses as parameters: fetch.c |
---|
% cat fetch.c #include <stdio.h> void myfetch(int *mp, double *xp); int main( ) { int m; /* unititialized! */ double x; /* unititialized! */ myfetch(&m, &x); printf("m = %i, x = %10.6f\n", m, x); } void myfetch(int *mp, double *xp) { *mp = 666; *xp = 2.718281828; return; } % cc -o fetch fetch.c % fetch m = 666, x = 2.718282 |