Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
scanf Assignment Suppression Tutorial
Learn the %*d trick: let scanf read a value from the input and quietly throw it away. Every program below was compiled and run, so the outputs you see are real.
What You Will Learn
By the end of this lecture you can:
- Explain what scanf assignment suppression is and why a single
*changes the meaning of a conversion. - Predict exactly how many values
scanfstores, and read its return value correctly. - Skip unwanted fields in dates, log lines and comma-separated records.
- Clean leftover characters from the input line with
%*[^\n]and%*c. - Spot the classic bug where an argument is passed for a skipped field.
Prerequisites
You should already know how printf and scanf work at a basic level, what a conversion specifier such as %d or %s is, and why scanf needs the address of a variable (the & operator). If those ideas are new, go back one lecture in this free embedded systems course, then come here. Compiler used for all examples: GCC with -std=c17 -Wall -Wextra.
What Is scanf Assignment Suppression?
Normally every conversion in a scanf format string does two jobs: it reads some characters from the input, converts them, and then stores the result through the next pointer argument. scanf assignment suppression cancels the second job. You write a * right after the %, and scanf still reads and checks the characters, but it does not store anything and it does not use up a pointer argument.
Think of it as reading a form where some boxes are irrelevant to you. You have to move your eyes past them to reach the box you care about, but you do not copy their content anywhere. That is all %*d means: “there is an integer here, consume it, forget it.”
The Syntax at a Glance
| Specification | Input it consumes | Stored in a variable? | Needs a pointer argument? |
|---|---|---|---|
%d | an integer | Yes | Yes (int *) |
%*d | an integer | No, discarded | No |
%s | one word (up to whitespace) | Yes | Yes (char *) |
%*s | one word | No, discarded | No |
%c | exactly one character | Yes | Yes |
%*c | exactly one character | No, discarded | No |
%*[^\n] | everything up to the end of the line | No, discarded | No |
Following One Input Through the Format
Suppose the user types 25 30 35 and your format is %d %*d %d. The diagram shows which input token meets which specification. Bright boxes are stored; dim boxes are skipped.
Notice the third row. scanf returns the number of values it actually assigned. A suppressed conversion is never counted, even though it consumed input successfully. This detail matters every time you validate input with if (scanf(...) == N).
Example 1: Skip the Middle Number
This is the smallest useful program. It reads three numbers but keeps only the first and the last, and it prints the return value so you can watch the counting rule in action.
File: s1_basic.c
#include <stdio.h>
int main(void)
{
int first = 0, last = 0;
int stored;
printf("Enter three numbers: ");
stored = scanf("%d %*d %d", &first, &last);
printf("scanf stored %d value(s)\n", stored);
printf("first = %d, last = %d\n", first, last);
return 0;
}
Build and run:
gcc -std=c17 -Wall -Wextra -o s1_basic s1_basic.c
./s1_basic
Expected output when you type three numbers:
Enter three numbers: 25 30 35
scanf stored 2 value(s)
first = 25, last = 35
Now run it again but type only two numbers. The second conversion that stores (%d for last) finds nothing, so scanf stops early:
Enter three numbers: 7 8
scanf stored 1 value(s)
first = 7, last = 0
Read that carefully. With input 7 8 the first %d stored 7, %*d swallowed 8, and the last %d hit the end of the line and failed. The return value is 1, and last kept the 0 we gave it at declaration. This is why we always initialise variables that scanf might not reach.
The Classic Bug: One Pointer Too Many
A very common mistake is to count the skipped field when listing arguments. Beginners write three variables for a format that only has two storing conversions. Here is that bug on purpose:
#include <stdio.h>
int main(void)
{
int x = 0, y = 0, z = -1; /* -1 marks "never written" */
scanf("%d %*d %d", &x, &y, &z); /* BUG: only two conversions store */
printf("x=%d y=%d z=%d\n", x, y, z);
return 0;
}
GCC notices it right away if you compile with warnings on:
s2_sentinel.c:7:11: warning: too many arguments for format [-Wformat-extra-args]
Run it with 25 30 35:
x=25 y=35 z=-1
Read the output closely
The variable z stayed at -1. The extra pointer was never used because the format only has two storing conversions. If z had been left uninitialised, you would print a random leftover number from the stack and wonder where it came from. The rule: the number of pointer arguments must equal the number of conversions without a *. Always compile with -Wall.
Example 2: Pull the Month and Year from a Date
Suppose a sensor logger stores dates as dd-mm-yyyy and your report only needs the month and year. A literal - in the format must match the same character in the input. Combined with suppression, the format becomes very compact.
#include <stdio.h>
int main(void)
{
int month = 0, year = 0;
printf("Enter date (dd-mm-yyyy): ");
if (scanf("%*d-%d-%d", &month, &year) == 2)
printf("Month = %d, Year = %d\n", month, year);
else
printf("Bad format\n");
return 0;
}
Enter date (dd-mm-yyyy): 22-10-2026
Month = 10, Year = 2026
Because we compare the return value with 2, bad input is caught. Typing the same date with slashes makes the literal - fail to match:
Enter date (dd-mm-yyyy): 22/10/2026
Bad format
Example 3: Read One Field from a Log Line
Embedded devices often print status lines such as WARN disk 85. Maybe you only need the number at the end. Skip the two words with %*s and capture the integer:
#include <stdio.h>
int main(void)
{
int percent = 0;
printf("Log line: ");
if (scanf("%*s %*s %d", &percent) == 1)
printf("Usage: %d%%\n", percent);
return 0;
}
Log line: WARN disk 85
Usage: 85%
Two details to observe. First, %*s stops at whitespace, so each one skips exactly one word. Second, %% inside printf prints a literal percent sign. This pattern scales: to read the 5th word of a line you write four %*s and one real conversion.
Example 4: Skip Text up to a Comma
The scan set %[^,] means “read any characters except a comma”. Add the * and it skips a whole text field of any length. This handles records like Asha,27 where the name length varies:
#include <stdio.h>
int main(void)
{
int age = 0;
printf("Record (name,age): ");
if (scanf("%*[^,],%d", &age) == 1)
printf("Age = %d\n", age);
return 0;
}
Record (name,age): Asha,27
Age = 27
Example 5: Clean the Input Line with scanf Suppression
This is the use that saves beginners the most pain. After scanf("%d", ...) the Enter key’s newline is still waiting in the input. The next %c reads that newline instead of the letter you typed. Two suppressed conversions remove the leftovers:
#include <stdio.h>
int main(void)
{
int num = 0;
char ch = '?';
printf("Number: ");
scanf("%d", &num);
scanf("%*[^\n]"); /* throw away the rest of the line */
scanf("%*c"); /* throw away the newline itself */
printf("Letter: ");
scanf("%c", &ch);
printf("num=%d ch=%c\n", num, ch);
return 0;
}
Type 42 abc, press Enter, then type a letter:
Number: 42 abc
Letter: Z
num=42 ch=Z
The first scanf took 42. The line still contained abc and a newline. %*[^\n] removed everything up to the newline, and %*c removed the newline itself. Only then did %c see the letter.
Why two separate calls?
If the line is already empty, %*[^\n] matches zero characters and fails. When both conversions are in one format string, scanf stops at the failure and never reaches %*c, so the newline stays behind. Two separate calls make the cleanup work in both cases.
How scanf Handles Whitespace While Skipping
Most numeric conversions such as %d and %s first skip leading whitespace. %c and the scan set %[ do not. That includes the suppressed forms, so %*c removes exactly one character, whitespace or not. Compare these two formats on the input xy followed by Enter:
| Format | Input | What gets stored |
|---|---|---|
%*c%c | xy | x dropped, y stored |
%*d %d | 10 20 | 10 dropped, spaces skipped automatically, 20 stored |
%d,%*d,%d | 10,20,30 | 10 and 30 stored, 20 dropped, return value 2 |
Common Mistakes with scanf Assignment Suppression
| Symptom | Likely cause | Fix |
|---|---|---|
| Variable shows a random number | scanf stopped before reaching it and the variable was never initialised | Initialise to a known value and test the return value |
| Compiler says too many arguments for format | You passed a pointer for a %* field | Remove the pointer; only non-suppressed conversions take one |
%c reads a newline | Newline from an earlier Enter is still in the input | Use scanf("%*[^\n]") then scanf("%*c"), or a space before %c |
| Return value is lower than expected | Suppressed fields are not counted | Compare against the number of storing conversions only |
| Literal text in the format never matches | Input uses a different separator | Print the raw input first and compare character by character |
Best Practices
- Compare
scanf‘s return value with the number of storing conversions every time. - Initialise every variable that scanf might leave untouched.
- Use suppression for fields you truly never need. If you might want the value later, store it.
- For text fields, add a width such as
%19swhen storing into an array so you never overflow it. Suppressed fields store nothing, so they have no overflow risk. - For serious text parsing on embedded targets, read a line with
fgetsand then usesscanfwith the same formats you learned here.
Why this matters on real devices
Firmware tools, serial consoles and test scripts constantly parse short fixed-format lines. Knowing how to skip a field without declaring a throwaway variable keeps parsing code short and avoids unused-variable warnings. The same skill carries over to sscanf when you later read data from a UART buffer in this free embedded C course.
Try It Yourself: Quick Quiz
Predict each answer first, then open the box. All answers were verified by running the code.
Q1. Input 1 2 3 4. What are a and b after scanf("%d %*d %*d %d", &a, &b)?
a = 1 and b = 4. The two middle numbers are read and dropped.
Q2. Input 5 6. What does scanf("%*d %*d") return?
0. Both conversions succeeded, but suppressed conversions are never counted as assignments.
Q3. Input xy. What does ch hold after scanf("%*c%c", &ch)?
The letter y. %*c consumed the x.
Q4. Input 10,20,30 with scanf("%d,%*d,%d", &a, &b). Return value, a, b?
Return value 2, a = 10, b = 30.
Q5. Input 25 30 with scanf("%d %*d %d", &a, &b), both initialised to 0. Return value, a, b?
Return value 1, a = 25, b = 0. The 30 was skipped, then there was nothing left for the last %d.
Interview Questions
What does the asterisk in %*d do?
It suppresses assignment. scanf reads and converts an integer but discards it and does not consume a pointer argument.
Does a suppressed conversion increase the value returned by scanf?
No. The return value counts only successful assignments to arguments.
How is %*d in scanf different from %*d in printf?
In scanf the star means skip. In printf the star means the field width is taken from an int argument, for example printf("%*d", 6, 42).
Why is scanf("%*[^\n]") followed by scanf("%*c") a useful idiom?
It discards the rest of the current line and the newline so the next character read starts a fresh line.
Key Takeaways on scanf Assignment Suppression
Remember these five points
- A
*after%means: read it, check it, do not store it. - Suppressed conversions take no pointer argument and are not counted in scanf’s return value.
- Pointer arguments must match the storing conversions, one for one.
%*[^\n]and%*cclean the line after a numeric read.- Initialise variables and check the return value, because scanf can stop early.
Assignment suppression is a small feature, but it teaches the real model behind scanf: the format string is a pattern that walks along the input one piece at a time, and each piece either lands in a variable or disappears. Once you see scanf that way, strange behaviours such as leftover newlines or early stops become predictable. In the next lecture of this free embedded systems course we move to single-character input with getchar and putchar, where the same newline puzzle appears again with a different solution.
Frequently Asked Questions
What is scanf assignment suppression in C?
It is the * placed after % in a scanf conversion, such as %*d. scanf reads the input but does not store it in any variable.
Does %*d need an argument?
No. A suppressed conversion takes no pointer argument. Passing one is a bug that GCC reports with -Wformat-extra-args.
Is the skipped value counted in scanf’s return value?
No. scanf returns only the number of successful assignments.
Can I suppress a string field of unknown length?
Yes. %*s skips one word and %*[^,] skips everything up to a comma. Nothing is stored, so there is no buffer to overflow.
How do I discard the rest of a line after scanf?
Call scanf("%*[^\n]") and then scanf("%*c"). Another common way is a loop with getchar, covered in the next lecture.
Does assignment suppression work with sscanf and fscanf?
Yes. The whole scanf family shares the same format rules.
Is this lecture part of a free embedded C course?
Yes. It belongs to the free embedded systems course on EmbeddedPathashala that builds the C foundation needed before Linux kernel and device driver work.
Keep Going with the Free Embedded C Course
Next you will learn character-level input with getchar and putchar. Everything 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