The following page will list various tips and tricks on using the printf() function. I recommend copying those examples and trying them out for yourself. I also encourage You to try modify some lines or values and see what happens.
Every code example has some accompanying text, explaining what the good and bad sides of things might be. There are also some recommendations and alternative solutions provided to improve even further.
Printing text
1 2 3 4 5 6 7 8 |
#include <stdio.h> int main(void) { printf("Hello!"); printf("How are you?"); return 0; } |
1 2 3 4 5 6 7 8 |
#include <stdio.h> int main(void) { printf("Hello!\n"); printf("How are you?\n"); return 0; } |
1 2 3 4 5 6 7 |
#include <stdio.h> int main(void) { printf("Hello!\nHow are you?\n"); return 0; } |
1 2 3 4 5 6 7 8 |
#include <stdio.h> int main(void) { puts("Hello!"); puts("How are you?"); return 0; } |
Printing values from variables
To print values in C, we only need to know the data type of the variable, the variable’s name and where do we intend to place this value. In a sense, it’s quite a basic operation.
1 2 3 4 5 6 7 8 9 |
#include <stdio.h> int main(void) { char name[] = "Dolores"; int number = 21; printf("%s! You're number %d on the waiting list\n", name, number); return 0; } |
As a first example, we’ll print two values from two different types of variables. It’s important to make sure that we use the correct format (%d for integer, %s for string) and that the variables are correctly ordered after the format. The values from the variables are placed into the text from left to right (in the order of appearance). When an invalid format for the variable is used, a compiler warning is given. This means that it will still compile, however the result might be unexpected.
1 2 3 4 5 6 7 8 9 |
#include <stdio.h> int main(void) { float value = 3.33; printf("The value is %f\n", value); printf("The value with limited precision is %.2f\n", value); return 0; } |
A more difficult situation comes from real numbers. It’s often advisable to limit the number of places after the comma, so not to panic the user and make the output pleasing.
1 2 3 4 5 6 7 8 |
#include <stdio.h> int main(void) { float value = 994.331; printf("The value is %f\n", value); return 0; } |
You must also be careful with how much precision a variable can hold. It is not possible to represent all real numbers in a digital form without some loss. This is due to the binary storage methods that we use with computers. One of the ways to get around this would be to use a data type with more precision (e.g. double) or even storing floating point numbers as integers and converting as necessary. The latter is actually how banks often do it.
Padding and aligning
There are often scenarios where just printing a value within a line of text will not be enough. This is often the case with displaying tables where aligning fields becomes necessary.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <stdio.h> int main(void) { char *names[] = {"Ott", "Dolores", "Madis"}; int employeeNum[] = {7, 19, 2123}; int ages[] = {22, 19, 53}; int i; for (i = 0; i < 3; i++) { printf("%s\t%d\t%d\n", names[i], ages[i], employeeNum[i]); } return 0; } |
The most primitive way to do this is using the tabular or \t within the code. This will align the fields to some predesignated tab stops within the terminal itself.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <stdio.h> int main(void) { char *names[] = {"Ott", "Dolores", "Johanna-Maria"}; int employeeNum[] = {7, 19, 2123}; int ages[] = {22, 19, 53}; int i; for (i = 0; i < 3; i++) { printf("%s\t%d\t%d\n", names[i], ages[i], employeeNum[i]); } return 0; } |
However as soon as the length of the field starts to differ enough so that they go to different tab stops, everything breaks. Those tab stops are usually read from the left and the length of one is 4 characters.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <stdio.h> int main(void) { char *names[] = {"Ott", "Dolores", "Johanna-Maria"}; int employeeNum[] = {7, 19, 2123}; int ages[] = {22, 19, 53}; float wages[] = {13, 8.95, 10.1}; int i; for (i = 0; i < 3; i++) { printf("%-13s %3d %06d %5.2f\n", names[i], ages[i], employeeNum[i], wages[i]); } return 0; } |
Let’s look at a more complex solutions where we use length modifiers for our variables. We’ve also added a column for wages to show floating point numbers.
- First of all we should fix how much space is there for each field – e.g. %13s, %3d, %6d. This number in between will say how many spaces to designate for each field. If the value is shorter, it will print whitespace instead. If it is longer however, it will still misalign everything else.
- Secondly we use left alignment for text: %-13s. The minus symbol is the key here to left align text. Without any modifier the text would be aligned to the right. Usually we want to align text to the left and numbers to the right.
- The third new format we’re using is %06d. This indicates, that the number will be given 6 characters of space, just as before, however instead of whitespace we will print zeros.
- For the last one, we’ll look at floating point formatting (%5.2f). This means that we will always print two digits after the comma, even if they were zeros. The number before indicates how many places everything will get together, including the floating point separator. 5 in this case would mean that we get 2 numbers before and two number after the comma and one is reserved for the separator (point).
Useful tricks
Using the tricks we’ve learned so far, we can also create headers for our tables. In C programs, it doesn’t matter if we put actual variables or just constants in printf statement after the format. We’ll use this property to align the text in the header with the rest of the table.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <stdio.h> int main(void) { char *names[] = {"Ott", "Dolores", "Johanna-Maria"}; int employeeNum[] = {7, 19, 2123}; int ages[] = {22, 19, 53}; float wages[] = {13, 8.95, 10.1}; int i; printf("%-13s %3s %6s %5s\n", "name", "age", "id #", "wage"); for (i = 0; i < 3; i++) { printf("%-13s %3d %06d %5.2f\n", names[i], ages[i], employeeNum[i], wages[i]); } return 0; } |
The solution is becoming quite impressive already, however there are still a few issues. One of which is changing the length of the field. Currently we need to do it in two places, however it would be preferred to do it in only one place, when needed. Let’s take a look at achieving this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include <stdio.h> #define F_LEN_NAME 13 #define F_LEN_AGE 3 #define F_LEN_ID 6 #define F_LEN_WAGE 5 int main(void) { char *names[] = {"Ott", "Dolores", "Johanna-Maria"}; int employeeNum[] = {7, 19, 2123}; int ages[] = {22, 19, 53}; float wages[] = {13, 8.95, 10.1}; int i; printf("%-*s %*s %*s %*s\n", F_LEN_NAME, "name", F_LEN_AGE, "age", F_LEN_ID, "id #", F_LEN_WAGE, "wage"); for (i = 0; i < 3; i++) { printf("%-*s %*d %0*d %*.2f\n", F_LEN_NAME, names[i], F_LEN_AGE, ages[i], F_LEN_ID, employeeNum[i], F_LEN_WAGE, wages[i]); } return 0; } |
The length of the field can be given using a variable or a constant instead of just writing it into the format. To do this, we will write an asterksk (*) instead of the actual number. In this case, the length of the field will be taken from the arguments of that printf statement. First value in this case needs to be the length, given as #define constants, and the second value is from the actual variable. Now all we need to do is change the constant and it will be easy to modify the table column widths.
The next step in this would be making these columns either dynamically changing in widths or just cutting off the excess if a value is too long. To achieve the first, we would need to replace the constants with variables and we would need to scan the entire column for the longest value. The second option would force us to print characters, one at a time, until we run out of room. Which is better out of all the given ideas and solutions depends on the task at hand.
I’d also like to point out, that due to the line length limit, we’re splitting this line to make it pleasing to the eye and of course easier to fix if we miss something. Information about this can be found in the coding style.