printf: formatted output
printf takes a format string and then one value for each placeholder in it. The placeholders begin with % and tell printf what kind of value to expect and how to display it.
The format string is printed literally except for the placeholders, so ordinary text, spaces and punctuation can be mixed in freely. Escape sequences beginning with a backslash produce characters that cannot be typed directly.
| Placeholder | For | Example output |
|---|---|---|
| %d | int | 42 |
| %f | float or double | 3.140000 |
| %.2f | float, 2 decimal places | 3.14 |
| %c | a single character | A |
| %s | a string | Ayesha |
| %5d | int, right-aligned in 5 columns | 42 |
| \n | newline | moves to the next line |
| \t | tab | moves to the next tab stop |
scanf, and the ampersand
scanf reads input and stores it in variables. It takes a format string, exactly like printf, and then the addresses of the variables to fill — which is what the & is for.
The reason is that C passes arguments by value: a function receives a copy and cannot change the original. To let scanf modify your variable, you give it the variable's address rather than its value, and scanf writes through that address.
Forgetting the & is the most common C error there is
scanf("%d", marks); passes the value of an uninitialised variable and asks scanf to treat it as an address. The program may crash, may silently corrupt memory, or may appear to work. Modern compilers warn about it; older ones do not. If a program using scanf behaves inexplicably, check the ampersands first.
Reading text
scanf("%s", name) reads a single word and stops at the first space, so "Ayesha Khan" leaves "Khan" unread and the next scanf picks it up unexpectedly. To read a whole line including spaces, use fgets(name, 20, stdin), which also limits how many characters it will accept.
That limit matters. scanf("%s", name) into a 20-character array will happily write 50 characters if the user types 50, overwriting whatever memory follows. This is a buffer overflow, and it is both a common bug and a classic security vulnerability.
Write a program that reads a student's name and two marks, then prints the name and the average to two decimal places.
char name[30]; int m1, m2; float avg;Declare everything first, with the array large enough for a realistic name.printf("Enter name: "); scanf("%s", name);A prompt before every input, and no & because name is an array.printf("Enter two marks: "); scanf("%d %d", &m1, &m2);Two placeholders, two addresses, in the same order. The space in the format string lets scanf skip whitespace between the numbers.avg = (m1 + m2) / 2.0;The 2.0 forces floating-point division. With 2 the answer would be truncated.printf("%s scored %.2f\n", name, avg);%.2f gives exactly two decimal places, which is what the question asked for.
Declare, prompt, scanf with & on the numbers, divide by 2.0, print with %.2f.
Getting the placeholders right
The format string and the values must agree. C does not check this: printf("%d", 3.7) compiles and prints nonsense, because printf believes it is looking at an integer and interprets the bits accordingly.
Three rules prevent almost every problem. Use one placeholder per value and no more. Match the type exactly — %d for int, %f for float, %lf when reading a double with scanf. And remember that %f prints six decimal places by default, so a money value needs %.2f.
Before you leave this chapter
- printf takes a format string plus one value per placeholder, in order.
- %d int, %f float, %c char, %s string; %.2f fixes the decimal places.
- scanf needs the ADDRESS of each variable, so use & — except for arrays and strings.
- scanf("%s") stops at the first space; fgets reads a whole line and limits the length.
- Mismatched placeholders compile silently and print nonsense.
Building readable output
Output that a person has to decipher wastes the work that produced it. Two devices make the difference, and both are examinable.
Field widths align columns: %10s prints a string right-aligned in ten characters, and %-10s left-aligns it. Combined with \t for tabs, a table of results lines up rather than staggering across the screen.
Labels make a number mean something. printf("%d", t) prints a bare number; printf("Total marks: %d out of %d\n", t, max) tells the reader what it is. In an exam, unlabelled output loses marks even when the calculation is correct.
Print a table of three students with names left-aligned in 12 columns and marks right-aligned in 5.
- Header:
printf("%-12s%5s\n", "Name", "Mark");The same widths are used for the header as for the data, so the columns align. - Each row:
printf("%-12s%5d\n", name, mark);The minus sign left-aligns the name; the number right-aligns, which is how figures should be read. - A name longer than 12 characters overflows the column rather than being cut.The width is a minimum, not a maximum — worth knowing before choosing it.
- Choose the width from the longest realistic value, not the longest one in your test data.A table that aligns for three test names and breaks for a real class is not finished.
Use %-12s for the name and %5d for the mark, with the same widths in the header row.