Output Format Strings

When making use of functions such as printf where a format string must be specified, each variable type has a code associated with it to be used in the format string, to specify that this particular type of variable will appear as a parameter. These codes specifying the variable types must be included in the format string in the same order that the variables appear as parameters.

The following code illustrates this.

char alpha = 'd';
int num1 = 123;
float radius = 4.0f;
printf("The letter %c lives at %d North St. with the number %f.",alpha,num1,radius);

The following table gives the format specifiers for the types we have introduced so far. In each case one can specify not only the type of the variable to be displayed, but the way that it will be displayed.

Format Type Specifier Variable Type Displayed As
d or i int decimal (base 10)
o unsigned int octal (base 8)
u unsigned int decimal (base 10)
x or X unsigned int hexadecimal (base 16)
f or F float or double decimal point but no exponent
e or E float or double decimal point and exponent
g or G float or double uses exponent if needed
a or A float or double hexadecimal (base 16) floating point
c int or char character
s array of char's character string
p pointer address in hexadecimal

We simplify somewhat here. Actually the format specifier %c expects a variable of type int. However if one supplies a char this is automatically viewed as an int by C via a process called type casting which we will learn about later. Thus it does no harm at this stage to think of %c as specifying a variable of type char. The usefulness of specifying an int is that you can display a character whose character code is given by that int.

For the hexadecimal display formats, the difference between the lower and upper case format specifiers is that any letters in the hexadecimal number are displayed in lower or upper case respectively.

Again, all of the floating point types actually expect double arguments, however a variable of type float is automatically type cast by C to a double.

For the floating point types, computations such as 0 divided by 0 do not result in a number. The result of such a computation is displayed as nan or NAN, depending on whether a lower or upper case format specifier was used. Similarly if a large number is divided by a small number, the result may be too large to store and is treated as infinity. This is displayed as inf or INF, again depending on the case of the format specifier.

Sometimes when displaying or outputing data, one wishes to align the display of the data so it looks visually appealing. Since numbers may be of varying lengths, it is useful to know exactly how many characters have been output so far by the current output statement. This is done with the format specifier %n. Instead of expecting a variable to be output, the number of characters displayed so far is put into the corresponding variable, which is expected to be of type int.

Of course if an int is short, long or long long you must tell C this too. One simply puts an h in front of the letter from the table above to specify short. (The letter h is used since it is the second letter of the word short, and s is already used for something else.)

One specifies long and long long in a similar way by prepending l or ll respectively.

The inverse operation to displaying a character with a given integer character code, is to display the integer character code of a given character. This is done by prepending hh to one of the format specifiers which expects an int. This causes it to expect a char instead, whose character code is then displayed as an integer.

We summarize in a table.
Format Size Specifier Size
h short
l long
ll long long
hh (convert char to int code)

Of course C would not be very flexible if it did not allow you to specify the number of digits that should be displayed when outputing a number, or the number of characters to display if outputing a string. This is called the precision. So far we have merely shown how to construct format specifiers of the following kind:

% size type

However, numerous other optional details can be specified, such as the precision. Along with all optional components, a format specifier may look as follows-na:

% flags width .precision size type

The precision is simply a whole number giving the number of decimal places which should be displayed for format types a, A, e, E, f, F, the maximum number of significant digits for types g, G, the minimum number of characters for types d, i, o, u, x, X or the maximum number of characters to be printed for type s. Leading zeroes are added if an integer falls short of the specified minimum. The default precision for integer types is 1, whilst for floating point types except a, A it is 6. For the two exceptions it is taken to be sufficiently large to distinguish values of type double except when the exponent is a power of 2, in which case an exact value can be and is output.

If one does not wish to specify once and for all what precision to use in a particular output statement, one can specify the precision with a variable of type int. Instead of specifying the precision with a number, one simply uses an asterisk "*" in its place and includes an int in the list of parameters of the output function, corresponding to that position in the format string.

Here are some examples making use of a format string with a precision specified:

    float scale = 1.57f;
    int num2 = 123;
    int prec = 4;
    printf("Scale is %.5a\n",scale);      //Scale is 0xc.8f5c3p-3
    printf("Scale is %.5E\n",scale);      //Scale is 1.57000525E+00
    printf("Scale is %.5f\n",scale);      //Scale is 1.57000
    printf("Scale is %.5g\n",scale);      //Scale is 1.57
    printf("Scale is %.*f\n",prec,scale); //Scale is 1.5700	
    printf("Num2 is %.5d\n",num2);        //Num2 is 00123
    printf("Num2 is %.50\n",num2);        //Num2 is 00173
    printf("Num2 is %.5x\n",num2);        //Num2 is 0007b

The width specifies the minimum number of characters to be output for this format specification. If it falls short, spaces are used to pad the left hand side. If the width is a negative number, any padding is added to the right. Specifying the width is useful for producing output appearing in tables or tabbed rows-na. Again an asterisk can be used to specify that the width is given by a variable of type int.

Here are some examples making use of a width:

    printf("Scale is %7.3f\n",scale); //Scale is   1.570
    printf("Scale is %5.d\n",num2);   //Scale is   123

Finally one has various flags to modify other behaviour. The minus sign of a negative width is already one such flag. It specifies that the data for the field should be left aligned instead of right aligned. The other flags are:

+ specifies for a number, that a sign should always be included, even if it is positive.

a space specifies that a space should be prepended to the output of a number if the sign is positive. Of course this flag is ignored if the previous flag is also used.

# specifies that a leading zero be used for an octal number (format specifiers o and O), a leading 0x or 0X be used for a hexadecimal number (format specifiers x and X) or that a decimal point always be included for the floating point types.

0 specifies that leading zeroes should be used to pad a number rather than spaces. Of course a "-" flag or a specified precision for an integer type trumps a 0 flag.

Here are some examples:

    printf("Scale is %#.0f\n",scale); //Scale is 2.
    printf("Num2 is %-5.d!\n",num2);  //Num2 is 123  !
    printf("Num2 is %+i\n",num2);     //Num2 is +123
    printf("Num2 is %#o\n",num2);     //Num2 is 0173

Finally we note that to output a % sign, one simply puts %% in the format string:

    printf("Here is a %% sign.\n");   //Here is a % sign.