Format specifiers are special operators that are responsible for indicating the data types used for both input and output. Simply put, a format specifier defines the data type involved when accepting an input or printing an output. While format specifiers can be found in numerous languages, in this blog, we'll focus solely on format specifiers in C and learn how they work using various code snippets. And even if you’ve only had a basic introduction to C, you’ll be good to go for this lesson.
But before we get started, let’s understand how we usually deal with input and output in C.
Input and output in C#
Two major functions in C are the scanf() and printf() functions.
scanf()#
The function scanf() is common in C and is designed to receive user input from the standard input stream (e.g. keyboard in the user-specified format). Let’s learn how scan(f) works using the syntax below.
scanf() syntax#
scanf(format_specifier, &pointer_to_variable);
format_specifier refers to the second parameter’s data type. The user specifies the data type of the variable for which the user will provide a value to the program so that it can be interpreted accordingly.
&pointer_to_variable refers to the memory location where the variable is stored so that it can be updated once the user provides the input value.
scanf Essentials: Scansets, Assignment Suppression, Widths, and Return Values#
For input handling, format specifiers in C provide features that make scanf both powerful and safer when used carefully.
Field Widths#
Always limit the number of characters read to prevent buffer overflow:
scanf("%19s", buf); // Safe for a 20-byte buffer
Widths also apply to %d, %f, and others, controlling how many characters are consumed.
Assignment Suppression (*)#
Use * to convert input but skip storing it:
scanf("%*d %d", &x); // Skips first integer, stores second
This is handy when you want to ignore delimiters, placeholders, or IDs.
Scansets (%[])#
Scansets let you filter allowed characters:
scanf("%19[^\n]", line); // Read until newlinescanf("%10[0-9A-Fa-f]", hex); // Read up to 10 hex digits
They’re ideal for parsing structured text safely without consuming unwanted input.
Return Value#
scanf returns the number of successfully assigned items:
if (scanf("%d %f", &x, &y) != 2) {fprintf(stderr, "Invalid input!\n");}
Always check this return value before using the read variables.
Why It Matters#
By combining width limits, scansets, and assignment suppression, you make format specifiers in C safe, predictable, and robust—avoiding common input parsing bugs that plague beginners and experts alike.
printf()#
Another common C function, printf(), is responsible for outputting a string in the user-specified format to the standard output (e.g. screen). Let’s learn how this function works using the syntax below.
printf() syntax#
printf(const char * c_string, arguments ...)
const char * c_string refers to the C string that is to be outputted to the screen. Since it cannot be modified, it’s passed as const.
The count of arguments can be more than one if the string contains more than one variable to be outputted and each argument represents the data type of the corresponding variable in the string.
Note: We do not add the pointer (&) sign in the print function as the memory address for that value will not be updated with a new value. Learn more about pointers here.
Format specifiers and data types#
As discussed before, a particular format specifier is associated with a particular data type of the value that is to be printed or accepted. Depending on the particular use case, the variable could have any data type. The following table thoroughly explains what format specifier is to be used for what data type.
Format Specifier | Syntax | Description |
%d | int | Decimal integer or signed integer specifier |
%c | char | Character specifier |
%e | float | Scientific notation specifier |
%f | float | Float specifier |
%g | float | Fixed precision flat specifier |
%u | unsigned int | Unsigned integer specifier |
%x | int | Hexadecimal specifier |
%ld | long | Long integer specifier |
%lu | unsigned long | Unsigned long specifier |
%lld | long long | Long long specifier |
%llu | unsigned long long | Unsigned long long specifier |
%lf | double | Double specifier |
%Lf | long double | Long double specifier |
%o | int | Octal specifier |
%s | char array | String specifier |
%n | int | Count specifier (prints nothing) |
%[flags][width][.precision][length]type
Each part is optional, but when combined thoughtfully, they produce professional-grade formatted output.
Flags#
Control alignment, padding, sign display, and alternate notation:
-→ Left-justify within the field width+→ Always show the sign(space) → Prepend a space for positive numbers
0→ Zero-pad numeric fields#→ Alternate form (e.g.,0xprefix for%x, force decimal point for%f)
Example:
printf("%#08x\n", 255); // Output: 0x0000ff
Width#
Specifies minimum field width:
printf("%8d\n", 42); // Pads with spaces to 8 characters
You can make width dynamic with *:
printf("%*d\n", 5, 42); // Width determined at runtime
Precision#
Controls numeric precision or string truncation:
Floats → digits after decimal (
%.3f)Strings → max characters to print (
%.5s)
Precision can also be dynamic:
printf("%.*f\n", 2, 3.14159); // 3.14
Length Modifiers#
Adjust the size of the argument:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Correct modifiers make your code portable across 32-bit and 64-bit systems.
Why It Matters#
Once you learn this one format template, you can decode nearly any formatting task in C—far beyond memorizing a few specifiers. It’s one of the most reusable patterns in mastering formatted output.
C code examples#
The use of a few format specifiers in C code is demonstrated through the short code snippets below. You can run them to see their output, and feel free to experiment with the code yourself — you’ll be a format-specifier expert in no time!
Decimal integer or signed integer specifier#
The following code demonstrates how to input and output decimal integers or signed integers. You can run the code below to see its output and experiment with it too.
Character specifier#
The following code demonstrates how to input and output characters. You can run the code below to see its output and experiment with it.
Scientific notation specifier#
The following code demonstrates how to input and output numbers in scientific notation.
Float specifier#
The following code demonstrates how to input and output floating point numbers.
Note: Knowing the difference between float and double data types is important.
Fixed precision float specifier#
The following code demonstrates how to input and output floats with the same precision as initially given.
Unsigned integer specifier#
The following code demonstrates how to input and output unsigned integers.
Hexadecimal specifier#
The following code demonstrates how to input and output hexadecimal numbers.
Long integer specifier#
The following code demonstrates how to input and output long integers.
Unsigned long specifier#
The following code demonstrates how to input and output unsigned long integers.
Long long specifier#
The following code demonstrates how to input and output long long integers.
Unsigned long long specifier#
The following code demonstrates how to input and output unsigned long long integers.
Double specifier#
The following code demonstrates how to input and output double values.
Octal specifier#
The following code demonstrates how to input and output octal values.
String specifier#
The following code demonstrates how to input and output strings.
Note: Feel free to delve deeper into the use of n in printf as well.
Percentage printing specifier#
The following code demonstrates how to output the percentage sign.
Why are format specifiers important?#
Format specifiers play a crucial role when it comes to interpreting and displaying data correctly. They have three main functions in programming: data representation, proper memory allocation, and input and output control.
Data representation: Format specifiers describe how variables with different data types should be parsed or formatted.
Proper memory allocation: Format specifiers help the compiler determine how much memory space to take for a particular variable depending on its type.
Input and output control: Format specifiers provide a standardized technique for incorporating variables within inputs or outputs and adding consistency in operations.
Rules for format specifiers#
Let’s review a key few rules to keep in mind when dealing with format specifiers.
1. Format specifiers always start with the percentage sign (%) followed by the data type symbol mentioned in the table above.
2. When there is more than one variable involved, it is necessary to maintain the correct order of arguments when compared to the order of format specifiers.
3. Ensure the printf() or scanf() statement matches the data type of the corresponding variable.
4. Buffer overflows can occur while using the string format specifier if the amount of memory needed for the string is insufficient. Extra precautions should be taken to avoid storage concerns.
5. Some format specifiers support changes in the precision and width of the involved variable. The next section explores such modifiers in detail.
Input vs Output Differences (and Portable Types)#
Not all format specifiers in C behave the same in printf and scanf. Understanding these distinctions prevents subtle and frustrating bugs.
%d vs %i#
In
printf, they’re equivalent for printing integers.In
scanf,%iinterprets input based on prefixes:0x→ hexadecimal0→ octalnone → decimal
%dalways expects decimal input.
Use %d when you only want decimal input and %i when you want prefix-based parsing.
%f vs %lf#
In
scanf:%freads afloat.%lfreads adouble.
In
printf, both print adoublebecause default argument promotion convertsfloattodoublein variadic functions.
This is one of the most common beginner pitfalls in C I/O.
Portable Specifiers for Correct Types#
To ensure portability across compilers and architectures, use specifiers that match your data type:
|
|
|
|
|
|
Pointer |
|
|
Wide character |
|
|
Wide string |
|
|
Why It Matters#
Using the matching specifier and type keeps format specifiers in C portable, precise, and warning-free, no matter the platform or compiler.
Formatting the input or output#
The C language allows its users to correctly format an input or output by pairing some additional information with the format specifier.
Right justification: Adding a number between the % and the format specifier symbol results in the same amount of spaces before the involved variable.
Left justification: Adding a negative number between the % and the format specifier symbol results in the same amount of spaces after the involved variable.
Precision modifiers: For floating point integers (i.e. values with a decimal part), the precision for the decimal value can also be specified. Adding a .digit between the % and the f symbol represents the required number of acceptable places after the decimal point.
Note: For a shorter or completely unspecified field width, only the minimum number of characters in the original variable are printed.
Let’s see how to perform these formatting techniques in our code as well.
And that marks the end of our discussion on format specifiers. From understanding how to handle input and output using formatted strings to learning more about coding specifiers for different data types, we’ve covered everything you need to know to work with format specifiers in C, even if you're learning C from scratch. You can now incorporate the correct specifiers and deal with your data types correctly.
Common Pitfalls with Format Specifiers in C#
Even seasoned developers encounter subtle issues with format specifiers in C, especially around mismatched types and unsafe inputs. Keep these best practices in mind:
Mismatched Specifier and Argument Type#
Passing the wrong argument type to printf or scanf causes undefined behavior.
Always match the correct length modifier (e.g., %ld for long, %lf for double).
Unbounded %s in scanf#
Never use a bare %s. Always limit width to prevent buffer overflow:
scanf("%19s", buf); // Safe for a 20-byte buffer
if (scanf("%d", &x) != 1) {fprintf(stderr, "Invalid input.\n");}
Why It Matters#
Mastering these safety habits ensures your use of format specifiers in C remains predictable, portable, and secure—no undefined behavior, no silent bugs.
Happy learning!