What is the meaning of "%-*.*s" in a printf format string? - c

#define FMT "%-*.*s e = %6ld, chars = %7ld, stat = %3u: %c %c %c %c\n"
This macro is passed into the printf function. What does %-*.*s mean?

You can read the manual page for printf. But it's more like a law text than a tutorial, so it will be hard to understand.
I didn't know *.* and had to read the man page myself. It's interesting. Let's start with a simple printf("%s", "abc"). It will print the string abc.
printf("%8s", "abc") will print abc, including 5 leading spaces: 8 is the "field width". Think of a table of data with column widths so that data in the same column is vertically aligned. The data is by default right-aligned, suitable for numbers.
printf("%-8s", "abc") will print abc , including 5 trailing spaces: the minus indicates left alignment in the field.
Now for the star:
printf("%-*s", 8, "abc") will print the same. The star indicates that the field width (here: 8) will be passed as a parameter to printf. That way it can be changed programmatically.
Now for the "precision", that is:
printf("%-*.10s", 8, "1234567890123") will print only 1234567890, omitting the last three characters: the "precision" is the maximum field width in case of strings. This is one of the rare cases (apart from rounding, which is also controlled by the precision value) where data is truncated by printf.
And finally
printf("%-*.*s", 8, 10, "1234567890123") will print the same as before, but the maximum field width is given as a parameter, too.

Related

format string used in printf function in C programming

In this code:
sprint(buf_ptr, "%.*s", MAX_BUF_LEN, desc);
what does "%.*s", mean? what does "%20.20s" and "%.28s" mean- in snprintf?
In the %*s format specification, the s indicates that the argument will be a (null-terminated) character string and the * (width specifier) says that the field width is given as the argument immediately preceding the string.
In your other examples, the width specifier(s) is(are) given as fixed values.
Actually, in the printf formats you give, there are both width and precision specifiers: the width is the value before the period and the precision is after. For strings, the width is the minimum output field size (space padded if necessary) and the precision is the maximum number of characters to print (string will be truncated, if necessary). In either case, if a * is specified for either, it will be assumed to be in the list of arguments (as an integer) immediately before the string it applies to.
what does "%.*s", mean?
desc, below, is a character pointer that need not point to a string1. Printing will continue until MAX_BUF_LEN charters (the precision) are printed or until a null character is read - which ever comes first.
sprint(buf_ptr, "%.*s", MAX_BUF_LEN, desc);
what does "%20.20s" ... mean- in snprintf?
Let us use two different values for clarity: "%19.21s".
desc is a character pointer that need not be a string. Printing will continue until 21 charters are printed or until a null character is read - which ever comes first. If the the number of charters to print is less than 19 (the minimum width), pad on the left with spaces to make at least 19 characters total.
sprint(buf_ptr, "%19.21s", desc);
what does ... "%.28s" mean- in snprintf?
Just like sprint(buf_ptr, "%.*s", 28, desc);
Loosely speaking, think of "%minimum.maximum s"
1 A string is a contiguous sequence of characters terminated by and including the first null character.

Why does my program seem to go over some numbers? [duplicate]

