We have covered simple format specifier for printf and scanf here [C Programming #87: stdio - printf, scanf]. This article tries to give incrementally with example most complex and insane formatting that could be achieved. I don't expect you to remember all of it. My idea to here is to show how beautiful and complex the construct are.
constant width
Say you want to show print something like below. Table of number of something per year.
2010 107 2011 9 2012 22 2013 120 2014 34
Now say i write a C program where the year and number is stored in array of struct.
#include <stdio.h> typedef struct stat_tag { int year; int num; }stat_t; int main() { stat_t list[5] = {{2010, 107}, {2011, 9}, {2012, 22}, {2013, 120}, {2014, 34}}; int i; for(i = 0; i < 5; i++){ printf("%d %d\n", list[i].year, list[i].num); } return 0; }
2010 107 2011 9 2012 22 2013 120 2014 34
If you see the output, it is not properly aligned.
Issue is that we need all the number aligned to its right.
This can be ac hive by specifying the number between %
and d
.
This number represents the width. Since it is constant number it is called constant width.
Now re-writing the above program with the appropriate width.
#include <stdio.h> typedef struct stat_tag { int year; int num; }stat_t; int main() { stat_t list[5] = {{2010, 107}, {2011, 9}, {2012, 22}, {2013, 120}, {2014, 34}}; int i; for(i = 0; i < 5; i++){ printf("%d %3d\n", list[i].year, list[i].num); } return 0; }
2010 107 2011 9 2012 22 2013 120 2014 34
Now the o/p exactly looks as we would like it to be.
variable width
In the above C program we assumed that the width as constant by looking at the numbers.
Say in some program we don't know the numbers before hand.
Then variable width specifier comes into help.
Between %
and d
we need to put *
suggesting that width is variable.
Now the width is passed as one of the argument to printf.
Hence for %*d
we need to pass two arguments first the width and second the number itself to be printed.
Now re-writing the same above program to make it more generic.
#include <stdio.h> typedef struct stat_tag { int year; int num; }stat_t; int main() { stat_t list[5] = {{2010, 1072345}, {2011, 9}, {2012, 22}, {2013, 120}, {2014, 34}}; int i, width = 0, tw = 0; char temp[100]; /* This loop is for width calculation */ /* Note how snprintf is used to find number of digits in a number */ for(i = 0; i < 5; i++){ tw = snprintf(temp, 100, "%d", list[i].num); if(tw > width) { width = tw; } } for(i = 0; i < 5; i++){ printf("%d %*d\n", list[i].year, width, list[i].num); } return 0; }
2010 1072345 2011 9 2012 22 2013 120 2014 34
You can try changing the num and see how the o/p gets adapted.
left or right justify
Say you want to print the some items in tabular format, say something like below
James Smith Michael Smith Maria Garcia Maria Rodriguez
To make something like above formatting we need to start second name at same place.
Hence First Name and spaces following it form a const width.
We know the format specifier for string is %s
.
Above const width can be specified by adding a number in between %
and s
.
Example %20s
, here it will print with the constant width 20 characters.
And we want it left justified we need to use -
.
What would happen if the string is bigger than 20 characters, it would overflow the width boundary.
Let me give the example by storing the first name and second name in struct
.
#include <stdio.h> typedef struct name_tag{ char *first; char *second; }name_t; int main() { name_t list[4] = {{"James", "Smith"}, {"Michael","Smith"}, {"Maria", "Garcia"}, {"Maria", "Rodriguez"}}; int i; for(i = 0; i < 4; i++) { printf("%-15s %-15s\n", list[i].first, list[i].second); } return 0; }
James Smith Michael Smith Maria Garcia Maria Rodriguez
Same thing could be applied to numbers as well, but it is customary to align number right justified and string left justified.
zero fill
Lets take another example where you want numbers as follows.
2010 107 2011 009 2012 022 2013 120 2014 034
See that each number is padded with zero.
This can be easily achieved by using 0
in between %
and d
for zero padding.
#include <stdio.h> typedef struct stat_tag { int year; int num; }stat_t; int main() { stat_t list[5] = {{2010, 107}, {2011, 9}, {2012, 22}, {2013, 120}, {2014, 34}}; int i; for(i = 0; i < 5; i++){ printf("%d %03d\n", list[i].year, list[i].num); } return 0; }
2010 107 2011 009 2012 022 2013 120 2014 034
compulsory +
Now say we have following table to be formatted.
2010 +107 2011 -9 2012 +22 2013 -120 2014 +34
Above formatting can be achieved by mentioning + in between %
and d
.
#include <stdio.h> typedef struct stat_tag { int year; int num; }stat_t; int main() { stat_t list[5] = {{2010, +107}, {2011, -9}, {2012, +22}, {2013, -120}, {2014, +34}}; int i; for(i = 0; i < 5; i++){ printf("%d %+4d\n", list[i].year, list[i].num); } return 0; }
2010 +107 2011 -9 2012 +22 2013 -120 2014 +34
Note that here width also includes the +/- sign also.
precision
This is applicable to floating point number. Say i want to print following table.
2010 10.7 2011 9.0 2012 22.1 2013 120.3 2014 34.0
If you see the above number number following .
tells the precision of it.
Here width of precision is 1. Above formatting can be achieved as follows.
#include <stdio.h> typedef struct stat_tag { int year; float num; }stat_t; int main() { stat_t list[5] = {{2010, 10.7}, {2011, 9.0}, {2012, 22.1}, {2013, 120.3}, {2014, 34.0}}; int i; for(i = 0; i < 5; i++){ printf("%d %6.1f\n", list[i].year, list[i].num); } return 0; }
2010 10.7 2011 9.0 2012 22.1 2013 120.3 2014 34.0
Note here the width is total width of number including all numbers and .
entire spec
Overall spec can be found here - http://man7.org/linux/man-pages/man3/printf.3.html I don't want to repeat it as such this article is quite big enough.
Links
- Next Article - C Programming #89: printf - %n specifier
- Previous Article - C Programming #87: stdio - printf, scanf
- All Article - C Programming
No comments :
Post a Comment