format string used in printf function in C programming - c

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.

Related

C - format specifier for scanf?

float lat, lon;
char info[50];
scanf("%f, %f, %49[^\n]", &lat, &lon, info);
In the above snippet, what kind of format specifier is %49[^\n].
I do understand that it is the format specifier for the character array which is going to accept input upto 49 characters (+ the sentinal \0), and [^\n] looks like its a regex (although I had read somewhere that scanf doesn't support regex) OR a character set which is to expand to "any other character" that is NOT "newline" \n. Am I correct?
Also, why is there no s in the format specifier for writing into array info?
The program this snippet is from works. But is this good C style?
The specifier %[ is a different conversion specifier from %s, even if it also must be paired with an argument of type char * (or wchar_t *). See e.g. the table here
[set] matches a non-empty sequence of character from set of characters.
If the first character of the set is ^, then all characters not in the set are matched. If the set begins with ] or ^] then the ] character is also included into the set. It is implementation-defined whether the character - in the non-initial position in the scanset may be indicating a range, as in [0-9]. If width specifier is used, matches only up to width. Always stores a null character in addition to the characters matched (so the argument array must have room for at least width+1 characters)
My apologies, I incorrectly answered below. If you can skip to the end, I'll give you the correct answer.
*** Incorrect Answer Begins ***
It would not be a proper format specifier, as there is no type.
%[parameter][flags][width][.precision][length]type
are the rules for a format statement. As youc an see, the type is non-optional. The author of this format item is thinking they can combine regex with printf, when the two have entirely different processing rules (and printf doesn't follow regex's patterns)
*** Correct Answer Begins ***
scanf uses different format string rules than printf Within scanf's man page is this addition to printf's rules
[
Matches a nonempty sequence of characters from the specified set
of accepted characters; the next pointer must be a pointer to char,
and there must be enough room for all the characters in the string,
plus a terminating null byte. The usual skip of leading white space is
suppressed. The string is to be made up of characters in (or not in) a
particular set; the set is defined by the characters between the open
bracket [ character and a close bracket ] character. The set excludes
those characters if the first character after the open bracket is a
circumflex (^). To include a close bracket in the set, make it the
first character after the open bracket or the circumflex; any other
position will end the set. The hyphen character - is also special;
when placed between two other characters, it adds all intervening
characters to the set. To include a hyphen, make it the last character
before the final close bracket. For instance, [^]0-9-] means the set
"everything except close bracket, zero through nine, and hyphen". The
string ends with the appearance of a character not in the (or, with a
circumflex, in) set or when the field width runs out.
Which basically means that scanf can scan with a subset of regex's rules (the character set subset) but not all of regex's rules

Using sscanf for an unknown number of variables

For a school assignment, I have to read in a string that has at least one but up to three variables(named command, one, and two). There is always a character at the beginning of the string, but it may or may not be followed by integers. The format could be like any of the following:
i 5 17
i 3
p
d 4
I am using fgets to read the string from the file, but I'm having trouble processing it. I've been trying to use sscanf, but I'm getting segfaults reading in a string that only has one or two variables instead of three.
Is there a different function I should be using?
Or is there a way to format sscanf to do what I need?
I've tried sscanf(buffer, "%c %d %d", command, one, two) and several variations with no luck.
sscanf is probably up to this task, depending on the exact requirements and ranges of inputs.
The key here is is that the scanf family functions returns a useful value which indicates how many conversions were made. This can be less than zero: the value EOF (a negative value) can be returned if the end of the input occurs or an I/O error, before the first conversion is even attempted.
Note that the %c conversion specifier doesn't produce a null-terminated string. By default, it reads only one character and stores it through the argument pointer. E.g.
char ch;
sscanf("abc", "%c", &ch);
this will write the character 'a' into ch.
Unless you have an iron-clad assurance that the first field is always one character wide, it's probably better to read it as a string with %s. Always use a maximum width with %s not to overflow the destination buffer. For instance:
char field1[64]; /* one larger than field width, for terminating null */
sscanf(..., "%63s", field1, ...);
sscanf doesn't perform any overflow checks on integers. If %d is used to scan a large negative or positive value that doesn't fit into int, the behavior is simply undefined according to ISO C. So, just like with %s, %d is best used with a field width limitation. For instance, %4d for reading a four digit year. Four decimal digits will not overflow int.

character array overflowing by sprintf

I am using char array[6];
I am converting a float variable to string using sprintf as follows..
sprintf(array,"%f\0",floatvar);
and i am writing char array on LCD.
Problem is my array size is only 6 bytes, but it is printing "00000.00000" 11 byte of data. Array size is restricted to 6 bytes. But How the array overflowing in this case?
The sprintf function expects that you provide a big enough buffer to hold all of its output. Otherwise your code causes undefined behaviour.
Your code would not produce 00000.00000 either; if the value is between 0 and 1 then the output will start with 0. . Perhaps you used a different format string in your real code.
With %f it is not possible to constrain the output solely via format string modifiers. To be safe, you can use snprintf:
snprintf(array, 6, "%f", floatvar);
If your system does not have snprintf available then I would suggest downloading a freeware implementation of vsnprintf.
As a last resort you could use sprintf with a lot of checking:
if ( floatvar < 0.f || floatvar >= 1.f )
exit.....;
sprintf(array, 6, "%.3f", floatvar);
The .3 means that at most 3 characters will show after the decimal point; and since we did a range check that means the start will be 0. , for a total of 5 output characters plus null terminator.
To be on the safe side I'd suggest temporarily outputting to a large buffer, using strlen to check what was written, and then copying to your 6-byte buffer if it did write correctly.
NB. "%f\0" is strange; string literals are strings and so they end in '\0' already. "%f\0" ends in two null terminators.

Trying to understand strange behavior of format specifier in printf

I saw that the as I keep increasing the value in format specifier "10s" to "100s" "1000s" I get the output which keeps on shifting on the screen
main()
{
char s[]="Hello,,world";
printf("%10s",s);
}
Output
10s
Hello,,worldPress any key to continue . . .
100s
Hello,,worldPress any key to continue . . .
1000s
Hello,,worldPress any key to continue . . .
What is happening ?
In printf , Giving the values in the format scpecifier, acts as giving the leading spaces before printing the output. Count of the array value will be taken.
In first case,
Total array count is 12. You gave 10. So there is no leading spaces.
In second and third case,
You gave 100, SO 100-12=88 spaces and 1000-12=988 spaces is given as a output.
Only numeric in the control string it will give you the leading spaces.
while using the printf("%10s",s);
10s will be leave the leading spaces before the string. Your string has 12 characters, if you give 10s the length of the sting is greater than the integer, so there is no white space.
if the integer value is greater than the string then it will leave the white space.
while giving 100s, the length of the sting is less than the integer, so it leaves the whitespace.
Statement printf("%ns",s); prints the string s, but with a width %nd to say that we want n characters (positions) reserved for the output. The result is that n space characters are placed before printing the character.

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);.

Resources