Output
printf is a function whose first parameter is the text
we want to print, and whose remaining parameters (if any)
are values we want to embed within the text.
We put markers, or placeholders, within the text to indicate exactly where we want the values to go, and use different types of markers to indicate what kind of data value is expected.
For example, the marker for an integer is %d, and the marker for a float is %f. The snippet below shows us embedding two floats and an int within a string of text.
int x = 1; float f = 1.1; float g = 2.5; printf("one int: %d, a float %f, another %f", x, f, g);The commonly used placeholders are
%d or %i decimal (integers) %f real numbers (in fixed point format) for use with float type %lf real numbers (in fixed point format) for use with double type %e real numbers (in scientific notation) %g real numbers (in fixed or scientific format) for use with float type %lg real numbers (in fixed or scientific format) for use with double type %c character %s a text string, e.g "blah blah blah"
There are also a variety of formatting options that can be specified in the placeholder, between the % and the key letter.
For example %4.2f specifies the float is to be padded to 4 characters total with, with 2 digits shown after the decimal point.
You can also display unicode characters, including characters from other alphabets,
math symbols, emoji-like characters, etc, if you know the unicode sequence for
the character. (Unicode tables can be found at
unicode.org/charts, or
unicode-table.com/en/.)
To display the character use either \uCCCC where the CCCC is its four-character hexadecimal code,
or \UCCCCCCCC where the CCCCCCCC is its eight-character hexadecimal code (e.g. the smiley face and
other emoticons are in codes 0001F600 through 0001F64F).
printf("\U0001F60A");
(Note: not all codes are supported on all systems.)
Input
Keyboard input is performed with scanf, which takes parameters
much like printf: the first one is a text string with a placeholder
for the type of data to be read, the second parameter is the
address of the variable to hold the value read in.
For example, to read a single integer:
int i; scanf("%d", &i); /* remember the & before the variable! */scanf returns an int, specifying how many items it succeeded in reading (0 if it can't read anything that fits the specified format). Thus if we wanted to read an unknown number of ints and print them as we go, we could use
while (scanf("%d", &i) > 0) { printf("%d\n", i); }Other input options are %s for string, %x for hexadecimal, %f for fixed-point float, %lf for fixed double, %e for exponential notation, %g will accept either fixed or exp notation floats, %lg for doubles, %c for char, %d or %i for decimal, %o for octal, %p for pointer, etc.
If you add a * between the % and the input type specifier
it means the item read is discarded instead of stored to
a variable. For example, the following reads three ints
but discards the middle one:
scanf("%d %*d %d", &i, &j);
You can (and probably should) specify the maximum number of characters to be read into the target variable, e.g. "%10s" indicates a maximum of 10 characters.
You can also extract data from patterns of input.
For example, to read and extract three ints from input of the form
(ddd) ddd-dddd you put the non-whitespace characters
that are part of the pattern to discard (i.e. the brackets and dash)
into the format string:
int i1, i2, i3;
scanf("(%3d) %3d-%4d", &i1, &i2, &i3);
Using scanf's return value to check for 'garbage' input
Since scanf returns a count of the number of values it successfully read,
we can check that return value and determine if there were unreadable values in the
user's data (e.g. they entered text when a number was expected). For example:
int x; int count = scanf("%d", &x); if (count == 0) { // means scanf did not read anything, i.e. there is non-integer data stuck in the buffer printf("That was not an integer\n"); } else { printf("You entered integer %d\n", x); }If garbage input was encountered, this means scanf was unable to read it, and the garbage input is still sitting in the input buffer. To clear it from the buffer, we can use mechanisms like scanf("%*s"); which reads/discards a "word" of input, e.g.:
int x; int count = scanf("%d", &x); if (count == 0) { // means scanf did not read anything, i.e. there is non-integer data stuck in the buffer printf("That was not an integer, discarding input\n"); scanf("%*s"); } else { printf("You entered integer %d\n", x); }
Quirks with scanf for floats and doubles:
The floating point format actually accepts two text strings: "nan" (which
it interprets as not-a-number) and "inf" (which it interprets as infinity).
If you perform a scanf("%f", &wherever), and the user types in text beginning
with an n or an i, then scanf reads the n/i and the next character before it
figures out they aren't really typing nan or inf. In such cases scanf might return 0
(indicating it didn't successfully read a value) but it also DOES clear the offending
word from the buffer.
Single-character input, capturing whitespace
You can also use getc() to read a single character,
e.g.
char c = getc();
Reading data to/from text strings (char[])
You can use sscanf and sprintf to read data to/from
character arrays. The approach is the same as scanf/printf,
but you specify the character array as a first parameter, e.g.
int i; // int to translate into text
char text[80];
sscanf(text, "%d", &i);