Format Specifiers in C

Format Specifiers in C

8 mins read
Dec 19, 2023
Share
editor-page-cover

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 newline
scanf("%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)

The Full Anatomy of Format Specifiers in C (printf Family)#

Beyond %d, %f, and %s, format specifiers in C follow a consistent structure that lets you control precision, alignment, and data type precisely.

General Syntax#

%[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., 0x prefix 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:

hh

char

%hhd

h

short

%hd

l

long

%ld

ll

long long

%lld

L

long double

%Lf

z

size_t

%zu

t

ptrdiff_t

%td

j

intmax_t

%jd

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.

C
#include <stdio.h>
int main(){
printf("Learning decimal integer specifiers today!\n\n");
int my_integer;
printf("Enter an integer value here = \n");
scanf("%d", &my_integer);
printf("The value obtained using the decimal integer specifier is = %d \n", my_integer);
return 0;
}
Did you find this helpful?

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.

C
#include <stdio.h>
int main() {
printf("Learning character specifiers today!\n\n");
char my_character;
printf("Enter a character here = \n");
scanf(" %c", &my_character);
printf("The value obtained using the character specifier is = %c \n", my_character);
return 0;
}
Did you find this helpful?

Scientific notation specifier#

The following code demonstrates how to input and output numbers in scientific notation.

C
#include <stdio.h>
int main() {
printf("Learning scientific notation specifiers today!\n\n");
float my_float_sci;
printf("Enter a float value here = \n");
scanf("%e", &my_float_sci);
printf("The value obtained using the scientific notation specifier is = %e \n", my_float_sci);
return 0;
}
Did you find this helpful?

Float specifier#

The following code demonstrates how to input and output floating point numbers.

C
#include <stdio.h>
int main() {
printf("Learning float specifiers today!\n\n");
float my_float;
printf("Enter a float value here = \n");
scanf("%f", &my_float);
printf("The value obtained using the float specifier is = %f \n", my_float);
return 0;
}
Did you find this helpful?

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.

C
#include <stdio.h>
int main() {
printf("Learning float specifiers with fixed precision today!\n\n");
float my_float_prec;
printf("Enter a float value here = \n");
scanf("%g", &my_float_prec);
printf("The value obtained using the float specifier with fixed precision is = %g \n", my_float_prec);
return 0;
}
Did you find this helpful?

Unsigned integer specifier#

The following code demonstrates how to input and output unsigned integers.

C
#include <stdio.h>
int main() {
printf("Learning unsigned integer specifiers today!\n\n");
unsigned int my_unsigned_integer;
printf("Enter an unsigned integer value here = \n");
scanf("%u", &my_unsigned_integer);
printf("The value obtained using the unsigned integer specifier is = %u \n", my_unsigned_integer);
return 0;
}
Did you find this helpful?

Hexadecimal specifier#

The following code demonstrates how to input and output hexadecimal numbers.

C
#include <stdio.h>
int main() {
printf("Learning hexadecimal representation specifiers today!\n\n");
int my_hexadecimal;
printf("Enter a hexadecimal here = \n");
scanf("%x", &my_hexadecimal);
printf("The value obtained using the hexadecimal representation specifier is = %x \n", my_hexadecimal);
printf("The value in decimal format is = %d \n", my_hexadecimal);
return 0;
}
Did you find this helpful?

Long integer specifier#

The following code demonstrates how to input and output long integers.

C
#include <stdio.h>
int main() {
printf("Learning long specifiers today!\n\n");
long my_long;
printf("Enter a long value here = \n");
scanf("%ld", &my_long);
printf("The value obtained using the long specifier is = %ld \n", my_long);
return 0;
}
Did you find this helpful?

Unsigned long specifier#

The following code demonstrates how to input and output unsigned long integers.

C
#include <stdio.h>
int main() {
printf("Learning unsigned long specifiers today!\n\n");
unsigned long my_unsigned_long;
printf("Enter an unsigned long value here = \n");
scanf("%lu", &my_unsigned_long);
printf("The value obtained using the unsigned long specifier is = %lu \n", my_unsigned_long);
return 0;
}
Did you find this helpful?

Long long specifier#

The following code demonstrates how to input and output long long integers.

C
#include <stdio.h>
int main() {
printf("Learning long long specifiers today!\n\n");
long long my_long_long;
printf("Enter a long long value here = \n");
scanf("%lld", &my_long_long);
printf("The value obtained using the long long specifier is = %lld \n", my_long_long);
return 0;
}
Did you find this helpful?

Unsigned long long specifier#

The following code demonstrates how to input and output unsigned long long integers.

C
#include <stdio.h>
int main() {
printf("Learning unsigned long long specifiers today!\n\n");
unsigned long long my_unsigned_long_long;
printf("Enter an unsigned long long value here = \n");
scanf("%llu", &my_unsigned_long_long);
printf("The value obtained using the unsigned long long specifier is = %llu \n", my_unsigned_long_long);
return 0;
}
Did you find this helpful?

Double specifier#

The following code demonstrates how to input and output double values.

C
#include <stdio.h>
int main() {
printf("Learning double specifiers today!\n\n");
double my_double;
printf("Enter a double value here = \n");
scanf("%lf", &my_double);
printf("The value obtained using the double specifier is = %lf \n", my_double);
return 0;
}
Did you find this helpful?

Octal specifier#

The following code demonstrates how to input and output octal values.

C
#include <stdio.h>
int main() {
printf("Learning octal representation specifiers today!\n\n");
int my_octal;
printf("Enter an integer for octal representation here = \n");
scanf("%o", &my_octal);
printf("The value obtained using the octal representation specifier is = %o \n", my_octal);
return 0;
}
Did you find this helpful?

String specifier#

The following code demonstrates how to input and output strings.

C
#include <stdio.h>
int main() {
printf("Learning string specifiers today!\n\n");
// add a string with a maximum length of 49
char my_string[50];
printf("Enter a string here = \n");
scanf("%s", my_string);
printf("The value obtained using the string specifier is = %s \n", my_string);
return 0;
}
Did you find this helpful?

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.

C
#include <stdio.h>
int main() {
printf("Printing literal %% character today!\n");
return 0;
}

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, %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.

%f vs %lf#

  • 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.

Portable Specifiers for Correct Types#

To ensure portability across compilers and architectures, use specifiers that match your data type:

size_t

%zu

printf("%zu", n);

ptrdiff_t

%td

printf("%td", diff);

Pointer

%p

printf("%p", ptr);

Wide character

%lc

printf("%lc", wc);

Wide string

%ls

printf("%ls", wstr);

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.

C
#include <stdio.h>
int main() {
int my_int = 42;
float my_float = 3.14159;
printf("Right Justification: %8d\n", my_int);
printf("Left Justification: %-8d\n", my_int);
printf("Shorter Field Width: %d\n", my_int);
printf("Precision Modifier: %.2f\n", my_float);
return 0;
}

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

Explicit Base for Numeric Input#

Use %d for decimal-only input.
Reserve %i for cases where you intentionally want automatic base detection (decimal, octal, or hex).

Always Check Return Values#

scanf returns the number of successfully read items—validate it before using variables:

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!


Written By:
izza ahmad