What does "%.*s" mean in printf? - c

I got a code snippet in which there is a
printf("%.*s\n")
what does the %.*s mean?

You can use an asterisk (*) to pass the width specifier/precision to printf(), rather than hard coding it into the format string, i.e.
void f(const char *str, int str_len)
{
printf("%.*s\n", str_len, str);
}

More detailed here.
integer value or * that specifies minimum field width. The result is padded with space characters (by default), if required, on the left when right-justified, or on the right if left-justified. In the case when * is used, the width is specified by an additional argument of type int. If the value of the argument is negative, it results with the - flag specified and positive field width. (Note: This is the minimum width: The value is never truncated.)
. followed by integer number or *, or neither that specifies precision
of the conversion. In the case when * is used, the precision is
specified by an additional argument of type int. If the value of this
argument is negative, it is ignored. If neither a number nor * is
used, the precision is taken as zero. See the table below for exact
effects of precision.
So if we try both conversion specification
#include <stdio.h>
int main() {
int precision = 8;
int biggerPrecision = 16;
const char *greetings = "Hello world";
printf("|%.8s|\n", greetings);
printf("|%.*s|\n", precision , greetings);
printf("|%16s|\n", greetings);
printf("|%*s|\n", biggerPrecision , greetings);
return 0;
}
we get the output:
|Hello wo|
|Hello wo|
| Hello world|
| Hello world|

I don't think the code above is correct but (according to this description of printf()) the .* means
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 it's a string with a passable width as an argument.

See: http://www.cplusplus.com/reference/clibrary/cstdio/printf/
.* The precision is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted.
s String of characters

Related

How can I print "%#s" where # represent the spaces, but this spaces amount have to change depending on the input? [duplicate]

In order to determine the size of the column in C language we use %<number>d.
For instance, I can type %3d and it will give me a column of width=3.
My problem is that my number after the % is a variable that I receive, so I need something like %xd (where x is the integer variable I received sometime before in my program).
But it's not working.
Is there any other way to do this?
You can do this as follows:
printf("%*d", width, value);
From Lee's comment:
You can also use a * for the precision:
printf("%*.*f", width, precision, value);
Note that both width and precision must have type int as expected by printf for the * arguments, type size_t is inappropriate as it may have a different size and representation on the target platform.
Just for completeness, wanted to mention that with POSIX-compliant versions of printf() you can also put the actual field width (or precision) value somewhere else in the parameter list and refer to it using the 1-based parameter number followed by a dollar sign:
A field width or precision, or both, may be indicated by an asterisk ‘∗’ or an asterisk followed by one or more decimal digits and a ‘$’ instead of a digit string. In this case, an int argument supplies the field width or precision. A negative field width is treated as a left adjustment flag followed by a positive field width; a negative precision is treated as though it were missing. If a single format directive mixes positional (nn$) and non-positional arguments, the results are undefined.
E.g., printf ( "%1$*d", width, value );

How printf() function knows the type of its arguments

