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.
Two major functions in C are the scanf() and printf() functions.
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(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.
For input handling, format specifiers in C provide features that make scanf both powerful and safer when used carefully.
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.
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 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.
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.
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.
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(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.
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.
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., 0x prefix for %x, force decimal point for %f)
Example:
printf("%#08x\n", 255); // Output: 0x0000ff
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
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
Adjust the size of the argument:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Correct modifiers make your code portable across 32-bit and 64-bit systems.
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.
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!
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.
The following code demonstrates how to input and output characters. You can run the code below to see its output and experiment with it.
The following code demonstrates how to input and output numbers in scientific notation.
The following code demonstrates how to input and output floating point numbers.
Note: Knowing the difference between float and double data types is important.
The following code demonstrates how to input and output floats with the same precision as initially given.
The following code demonstrates how to input and output unsigned integers.
The following code demonstrates how to input and output hexadecimal numbers.
The following code demonstrates how to input and output long integers.
The following code demonstrates how to input and output unsigned long integers.
The following code demonstrates how to input and output long long integers.
The following code demonstrates how to input and output unsigned long long integers.
The following code demonstrates how to input and output double values.
The following code demonstrates how to input and output octal values.
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.
The following code demonstrates how to output the percentage sign.
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.
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.
Not all format specifiers in C behave the same in printf and scanf. Understanding these distinctions prevents subtle and frustrating bugs.
In printf, they’re equivalent for printing integers.
In scanf, %i interprets input based on prefixes:
0x → hexadecimal
0 → octal
none → decimal
%d always expects decimal input.
Use %d when you only want decimal input and %i when you want prefix-based parsing.
In scanf:
%f reads a float.
%lf reads a double.
In printf, both print a double because default argument promotion converts float to double in variadic functions.
This is one of the most common beginner pitfalls in C I/O.
To ensure portability across compilers and architectures, use specifiers that match your data type:
|
|
|
|
|
|
Pointer |
|
|
Wide character |
|
|
Wide string |
|
|
Using the matching specifier and type keeps format specifiers in C portable, precise, and warning-free, no matter the platform or compiler.
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.
Even seasoned developers encounter subtle issues with format specifiers in C, especially around mismatched types and unsafe inputs. Keep these best practices in mind:
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).
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");}
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!