Exercise 7 of 10 · Strings and formatting
The Scoreboard
What you will make
A game scoreboard where every name, score and bar of # characters lands in the same column, built entirely from printf's own field-width numbers rather than spaces typed by hand.
The one new idea: a number between % and the conversion letter gives printf a fixed field width
Receipts, timetables and printed reports are all text with values dropped into fixed-width columns. printf's width specifiers are how C does that, and reaching for %-7s instead of counting spaces by hand is the habit that survives the day a name turns out to be longer than you guessed.
Go straight to the code ↓A number between % and the letter
Every printf call so far has used a bare conversion like %s or %d, which prints a value taking up
exactly as much room as it needs. That is fine until you want several rows to line up in columns, because
"Ana" and "Cleo" are not the same length and neither are 12 and 8.
Put a number between the % and the letter and you get a field width: the minimum number of characters
that conversion will occupy, padded with spaces if the value is shorter.
printf("[%5d]\n", 12);
printf("[%5d]\n", 3407);[ 12]
[ 3407]Both numbers land inside a field five characters wide, padded on the left — the default for a numeric width is to right-justify, pushing the value against the right edge of its field, exactly like lining up numbers in a ledger.
The minus flag: padding the other side
A leading minus sign inside the width reverses that: the value is pushed to the left edge instead, and the padding spaces go on the right.
printf("[%-5d]\n", 12);
printf("[%5d]\n", 12);[12 ]
[ 12]The same value, the same width, opposite edges. Names read more naturally left-justified — %-7s — while
numbers in a column usually read better right-justified — %3d with no minus. That pairing, a left-justified
label followed by a right-justified number, is the shape behind most printed tables.
A worked example
A luggage desk rather than a scoreboard, so the answer to this exercise stays yours to write:
#include <stdio.h>
int main(void) {
printf("[%-6s][%4s]\n", "Owl", "3");
printf("[%-6s][%4s]\n", "Heron", "14");
return 0;
}[Owl ][ 3]
[Heron ][ 14]The square brackets are there only to make the padding visible. %-6s gives every name six characters,
padded on the right; %4s gives every count four, padded on the left. Both closing brackets land in the
same column, and so do both numbers, whatever their own lengths happen to be.
Your turn
The editor holds a scoreboard with three players. Press Run first. Ana and Ben come out as tidy rows;
Cleo's row is ragged, because her line still uses bare %s %d %s with ordinary typed spaces between them,
and nothing gives her values a fixed width:
printf("%s %d %s\n", "Cleo", 5, "#####");Rewrite that one line as a call using the same two field widths the rows above her use, so her row matches
them. The widths you need — 7 for the name, 3 for the score — are already on screen in the two finished
rows.
Then change her score to 11 and run it again: the bar and the number both change, and the row stays in
column. Put the 5 back afterwards.
If something goes wrong
The likeliest outcome is a row that still does not line up. Check the width numbers against the two rows
above it rather than guessing — 7 for the name field, 3 for the score field — and check the minus sign
is present on the name's %s and absent on the score's %d.
If the compiler stops on that line reporting an undeclared identifier, a quote mark went missing somewhere
around "Cleo".
Nothing here can break. Change a score, press Run, and read your own board.
Write your code
Runs in your browser. Press Run (or Ctrl/Cmd+Enter) and the output is checked for you.
Press Esc then Tab to move keyboard focus out of the code editor.
Output will appear here after you run your code.The runtime is starting in the background. You can type now — it will be ready before you are.
The answer appears here once you have run your code at least once.
Things that often go wrong here
- Leaving the row as %s %d %s with no width numbers at all
- This is the bug in the starter code. Each placeholder takes up only as much room as its own value needs, so the row starts wherever Cleo's four-letter name happens to end rather than at the eighth character like the rows above it.
- Writing %7s instead of %-7s
- Without the minus sign a width specifier right-justifies by default, padding on the left. Cleo's name would be pushed to the right edge of its seven characters — ' Cleo ' or similar depending on the digits — instead of starting flush at the left the way Ana's and Ben's do.
- Dropping the quotes from "Cleo"
- Cleo without quotes is read as the name of something the compiler has never heard of — a variable, most likely — so it stops with an error about an undeclared identifier rather than printing anything.
- Using %d for the bar argument instead of %s
- The bar is a string literal, a char*, not a number. %d tells printf to read the bytes it was handed as though they were an int, which is undefined behaviour — C will not stop you, and whatever appears on screen is not a reliable representation of anything.
Longer explanation: read the full lesson. Want a blank editor instead? Open the C playground.