Consider the following program,
#include <stdio.h>
int main()
{
char a = 130;
unsigned char b = 130;
printf("a = %d\nb = %d\n",a,b);
return 0;
}
This program will show the following output.
a = -126
b = 130
My question is how printf() function comes to know the type of a is signed and type of b is unsigned to show result like above?
printf() doesn't know the types, that's why you have to give a correct format string. The prototype for printf() looks like this:
int printf(const char * restrict format, ...);
So, the only argument with a known type is the first one, the format string.
This also means that any argument passed after that is subject to default argument promotion -- strongly simplified, read it as any integer will be converted to at least int -- or ask google about the term to learn each and every detail ;)
In your example, you have implementation defined behavior:
char a = 130;
If your char could represent 130, that's what you would see in the output of printf(). Promoting the value to int doesn't change the value. You're getting a negative number instead, which means 130 overflowed your char. The result of overflowing a signed integer type during conversion in C is implementation defined, the value you're getting probably means that on you machine, char has 8 bits (so the maximum value is 127) and the signed integer overflow resulted in a wraparound to the negative value range. You can't rely on that behavior!
In short, the negative number is created in this line -- 130 is of type int, assigning it to char converts it and this conversion overflows.
Once your char has the value -126, passing it to printf() just converts it to int, not changing the value.
The additional arguments to printf() are formatted according to the type specifier. See here for a list of C format specifiers.
https://fr.cppreference.com/w/c/io/fprintf
It's true that one would not expect b to be printed as 130 in your example since you used the %d specifier and not %u. This surprising behavior seems to be explained here.
Format specifier for unsigned char
I hope I got your question well.
Edit: I can not comment Felix Palmen's answer on account on my low reputation. default argument promotion indeed seems to be the key here, but to me the real question here besides the overflow of a is why b is still printed as 130 despite the use of the signed specifier. It can also be explained with default argument promotion but that should be made more precise.
You need to have a look at the definition of printf statement in stdio.h. You already got the answer in comment printf just write the string pointed by format to stdout.
It's variadic function and it use vargas to get all the arguments in variable-length argument list.
You
This is from the glibc from the GNU version.
int __printf (const char *format, ...)
{
va_list arg;
int done;
va_start (arg, format);
done = vfprintf (stdout, format, arg);
va_end (arg);
return done;
}
What vfprintf does?
It just writes the string pointed by format to the stream, replacing any format specifier in the same way as printf does, but using the elements in the variable argument list identified by arg instead of additional function arguments.
More information about the vfprintf
printf() does not know the data type of arguments. It works on format specifier you passed. The data type you are using is char (having range from -128 to +127) and unsigned char (having range from 0 to 255). Your output for a is overflowed after 127. So the output comes to -126.

How does %d format specifier work?

#include<stdio.h>
main()
{
char x ;
x = 'a' ;
printf("%d",x);
}
In this %d format specifier should read 4 bytes being an integer format specifier but x being an character is stored in 1 byte only. so the remaining 3 bytes should have garbage value and the output should be random.
But the output is always coming 97 which is the ASCII value of 'a'.
Can anyone tell how the format specifier works ?
Function arguments that don't match a declared parameter type of the function (i.e. because the function allows for variable arguments, like printf, or because no function prototype has been provided) undergo the default argument promotions (cf. C11 6.5.2.2), which turn a char value into a value of int or unsigned int. Therefore, passing a to printf matches the requirement for %d.

Set precision dynamically using sprintf

Using sprintf and the general syntax "%A.B" I can do this:
double a = 0.0000005l;
char myNumber[50];
sprintf(myNumber,"%.2lf",a);
Can I set A and B dynamically in the format string?
Yes, you can do that. You need to use an asterisk * as the field width and .* as the precision. Then, you need to supply the arguments carrying the values. Something like
sprintf(myNumber,"%*.*lf",A,B,a);
Note: A and B need to be type int. From the C11 standard, chapter §7.21.6.1, fprintf() function
... a field width, or precision, or both, may be indicated by an asterisk. In
this case, an int argument supplies the field width or precision. The arguments specifying field width, or precision, or both, shall appear (in that order) before the argument (if any) to be converted. A negative field width argument is taken as a - flag followed by a positive field width. A negative precision argument is taken as if the precision were omitted.
Yes - You use "*" e.g.
sprintf(mynumber, "%.*lf", 2, a);
See http://linux.die.net/man/3/sprintf

Set variable text column width in printf

In order to determine the size of the column in C language we use %<number>d.
For instance, I can type %3d and it will give me a column of width=3.
My problem is that my number after the % is a variable that I receive, so I need something like %xd (where x is the integer variable I received sometime before in my program).
But it's not working.
Is there any other way to do this?
You can do this as follows:
printf("%*d", width, value);
From Lee's comment:
You can also use a * for the precision:
printf("%*.*f", width, precision, value);
Note that both width and precision must have type int as expected by printf for the * arguments, type size_t is inappropriate as it may have a different size and representation on the target platform.
Just for completeness, wanted to mention that with POSIX-compliant versions of printf() you can also put the actual field width (or precision) value somewhere else in the parameter list and refer to it using the 1-based parameter number followed by a dollar sign:
A field width or precision, or both, may be indicated by an asterisk ‘∗’ or an asterisk followed by one or more decimal digits and a ‘$’ instead of a digit string. In this case, an int argument supplies the field width or precision. A negative field width is treated as a left adjustment flag followed by a positive field width; a negative precision is treated as though it were missing. If a single format directive mixes positional (nn$) and non-positional arguments, the results are undefined.
E.g., printf ( "%1$*d", width, value );

Resources