C Language Neat Tricks #1

The C language holds the potential of being utterly terrifying, which is something I admire greatly. Many beginners, as well as foolhardy travelers from other languages, treat a lot of the C language constructs as absolutes when, in fact, they aren’t. Therefore I present this week’s Lesson, the first in an ongoing series about strange, beautiful, and frightening things in the C language.

This first C Language Neat Trick deals with the format string in a printf() statement.

As a review, the printf() function features a variable number of arguments. The first one is always the format string. That’s followed by a number of arguments equal to the number of placeholders within the format string. The compiler lets you know when you get the numbers wrong, and also when the variable types are used improperly.

Here’s sample code that shows a hoard of printf() statements. Each format string uses one placeholder. Each statement has one argument.

#include <stdio.h>

int main()
{
    const float f = 123.45678;

    printf("%f\n",f);
    printf("%.4f\n",f);
    printf("%.3f\n",f);
    printf("%.2f\n",f);
    printf("%.1f\n",f);
    printf("%.0f\n",f);

    return(0);
}

Here’s sample output:

123.456779
123.4568
123.457
123.46
123.5
123

I’m sure this type output is desired by someone, but that’s not the point of this Lesson.

When you look at the code, you see repetitive statements. Lines 8 through 12 are essentially the same printf() function with only the format string changing in an arithmetic progression: One character in the string goes from 4 down to zero. Some programmers would proclaim, “That calls for a loop!” More timid and inexperienced programmers would counter, “No! It’s a format string! You can’t put it into a loop!”

Well?

A format string is, after all, a string. It can be manipulated. The prototype for the printf() function states it mush be a constant string, or const char *. Could the laws of the C universe be twisted and that format string manipulated?

Here’s my answer:

#include <stdio.h>

int main()
{
    const float f = 123.45678;
    char format[7] = "%. f\n";
    int x;

    printf("%f\n",f);
    for(x=4;x>=0;x--)
    {
        format[2] = '0'+x;
        printf(format,f);
    }

    return(0);
}

The string format is declared at Line 6. It shows a space character where a value should be. That value determines the number of digits to display after the decimal in a floating point number.

At Line 10, the for loop counts backwards from 4 to 0 (inclusive).

The format string is modified at Line 12. The blank is replaced by the value of variable x. That variable is added to character '0', which generates the characters '4' through '0' as the loop counts down. (See this blog post for an explanation.)

In line 13, the string format is inserted into the printf() statement — the compiler apparently doesn’t balk (at least on my machine) — and that string is used to display the value of f.

The code’s output is the same as the original, more proper example. And of course, this example is silly like all my examples. My point is that you can modify the format string in a printf() statement, should the need arise.

Leave a Reply