I'm trying to find a good way to print leading 0, such as 01001 for a ZIP Code. While the number would be stored as 1001, what is a good way to do it?
I thought of using either case statements or if to figure out how many digits the number is and then convert it to an char array with extra 0's for printing, but I can't help but think there may be a way to do this with the printf format syntax that is eluding me.
printf("%05d", zipCode);
The 0 indicates what you are padding with and the 5 shows the width of the integer number.
Example 1: If you use "%02d" (useful for dates) this would only pad zeros for numbers in the ones column. E.g., 06 instead of 6.
Example 2: "%03d" would pad 2 zeros for one number in the ones column and pad 1 zero for a number in the tens column. E.g., number 7 padded to 007 and number 17 padded to 017.
The correct solution is to store the ZIP Code in the database as a STRING. Despite the fact that it may look like a number, it isn't. It's a code, where each part has meaning.
A number is a thing you do arithmetic on. A ZIP Code is not that.
You place a zero before the minimum field width:
printf("%05d", zipcode);
sprintf(mystring, "%05d", myInt);
Here, "05" says "use 5 digits with leading zeros".
If you are on a *nix machine:
man 3 printf
This will show a manual page, similar to:
0 The value should be zero padded. For d, i, o, u, x, X, a, A, e,
E, f, F, g, and G conversions, the converted value is padded on
the left with zeros rather than blanks. If the 0 and - flags
both appear, the 0 flag is ignored. If a precision is given
with a numeric conversion (d, i, o, u, x, and X), the 0 flag is
ignored. For other conversions, the behavior is undefined.
Even though the question is for C, this page may be of aid.
ZIP Code is a highly localised field, and many countries have characters in their postcodes, e.g., UK, Canada. Therefore, in this example, you should use a string / varchar field to store it if at any point you would be shipping or getting users, customers, clients, etc. from other countries.
However, in the general case, you should use the recommended answer (printf("%05d", number);).
There are two ways to output your number with leading zeroes:
Using the 0 flag and the width specifier:
int zipcode = 123;
printf("%05d\n", zipcode); // Outputs 00123
Using the precision specifier:
int zipcode = 123;
printf("%.5d\n", zipcode); // Outputs 00123
The difference between these is the handling of negative numbers:
printf("%05d\n", -123); // Outputs -0123 (pad to 5 characters)
printf("%.5d\n", -123); // Outputs -00123 (pad to 5 digits)
ZIP Codes are unlikely to be negative, so it should not matter.
Note however that ZIP Codes may actually contain letters and dashes, so they should be stored as strings. Including the leading zeroes in the string is straightforward so it solves your problem in a much simpler way.
Note that in both examples above, the 5 width or precision values can be specified as an int argument:
int width = 5;
printf("%0*d\n", width, 123); // Outputs 00123
printf("%.*d\n", width, 123); // Outputs 00123
There is one more trick to know: a precision of 0 causes no output for the value 0:
printf("|%0d|%0d|\n", 0, 1); // Outputs |0|1|
printf("|%.0d|%.0d|\n", 0, 1); // Outputs ||1|
printf allows various formatting options.
Example:
printf("leading zeros %05d", 123);
You will save yourself a heap of trouble (long term) if you store a ZIP Code as a character string, which it is, rather than a number, which it is not.
More flexible..
Here's an example printing rows of right-justified numbers with fixed widths, and space-padding.
//---- Header
std::string getFmt ( int wid, long val )
{
char buf[64];
sprintf ( buf, "% *ld", wid, val );
return buf;
}
#define FMT (getFmt(8,x).c_str())
//---- Put to use
printf ( " COUNT USED FREE\n" );
printf ( "A: %s %s %s\n", FMT(C[0]), FMT(U[0]), FMT(F[0]) );
printf ( "B: %s %s %s\n", FMT(C[1]), FMT(U[1]), FMT(F[1]) );
printf ( "C: %s %s %s\n", FMT(C[2]), FMT(U[2]), FMT(F[2]) );
//-------- Output
COUNT USED FREE
A: 354 148523 3283
B: 54138259 12392759 200391
C: 91239 3281 61423
The function and macro are designed so the printfs are more readable.
If you need to store the ZIP Code in a character array, zipcode[], you can use this:
snprintf(zipcode, 6, "%05.5d", atoi(zipcode));

Printing number of spaces

Is there a way to specify the number of spaces using a variable?
For example lets say I have a basic print statement:
printf("%5d",someNumber);
This will print 5 spaces then the number. Is there a way that would let me declare a variable var = 5, and use a variable to determine spacing instead? The reason i'm asking is because I'm trying to control the number of spaces after each iteration of a loop to format data a certain way
Try:
printf("%*d", width, someNumber);
You can find more info by man 3 printf
"%5d" prints at least 5 characters. Leading spaces are first printed as needed, then the '-' sign, if needed, then the digits.
To print an int with at least n characters,use '*', the minimum field width:
printf("%*d", n, someNumber);
To print n spaces only, use
printf("%*s", n, "");
The format string is just that: a string. You can build your own with sprintf() e.g.:
sprintf(frmt,"%%%dd",iterator);
If iterator = 3 wil give the format string "%3d" which you can use in printf() like e.g.:
printf(frmt,some_number);
(The variable field width posted by Jesse Chen is not necessarily available everywhere)

What does the %*s format specifier mean?

In some code that I have to maintain, I have seen a format specifier %*s . Can anybody tell me what this is and why it is used?
An example of its usage is like:
fprintf(outFile, "\n%*s", indent, "");
It's used to specify, in a dynamic way, what the width of the field is:
The width is not specified in the format string, but as an additional
integer value argument preceding the
argument that has to be formatted.
so "indent" specifies how much space to allocate for the string that follows it in the parameter list.
So,
printf("%*s", 5, "");
is the same as
printf("%5s", "");
It's a nice way to put some spaces in your file, avoiding a loop.
Don't use "%*s" on a buffer which is not NULL terminated (packed) thinking that it will print only "length" field.
The format specifier %4s outputs a String in a field width of 4—that is, printf displays the value with at least 4 character positions.
If the value to be output is less than 4 character positions wide, the value is right justified in the field by default.
If the value is greater than 4 character positions wide, the field width expands to accommodate the appropriate number of characters.
To left justify the value, use a negative integer to specify the field width.
References: Java™ How To Program (Early Objects), Tenth Edition
When used in printf and fprintf:
printf("%*s", 4, myValue); is equivalent to printf("%4s", myValue);
It displays the variable with minimum width, rest right-justified spaces. To left-justify the value, use a negative integer.
When used in scanf and sscanf:
/* sscanf example */
#include <stdio.h>
int main ()
{
char sentence []="Rudolph is 12 years old";
char str [20];
int i;
sscanf (sentence,"%s %*s %d",str,&i);
printf ("%s -> %d\n",str,i);
return 0;
}
Output:
Rudolph -> 12
It is used to ignore a string.
* Causes fprintf to pad the output until it is n characters wide, where n is an integer value stored in the a function argument just preceding that represented by the modified type.
printf("%*d", 5, 10) //will result in "10" being printed with a width of 5.
http://www.cplusplus.com/reference/clibrary/cstdio/printf/
The width is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted.
e.g: printf("%*s", 4, myValue); is equivelant to printf("%4s", myValue);.

