Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
scanf Field Width Explained
Learn how the scanf field width in C (the 2 in %2d, the 4 in %4f, the 5 in %5s) decides how much input each conversion may read, what stays behind in the buffer, and how to keep your arrays safe. Part of our free embedded C programming course.
Every C program that listens to a keyboard, a serial console or a text file ends up calling scanf sooner or later. Most beginners learn %d, %f and %s and stop there. But there is one small number you can slip between the percent sign and the letter, and it changes everything: the scanf field width in C. It tells scanf the maximum number of characters it may consume for that one conversion.
In this lecture of our free embedded C programming course you will see exactly what that number does, why input sometimes seems to “split” in strange places, and how a single digit in a format string can be the difference between a safe program and a buffer overflow. C is the language of the Linux kernel, bootloaders and device drivers, so the habits you build here carry straight into our free embedded systems course, free embedded Linux course, free Linux device drivers course and free Linux kernel development course.
What You Will Learn
- What the scanf field width means, and how it differs from the width in printf
- The four rules scanf follows every time it applies a width
- How
%wd,%wfand%wsbehave when the input is shorter than, equal to, or longer than the width - Why leftover characters stay in the input buffer and how they affect the next read
- How to size a character array correctly for
%nsand avoid overflow - How to use widths with
sscanfto parse packed data such as GPS time and dates
Prerequisites
- You have read the earlier lectures in this chapter on conversion specifiers and basic printf and scanf use
- You know what an
int, afloatand achararray are - GCC installed (every program here was built with GCC 13 on Ubuntu 24.04 using
-std=c11)
What Is scanf Field Width in C?
A scanf conversion has several optional parts: %, an optional *, an optional width, an optional length modifier such as l, and finally the conversion letter. The width is a positive decimal number. Written as %5s, it means: “read at most five characters for this item, then stop.”
The word to remember is maximum. A scanf field width never pads, never inserts blanks and never forces scanf to wait for more characters. If the item ends early (because a space or a letter shows up), scanf is happy to stop early. The width only matters when the input is long enough to hit the limit.
This is the opposite of what the same number means in printf, where the width is a minimum and short values get padded. Students mix the two up constantly, so keep this table close.
| Question | scanf width | printf width |
|---|---|---|
| What does the number mean? | Maximum characters to read | Minimum characters to print |
| Data is shorter than the width | Item simply ends early, nothing is added | Output is padded with blanks |
| Data is longer than the width | Reading stops at the limit, the rest stays in the buffer | Whole value is printed, nothing is cut |
| Direction | Input (stdin to variable) | Output (variable to stdout) |
How scanf Applies a Field Width: Four Rules
Whatever the conversion letter is, scanf walks through the same routine for every item that carries a width.
- Skip leading whitespace. For
%d,%fand%s, spaces, tabs and newlines in front of the item are discarded first. They do not count toward the width. - Read while the characters still fit the item and the count is below the width. For
%dthat means an optional sign followed by digits; for%sit means anything that is not whitespace. - Convert and store. The characters collected become an integer, a float or a string. For
%s, scanf also appends the terminating'\0'. - Leave everything else alone. Characters that were not consumed remain in the input buffer. The next conversion, or the next scanf call, starts exactly there.
Pipeline
Exception: %c
%c does not skip whitespace and its width is an exact count. %3c reads exactly three characters (blanks included) and does not add a '\0'. Everything else in this lecture is about %d, %f and %s.
scanf Field Width with %d: Shorter, Equal, Longer
Let us read two integers with "%2d%3d". The first number may use at most two characters, the second at most three. Notice there is no space between the two conversions: with widths in place, none is needed, because scanf already knows where the first item must end.
#include <stdio.h>
int main(void)
{
int a = -1, b = -1, ch;
int n = scanf("%2d%3d", &a, &b);
printf("assigned=%d a=%d b=%d\n", n, a, b);
printf("left in buffer: [");
while ((ch = getchar()) != EOF && ch != '\n')
putchar(ch);
printf("]\n");
return 0;
}
The last loop is a debugging trick worth keeping. It prints whatever scanf left unread on the line, so you can literally see the buffer. Build and run it:
gcc -std=c11 -Wall -Wextra -o w_int w_int.c
./w_int
Type 483 9021 and press Enter. Here is what a run looks like for several inputs:
| You type | a | b | Left in buffer | Why |
|---|---|---|---|---|
| 7 41 | 7 | 41 | (nothing) | Both items shorter than their widths |
| 58 612 | 58 | 612 | (nothing) | Both items exactly as wide as the width |
| 48392 | 48 | 392 | (nothing) | No separator, widths alone split the digits |
| 483 9021 | 48 | 3 | 9021 (after a space) | %2d stops after 48; %3d reads the lone 3 and hits the space |
| -123 45 | -1 | 23 | 45 (after a space) | The minus sign uses up one of the two characters |
| (3 spaces)901234 | 90 | 123 | 4 | Leading blanks are skipped and not counted |
Before scanf
After %2d (a = 48)
After %3d (b = 3)
Legend
The fourth row is the one that surprises people. The user typed a three-digit number and a four-digit number, yet b became 3. Nothing is broken: %2d took “48”, and %3d found only “3” before the space ended its item. The four digits 9021 are still waiting in the buffer, and a later scanf call would happily pick them up.
Try it yourself: predict the result
With the same program, what do you expect for the input 12345 6? Work it out on paper first. Answer: a = 12, b = 345, and the buffer still holds ” 6″. Run it to confirm.
scanf Field Width with %f: The Decimal Point Counts
For floating-point input the width counts every character of the item: digits before the point, the point itself, digits after it, a leading sign, and even an exponent. Beginners often assume the width counts only digits. It does not.
#include <stdio.h>
int main(void)
{
float x = -1.0f, y = -1.0f;
int ch;
int n = scanf("%4f%5f", &x, &y);
printf("assigned=%d x=%.3f y=%.3f\n", n, x, y);
printf("left in buffer: [");
while ((ch = getchar()) != EOF && ch != '\n')
putchar(ch);
printf("]\n");
return 0;
}
gcc -std=c11 -Wall -Wextra -o w_float w_float.c
./w_float
| You type | x (%4f) | y (%5f) | Left in buffer | Why |
|---|---|---|---|---|
| 9 3.7 | 9.000 | 3.700 | (nothing) | Both shorter than their widths |
| 12.5 7.25 | 12.500 | 7.250 | (nothing) | “12.5” is exactly four characters |
| 3.1415 | 3.140 | 15.000 | (nothing) | %4f stops after “3.14”; “15” is read as a separate number |
| 123.456 98.765 | 123.000 | 456.000 | 98.765 (after a space) | %4f consumed “123.” including the point |
| -12.75 4 | -12.000 | 75.000 | 4 (after a space) | Sign and point both use width |
Look at the fourth row. The programmer wanted 123.456 but got 123.0 and then a stray 456. A width that is too small does not raise an error; it silently chops the number into pieces. For this reason, most real programs leave the width off %f entirely and only use it when the data format truly has a fixed character count.
%.2f in scanf to read “two decimal places”. Precision belongs to printf. In scanf you read the whole number and round or format it later.
scanf Field Width with %s: Protecting Your Buffers
This is the most important use of a scanf field width. A plain %s reads until whitespace, however long the word is. If the destination array is smaller than the word, scanf writes past the end of the array and corrupts memory. That is the classic buffer overflow, and it has caused real security vulnerabilities in embedded firmware and desktop software alike. (The old gets() function was removed from the language in C11 for exactly this reason.)
A width on %s limits how many characters are stored. The golden rule: the array must be one element larger than the width, because scanf adds a '\0' after the characters.
#include <stdio.h>
#include <string.h>
int main(void)
{
char tag[6]; /* 5 characters + 1 for '\0' */
char rest[16];
int ch;
int n = scanf("%5s %15s", tag, rest);
printf("assigned=%d tag=[%s] rest=[%s]\n", n, tag, rest);
printf("strlen(tag)=%zu\n", strlen(tag));
printf("left in buffer: [");
while ((ch = getchar()) != EOF && ch != '\n')
putchar(ch);
printf("]\n");
return 0;
}
gcc -std=c11 -Wall -Wextra -o w_str w_str.c
./w_str
| You type | tag | rest | Left in buffer |
|---|---|---|---|
| uart0 ready | uart0 | ready | (nothing) |
| Bluetooth | Bluet | ooth | (nothing) |
| SENSOR_TEMP_01 ok | SENSO | R_TEMP_01 | ok (after a space) |
tag[0] to tag[5]
Still in the input buffer
Legend
The word was cut after five characters, the array stayed safe, and the remaining text became the input for the next conversion. Cutting a word in two is a trade-off, but it is a far better failure than overwriting the stack.
Letting a Constant Control the Width
Unlike printf, scanf has no * trick to take the width from a variable. The width must be a literal inside the format string. To avoid keeping a number in two places, use the preprocessor to turn a constant into text:
#include <stdio.h>
#define NAME_LEN 7
#define STR_(x) #x
#define STR(x) STR_(x)
int main(void)
{
char name[NAME_LEN + 1];
if (scanf("%" STR(NAME_LEN) "s", name) == 1)
printf("name=[%s]\n", name);
return 0;
}
gcc -std=c11 -Wall -Wextra -o w_macro w_macro.c
echo firmware | ./w_macro
name=[firmwar]
Change NAME_LEN once and both the array size and the format string follow. The two-level STR and STR_ macros are needed so that NAME_LEN is expanded to 7 before it is turned into the text “7”.
Real-World Use: Parsing Packed Data with sscanf
Everything above works the same for sscanf, which reads from a string instead of the keyboard. This is where field widths shine, because many embedded data formats have no separators at all. Digits are simply packed side by side.
#include <stdio.h>
int main(void)
{
const char *date = "20261022"; /* YYYYMMDD, no separators */
const char *gps = "123519"; /* hhmmss as in a GPS sentence */
int y, mo, d, hh, mm, ss;
if (sscanf(date, "%4d%2d%2d", &y, &mo, &d) == 3)
printf("Date: %02d-%02d-%04d\n", d, mo, y);
if (sscanf(gps, "%2d%2d%2d", &hh, &mm, &ss) == 3)
printf("Time: %02d:%02d:%02d\n", hh, mm, ss);
return 0;
}
gcc -std=c11 -Wall -Wextra -o w_packed w_packed.c
./w_packed
Date: 22-10-2026
Time: 12:35:19
| Where you meet it | Example data | Format |
|---|---|---|
| GPS receiver (NMEA time) | 123519 | %2d%2d%2d for hours, minutes, seconds |
| RTC or log date | 20261022 | %4d%2d%2d for year, month, day |
| Fixed-width serial frame | 0042037 | %4d%3d for an id and a reading |
| Short device names | eth0, wlan0 | %15s to cap the name length |
A note for those heading toward drivers: kernel code has its own sscanf that understands field widths too, but for parsing a single number from user space (for example in a sysfs store handler) modern kernel code prefers kstrtoint() and friends, which reject trailing garbage. You will meet both in our free Linux device drivers course.
Common Mistakes and Troubleshooting
| Mistake | What you see | Fix |
|---|---|---|
| Expecting the width to pad or force a minimum | Input is not padded; short items just end early | Padding is a printf feature; scanf only limits |
char s[8] with %8s | Crash or odd bugs, because the terminator lands outside the array | Use %7s: width is array size minus one |
| Forgetting that leftovers remain | The next scanf reads text you did not expect, or a %c gets a newline | Print the leftovers while debugging, or read whole lines with fgets |
| Not checking the return value | Variables keep old or garbage values | Compare the return value of scanf with the number of items you expect |
| Counting only digits in the width | Sign or decimal point eats a slot, number is chopped | Add room for the sign and point, or drop the width on numbers |
Writing %.2f in scanf | Conversion does not work as expected | Remove the precision; scanf has none |
%s with scanf on data you do not control. Always give it a width that fits the array.
Best Practices, Performance and Security
- Always put a width on
%sand%[, sized as array length minus one. - Check the value returned by
scanfandsscanfbefore using the variables. - Use widths on numbers only when the data format is truly fixed-width; otherwise let the number end naturally at the first space.
- For serious input handling, read a full line with
fgetsinto a buffer and parse it withsscanf. You get one place to check for errors and nothing is left in the stream. - Performance: scanf is convenient but not fast. When you must read large volumes, for example sensor logs with thousands of lines,
fgetsplusstrtolorstrtodis noticeably quicker and reports errors more precisely. - Security: untrusted input plus unbounded
%sequals a vulnerability. A width is the cheapest fix there is.
Quick Quiz: Predict the Output
Click each question to reveal the answer. Try to answer before you open it.
Q1. The input is 12345 and the format is “%3d%2d”. What are the two values?
The first value is 123 and the second is 45. The widths split the digits even without a separator.
Q2. The input is “100 200” and the format is “%2d %2d”. What are the two values?
The first value is 10 and the second is 0. After %2d reads “10”, the next character is the second zero, which %2d reads as “0” and then stops at the space. The text ” 200″ is left in the buffer.
Q3. The input is ABCDEF and the code is char s[4]; scanf("%3s", s);. What is in s?
“ABC” followed by the terminator. This is the correct pairing: width 3, array size 4. DEF stays in the buffer.
Q4. The input is -0.75 and the format is “%4f”. What is stored?
-0.7. The minus sign and the decimal point both count, so the item is “-0.7” and the “5” remains.
Q5. Why is char name[8]; scanf("%8s", name); wrong?
Eight characters plus the terminator need nine bytes. It must be %7s for an eight-byte array.
Interview Questions
1. Is the width in scanf a minimum or a maximum?
A maximum. It limits how many characters one conversion may consume. It never pads.
2. What happens to characters beyond the width?
They stay in the input stream and become the input for the next conversion or the next scanf call.
3. Do leading spaces count toward the width of %d?
No. Leading whitespace is skipped first (except for %c, %[ and %n) and is not counted.
4. How do you safely read a word into char buf[32] with scanf?
Use %31s. One slot is reserved for the terminator.
5. Why do many teams avoid scanf for real input handling?
Errors leave unread data in the stream, the behaviour on bad input is awkward to handle, and it is slow for bulk data. Reading lines with fgets and parsing with sscanf or strtol is more predictable.
Summary and Key Takeaways
Remember these points
- The scanf field width in C is a maximum number of characters, never a minimum.
- Leading whitespace is skipped first and is not counted.
- For floats, the sign and the decimal point count toward the width.
- Unread characters stay in the buffer and feed the next conversion.
- For strings, array size must be at least width plus one.
- Check the return value and prefer fgets with sscanf for robust programs.
A field width is a tiny piece of syntax with big consequences. Used on %s, it is a safety belt. Used on numbers inside sscanf, it lets you slice packed data such as GPS time or compact dates without any separators. Used carelessly, it chops numbers into surprising pieces and leaves stray characters behind. The best habit you can build is to run the small programs in this lecture, change the input, and watch the “left in buffer” line until the behaviour feels obvious.
In the next lecture we switch to the output side and look at the width and precision of printf, where the same number means something very different.
Frequently Asked Questions
What is the scanf field width in C?
It is the optional number between the percent sign and the conversion letter, for example the 3 in %3d. It sets the maximum number of characters scanf may read for that conversion.
Does scanf field width truncate input or discard the extra characters?
It does not discard anything. Reading simply stops at the width, and the remaining characters stay in the input buffer for the next conversion.
How do I prevent buffer overflow with scanf?
Add a width to every %s equal to the array size minus one, such as %15s for a 16-byte array.
Can I pass the scanf width as a variable like printf’s star?
No. In scanf the star means “suppress assignment”, not “take the width from an argument”. Build the format with a macro or use snprintf to create it at run time.
Does the sign or decimal point count toward the width?
Yes. Every character that belongs to the item counts, including the sign, the decimal point and an exponent.
Is sscanf different from scanf for field widths?
The rules are the same. Only the source differs: sscanf reads from a string you provide instead of from standard input.
Where can I learn C for embedded systems for free?
EmbeddedPathashala offers a free embedded C programming course that leads into our free embedded systems course, free embedded Linux course, free Linux device drivers course and free Linux kernel development course.
Keep Going With the Free Course
You now know how the scanf field width in C controls what is read and what is left behind. Continue with the next lecture on printf width and precision, then try the quiz lab at the end of the chapter. Every lesson on EmbeddedPathashala is free, from C basics to Linux kernel and device drivers.
Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments