The printf function
The printf function is designed to change the contents of a string with values inserted at specific points in the string.
This is known as the format string
printf(string, exp1, exp2, ...)
The format string contains standard characters as well as conversion specifications, which begin with %.
The conversion specification is a placeholder that is filled when printing.
The
%character specifies how the value is converted from the internal from (binary) to the printed form (character).The conversion specification
%dis used to convert anintfrom binary to a string of decimal digits .%fdoes the same for afloatvalue.
C compilers are not required to check the number of conversion specifications with the number of output types.
If there are more output items, they will print a random value.
If there are more conversion specifications, it will likely not print the values
Compilers are also not required to check if the conversion spec matches the the output type. The wrong type will print a random value.
Conversion specifications
Conversion specifications have the form %m.pX or %-m.pX , where m and p are integers and X is a letter.
mis the minimum field width, specifies the minimum number of characters to print.If there are less values than
m, the value will be right justified with the remaining being spaces on the left.- e.g.
%4dwill display the number 123 as123.
- e.g.
If the value is greater than
m, the value will expand to display all the digits.- e.g.
%4will display the number 12345 as12345
- e.g.
Putting a minus sign before
mwill left justify.- e.g
-%4will display the number 123 as123
- e.g
pis the precision, which depends on the conversion specifier (X). The most common specifiers:ddisplays the integer as a decimal (base 10).pis the number of digits to display, adding extra zeros to the beginning of the number.- The default is
pis 1 (%d = %.1d)
- The default is
edisplays a floating-point number in an exponential format (scientific notification).pshows the number of digits that appear after the decimal point.- The default is 6.
fdisplays a floating-point number in a “fixed-decimal” format, without an exponent.pmeans the same for theespecifier.
gdisplays a floating-point number as either an exponent or a decimal format depending on the number’s size.pindicates the maximum number of significant digits, not digits after the decimal point.Will also not display trailing zeros like
fIf there are no digits after the decimal, it won’t show the decimal point.
gis very helpful when displaying number when you don’t know the length of the numbers beforehand or very in size.
Using printf to format numbers
/* Prints int and float values in various formats*/
#include <stdio.h>
int main(void)
{
int i;
float x;
i = 40;
x = 839.21f;
printf("|%d|%5d|%-5d|%5.3d|\n", i, i, i, i);
printf("|%10.3f|%10.3e|%-10g|\n", x, x, x);
return(0);
}|40| 40|40 | 040|
| 839.210| 8.392e+02|839.21 |
%10.3f, displaysxin a fixed format using 10 characters, 3 before the decimial, 3 after, and one for the actual decimal point.- That means
p = 3in this example takes up 7 characters, 3 before, 3 after, and the decimal.
- That means
Escape sequences
Here’s a few of the common escape sequences used in format strings:
Alert (bell) -
\aBackspace =
\bNew line -
\nHorizontal tab -
\t
Another common escape sequence is \", which represents the ” character.
- Since ” is used for the beginning/end of strings, it needs to be escaped.
The scanf function
scanf reads inputs according to a particular format.
- A
scanfformat string can contain both ordinary and conversion specifications, essentially the same asprintf.
For example:
int i, j;
float x, y;
scanf("%d%d%f%f", &i, &j, &x, &y);If a user inputs
1, -20, 0.3, -4.0e3, the results will be1,-20, 0.3 and -4000.0tightly packed because of the format string.The format string for
scanfis very similar toprint, except the&, which precedes each variable in the call.This is generally required and forgetting it will likely to unpredictable results.
It could crash, the input not updating the variables value, etc.
How scanf works
scanf is essentially a pattern-matching function that tries to match groups of input characters with conversion specifications.
For each conversion specification in the format string,
scanftries to locate an item of the appropriate type in the input data, skipping blank space if necessary.scanfthen reads the item, topping when it encounters a character that can’t belong to the item.If the item is successful read,
scanfcontinues processing the rest of the string format.If any item is not read successfully,
scanfreturns immediately without looking at the rest of the format string.scanfignores white space characters so it will read items even is spread over multiple lines.scanf“peeks” at the final new-line character without actually reading it. The new-line will be the character read by the next call toscanfWhen reading an integer,
scanffirst looks for a digit, a+, or-, then it reads digits until it reaches a non-digit.When reading a floating-point number,
scanflooks for a+or-followed by a series of digits (optional decimal point), followed by a possible exponent.- The exponent would be an
eorEwith a possible sign/digits
- The exponent would be an
Example of how scanf works
We write a program to read the following 4 numbers: 1, -20.3, -4.0e3 \n. The scanf could look like:
scanf("%d%d%f%f", &i, &j, &x, &y)scanf’s processes:
- Conversion specification:
%dThe first non-blank character is 1, which can be an integer.
It reads the next character which is a
-, whichscanfknows cannot be within an integer, so it puts it back.
- Conversion specification:
%dscanfreads the-, which is an acceptable start to an integer. It will continue going until it reads a character that cannot be included in an integer:2and0scanfstops when it reaches.because it is not a valid value for an integer. It puts it back.
- Conversion specification:
%fscanfreads the characters., which is a valid character for the beginning of a float, then3, and stops at the-because it is not a valid character for the middle of a float.scanfstores 0.3 in toxand puts back the-character
- Conversion specification
%fscanfnow reads-,4,.,0,e,3.\nIt stores all values but the
\n, which it puts back.
Ordinary characters in Format strings
The action scanf takes when it process ordinary characters depends on whether it is a white-space character:
White-space characters
When
scanfreads all the white-space characters until it reaches a non-white-space character, which it puts back.scanfdoesn’t differentiate between one or more white-space characters, even the fact of having none.
Non-white-space characters
When
scanfencounters a non-white-space character, it compares it to the next input character.If the two characters match, it disregards it and continues processing the format string.
If the characters do not match,
scanfputs the offending character back into the input, and aborts without further processing the format string.
scanf white-space example
Suppose the format string is " %d/ %d" with an input of “5/ 96". scanf
- Skips the first space since it is looking for an integer
- Matches
%dwith 5 - Attempts to match
/because it is in the format string - Skips the space
- Matches
%dwith 96 because it is a valid integer.
If the input is " 5 / 96" on the other hand, scanf
- Skips the first space
- Matches %
dwith 5 - Attempts to match the
/with/but there is no match with a space before a/in the format string. - The
/ 96characters remain to be read by the next call ofscanf- We should have used the format string
%d /d%to properly read this string.
- We should have used the format string
Adding fractions
/* Adds two fractions */
#include <stdio.h>
int main(void)
{
int num1, denom1, num2, denom2, result_num, result_denom;
printf("Enter first fraction: ");
scanf("%d/%d", &num1, &denom1);
printf("Enter second fraction: ");
scanf("%d/%d", &num2, &denom2);
result_num = num1 * denom2 + num2 * denom1;
result_denom = denom1 * denom2;
printf("The sum is %d/%d\n", result_num, result_denom);
return 0;
}Q&A
The \t escape causes printf to advance to the next tab stop. How does one know how far apart the tabs are?
- We don’t as it isn’t defined by C, but the operating system. It is typically 8 characters.
What happens when a scanf is expecting a number but is given a non-numeric input?
If it starts with a number followed by character, it reads in the number and leaves the characters for the next
scanifIf it is just characters, then
scanfwill likely store a random value in the variable.
What does it mean when scanf puts back characters and reads them again later?
Programs don’t actually read user input as its typed.
The input is actually stored in a hidden buffer that
scanfcan access.scanfcan put characters back into the buffer for subsequent reading.
Exercises
2. What calls of printf that display a float variable x in the following formats:
a) Exponential notation; left-justified in a field of size 8, one digit after the decimal point.
printf("%-8.1e", x)
b) Exponential notation; right-justified in a field size 10; 6 digits after the decimal point
printf("%10.6e", x)
c) Fixed decimal notation; left-justified of a field size 8, with 3 digits after the decimal point.
printf("-8.3f", x)
d) Fixed decimal notation; right justified of size 6; no digits after the decimal point.
printf("6.0f", x)
5. Suppose that we call scanf as follows:
scanf("%f%d%f", &x, &i, &y)And the user enters: 12.3 45.6 789
What are the values of x, i, and y after each call? Assume x and y are float and i is an int
x = 12.3i = 45y = 0.6scanfstops after the 6 because of the space.
Programming projects
1. Write a program that accepts a date from a user in the form of mm/dd/yyyy and responds back in the form yyyymmdd:
Enter a date (mm/dd/yyyy): 2/17/2011
You entered the date 20110217
/* Convert date from mm/dd/yyyy to yyyymmdd
* NOTE: 2/02/1999 should be 19990202
*/
#include <stdio.h>
int main(void)
{
int day, month, year;
printf("Enter a date (mm/dd/yyyy): ");
scanf("%2d/%2d/%4d", &month, &day, &year );
printf("You entered, %4d%2.2d%2.2d \n", year, month, day);
return 0;
}3. Books are identified by the ISBN, which after 01/01/07 contain 13 digits that are arranged in 5 groups (e.g. 978-0-393-97950-3).
The first group (GSI prefix) is either 978 or 979
The next is group identifier for language of origin
- 0 and 1 are for English speaking countries
The publisher code identifies the publisher (393 is W. W. Norton)
The item number is assigned by the publisher to identify the book
The last digit is a check digit to verify the accuracy of the of the preceding digits.
Write a program that parse the ISBN number:
Enter ISBN: 978-0-393-97850-3
GSI prefix: 978
Group identifier: 0
Publisher code: 393
Item number: 97950
Check digit: 3
/* Create a program that parses */
#include <stdio.h>
int main(void)
{
int gsi, group, pub, item, check;
printf("Enter ISBN: ");
scanf("%3d-%d-%3d-%5d-%3d", &gsi, &group, &pub, &item, &check);
printf("GSI prefix: %3d \n", gsi);
printf("Group identifier: %d\n", group);
printf("Publisher code: %3d\n", pub);
printf("Item number: %5d\n", item);
printf("Check digit: %d\n", check);
return 0;
}- Note: the
printfstatements could be combined into one statement