Printing leading 0's in C

I'm trying to find a good way to print leading 0, such as 01001 for a ZIP Code. While the number would be stored as 1001, what is a good way to do it?
I thought of using either case statements or if to figure out how many digits the number is and then convert it to an char array with extra 0's for printing, but I can't help but think there may be a way to do this with the printf format syntax that is eluding me.
printf("%05d", zipCode);
The 0 indicates what you are padding with and the 5 shows the width of the integer number.
Example 1: If you use "%02d" (useful for dates) this would only pad zeros for numbers in the ones column. E.g., 06 instead of 6.
Example 2: "%03d" would pad 2 zeros for one number in the ones column and pad 1 zero for a number in the tens column. E.g., number 7 padded to 007 and number 17 padded to 017.
The correct solution is to store the ZIP Code in the database as a STRING. Despite the fact that it may look like a number, it isn't. It's a code, where each part has meaning.
A number is a thing you do arithmetic on. A ZIP Code is not that.
You place a zero before the minimum field width:
printf("%05d", zipcode);
sprintf(mystring, "%05d", myInt);
Here, "05" says "use 5 digits with leading zeros".
If you are on a *nix machine:
man 3 printf
This will show a manual page, similar to:
0 The value should be zero padded. For d, i, o, u, x, X, a, A, e,
E, f, F, g, and G conversions, the converted value is padded on
the left with zeros rather than blanks. If the 0 and - flags
both appear, the 0 flag is ignored. If a precision is given
with a numeric conversion (d, i, o, u, x, and X), the 0 flag is
ignored. For other conversions, the behavior is undefined.
Even though the question is for C, this page may be of aid.
ZIP Code is a highly localised field, and many countries have characters in their postcodes, e.g., UK, Canada. Therefore, in this example, you should use a string / varchar field to store it if at any point you would be shipping or getting users, customers, clients, etc. from other countries.
However, in the general case, you should use the recommended answer (printf("%05d", number);).
There are two ways to output your number with leading zeroes:
Using the 0 flag and the width specifier:
int zipcode = 123;
printf("%05d\n", zipcode); // Outputs 00123
Using the precision specifier:
int zipcode = 123;
printf("%.5d\n", zipcode); // Outputs 00123
The difference between these is the handling of negative numbers:
printf("%05d\n", -123); // Outputs -0123 (pad to 5 characters)
printf("%.5d\n", -123); // Outputs -00123 (pad to 5 digits)
ZIP Codes are unlikely to be negative, so it should not matter.
Note however that ZIP Codes may actually contain letters and dashes, so they should be stored as strings. Including the leading zeroes in the string is straightforward so it solves your problem in a much simpler way.
Note that in both examples above, the 5 width or precision values can be specified as an int argument:
int width = 5;
printf("%0*d\n", width, 123); // Outputs 00123
printf("%.*d\n", width, 123); // Outputs 00123
There is one more trick to know: a precision of 0 causes no output for the value 0:
printf("|%0d|%0d|\n", 0, 1); // Outputs |0|1|
printf("|%.0d|%.0d|\n", 0, 1); // Outputs ||1|
printf allows various formatting options.
Example:
printf("leading zeros %05d", 123);
You will save yourself a heap of trouble (long term) if you store a ZIP Code as a character string, which it is, rather than a number, which it is not.
More flexible..
Here's an example printing rows of right-justified numbers with fixed widths, and space-padding.
//---- Header
std::string getFmt ( int wid, long val )
{
char buf[64];
sprintf ( buf, "% *ld", wid, val );
return buf;
}
#define FMT (getFmt(8,x).c_str())
//---- Put to use
printf ( " COUNT USED FREE\n" );
printf ( "A: %s %s %s\n", FMT(C[0]), FMT(U[0]), FMT(F[0]) );
printf ( "B: %s %s %s\n", FMT(C[1]), FMT(U[1]), FMT(F[1]) );
printf ( "C: %s %s %s\n", FMT(C[2]), FMT(U[2]), FMT(F[2]) );
//-------- Output
COUNT USED FREE
A: 354 148523 3283
B: 54138259 12392759 200391
C: 91239 3281 61423
The function and macro are designed so the printfs are more readable.
If you need to store the ZIP Code in a character array, zipcode[], you can use this:
snprintf(zipcode, 6, "%05.5d", atoi(zipcode));

Resources