Skip to Content
Course content

17: Format Specifiers in Depth

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I was working on a small diagnostic tool the other day to track sensor readings from a mock hardware interface. I hit a wall that reminded me why format specifiers are often the most frustrating part of C for people moving from Python or JavaScript. In those languages, the print function just "figures it out." In C, if you lie to printf about what you're handing it, it doesn't complain—it just gives you garbage or crashes your program.

Why is my sensor reading 0?

I started with a simple piece of code to print a temperature reading. I had a double for the precision, but in a rush, I used the wrong specifier. Look at this:

double temp = 25.45;
printf("Current Temp: %d\n", temp);

When I ran this, I didn't get 25. I didn't even get 25.45. I got 0 (or sometimes some massive, random integer depending on the compiler). Why? Because %d tells printf to go to the stack, grab 4 bytes, and treat them as a signed integer. But a double is 8 bytes and stored in a completely different format (IEEE 754). I basically asked the program to read a map of Paris using a guide for New York City.

The fix is obvious: %f for floats and doubles. But let's see what happens when I do that:

printf("Current Temp: %f\n", temp);
// Output: Current Temp: 25.450000

It works, but it's ugly. Nobody wants six trailing zeros on a thermometer display.

Taming the Floating Point Mess

I wanted exactly two decimal places. I remembered there's a way to "clamp" the precision. I tried adding a dot and a number between the percent sign and the type character.

printf("Current Temp: %.2f\n", temp);
// Output: Current Temp: 25.45

That's better. But then I realized my log was becoming a mess because the labels were different lengths. I had "Temp" and "Pressure", and the numbers weren't lining up vertically. It looked like this:

Temp: 25.45
Pressure: 101.32

I wanted a clean column. I decided to try "width" specifiers. I told C I wanted the string to take up exactly 10 characters of space.

printf("%10s: %.2f\n", "Temp", temp);
printf("%10s: %.2f\n", "Pressure", pressure);

Now the text is right-aligned. If I want it left-aligned—which usually looks more natural for labels—I just throw a minus sign in there: %-10s. This tells the compiler: "Reserve 10 spaces, put the text at the start, and pad the rest with spaces."

Peeking at the Metal

Finally, I needed to log the memory address of the sensor buffer to make sure my pointer arithmetic wasn't drifting. I tried using %d again, but addresses are huge and usually represented in hexadecimal. I tried %x, which works for unsigned integers in hex, but for pointers, there's a dedicated specifier: %p.

double *ptr = &temp;
printf("Sensor Address: %p\n", (void *)ptr);

You'll notice I cast ptr to (void *). I do this because %p specifically expects a void pointer. While some compilers let you slide with a double *, being explicit prevents those annoying warnings that pop up when you turn on -Wall.

Here is a quick cheat-sheet of what I ended up using for this tool:

  • %d: Signed integers (the bread and butter).
  • %u: Unsigned integers (use this for things that can't be negative, like memory sizes).
  • %f: Floating point (doubles/floats).
  • %.nf: Float with n decimal places.
  • %s: Strings (null-terminated character arrays).
  • %p: Pointer addresses.
  • %x: Hexadecimal representation.



📋 Practical Task

Building a System Resource Monitor Table

Your task is to create a program that simulates a system resource monitor. You need to print a formatted table that displays a process name, its Process ID (PID), its memory usage in MB, and its memory address.

Requirements:

  • Create a char[] for the process name (e.g., "Kernel"), an int for the PID, a double for memory usage, and a pointer to the memory variable.
  • The output must be aligned in columns.
  • The Process Name should be left-aligned in a 15-character column.
  • The PID should be right-aligned in a 10-character column.
  • The Memory usage should be displayed with exactly 2 decimal places.
  • The Memory address must be printed using the correct pointer specifier.

Example Output Goal:
PROCESS PID MEM(MB) ADDRESS
Kernel 101 12.40 0x7ffeed...
Browser 4022 156.12 0x7ffeed...

Rating
0 0

There are no comments for now.

to be the first to leave a comment.