Format Strings
Introduction
Formatting data correctly during input/output (I/O) operations is essential for clear communication between computers. In C, format strings offer a powerful yet compact way to control this formatting. Many new C developers initially find format specifiers perplexing. For example:
printf("%02X", 15);
What exactly does %02X mean? This article clarifies such specifiers and demonstrates their usage through practical examples.
Numeric Representations: Decimal, Octal, Hexadecimal
We can represent numbers in different numeric systems easily:
#include <stdio.h>
int main() {
int number = 255;
/* We can write 255 as hex or octal. */
if (number != 0xff || number != 0377) {
return 1;
}
printf("Decimal: %d\n", number);
printf("Octal: %o\n", number);
printf("Hex: %x\n", number);
printf("Capital hex: %X\n", number);
return 0;
}
output:
❯ gcc file.c && ./a.out
Decimal: 255
Octal: 377
Hex: ff
Capital hex: FF
Floating-Point Precision
Control floating-point precision easily:
#include <stdio.h>
int main() {
float number = 3.141592;
printf("Float: %0.0f\n", number);
printf("Float: %0.1f\n", number);
printf("Float: %0.2f\n", number);
return 0;
}
output:
❯ gcc file.c && ./a.out
Float: 3
Float: 3.1
Float: 3.14
Syntax: %.[precision]f
Padding with Zeroes
Use zero-padding to maintain numeric alignment:
#include <stdio.h>
int main() {
float number = 3.141592;
printf("%03.0f\n", number); // 003
printf("%05.1f\n", number); // 003.1
printf("%06.2f\n", number); // 003.14
return 0;
}
output:
❯ gcc file.c && ./a.out
003
003.1
003.14
Syntax: %0[width].[precision]f
If zero-padding is not specified, spaces are used instead:
printf("%3.0f\n", 3.14); // ' 3'
Character as Numeric
View numeric ASCII values:
#include <stdio.h>
int main() {
printf("%c: %d\n", 'G', 'G');
return 0;
}
output:
❯ gcc file.c && ./a.out
G: 71
String Alignment
Ensure neat alignment in output:
#include <stdio.h>
int main() {
char *a = "some value";
char *b = "some longer value";
printf("%7s: %s\n", "Normal", a);
printf("%7s: %s\n", "Long", b);
return 0;
}
output:
❯ gcc file.c && ./a.out
Normal: some value
Long: some longer value
Use left-alignment with -:
#include <stdio.h>
int main() {
char *str = "value";
printf("%5s: %-10s\n", "Left", str);
printf("%5s: %10s\n", "Rigth", str);
return 0;
}
output:
❯ gcc file.c && ./a.out
Left: value
Rigth: value
Scientific Notation
Simplify representation of large/small numbers:
#include <stdio.h>
int main() {
double number = 2E4;
printf("Decimal: %.0f\n", number);
printf("Scientific: %.0E\n", number);
return 0;
}
output:
❯ gcc file.c && ./a.out
Decimal: 20000
Scientific: 2E+04
String Truncation
Limit string length neatly:
#include <stdio.h>
int main() {
char *long_str = "very very very very long string";
printf("%10s: %s\n", "Normal", long_str);
printf("%10s: %.10s\n", "Truncated", long_str);
return 0;
}
output:
❯ gcc file.c && ./a.out
Normal: very very very very long string
Truncated: very very
Using % Literal
To include a % character literally:
#include <stdio.h>
int main() {
int number = 85;
printf("%d%%\n", number);
return 0;
}
output:
❯ gcc file.c && ./a.out
85%
Forcing Number Sign
Explicitly indicate positive numbers:
#include <stdio.h>
int main() {
float negative = -1.5;
float positive = 1.5;
printf("Negative: %+.2f\n", negative);
printf("Positive: %+.2f\n", positive);
return 0;
}
output:
❯ gcc file.c && ./a.out
Negative: -1.50
Positive: +1.50
Specifying padding dynamically
Specify padding as argument:
#include <stdio.h>
int main() {
const char *s = "Hi";
int w1 = 5, w2 = 10;
printf("'%*s'\n", w1, s);
printf("'%*s'\n", w2, s);
return 0;
}
output:
❯ gcc file.c && ./a.out
' Hi'
' Hi'
Conclusion
C's format strings are an essential skill for effective debugging and displaying information. With practice, these specifiers quickly become second nature, greatly enhancing readability and correctness in your code.