Trying to understand strange behavior of format specifier in printf - c

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.

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.

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)

Meaning of [^:]: format string in scanf

I found this in some code and could not understand what it does:
scanf("%[^:]:%[^:]:%[^:\n]", a, b, c);
There was no mention of the [^:]: format string in the C documentation and I am quite confused.
The format string %[..] is for specifying the possible characters. For example %[A-DF] is for A, B, C, D, and F. And the ^ at the beginning is for any character excluding the characters specified. Hence, the first format string is for reading characters excluding colon. And the next is colon, and so on. You may test the scanf for the following input:
Adam:And:Apple
Important thing you should remember is, scanf() function accepts the arguments how it is specified.
For example:
scanf("%d %d",&a,&b);
assuming a and b are integer.
In the command line you have to input a and then followed by space and then b.because you have given a space in-between two "%d's". if you are giving n number of spaces are other character then you have to enter in-between those character before the value gets accepted.
Hence in your case:
you enter the string not containing ":" in it.
Consider this case, if you want to enter a string containing ":" in it.
For example:
"some:init" is the string then, in first %[^:] the string "some" is stored,then comes the ":" and then in second %[^:] it stores init. Then it wait for one more ":" and then the string not containing ":".
ultimately accepting the input in this format doesn't fetch any thing.
The only thing matters is how you print it on to the console.

Sscanf not returning what I want

I have the following problem:
sscanf is not returning the way I want it to.
This is the sscanf:
sscanf(naru,
"%s[^;]%s[^;]%s[^;]%s[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
"%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]"
"%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]",
&jokeri, &paiva1, &keskilampo1, &minlampo1, &maxlampo1,
&paiva2, &keskilampo2, &minlampo2, &maxlampo2, &paiva3,
&keskilampo3, &minlampo3, &maxlampo3, &paiva4, &keskilampo4,
&minlampo4, &maxlampo4, &paiva5, &keskilampo5, &minlampo5,
&maxlampo5, &paiva6, &keskilampo6, &minlampo6, &maxlampo6,
&paiva7, &keskilampo7, &minlampo7, &maxlampo7);
The string it's scanning:
const char *str = "city;"
"2014-04-14;7.61;4.76;7.61;"
"2014-04-15;5.7;5.26;6.63;"
"2014-04-16;4.84;2.49;5.26;"
"2014-04-17;2.13;1.22;3.45;"
"2014-04-18;3;2.15;3.01;"
"2014-04-19;7.28;3.82;7.28;"
"2014-04-20;10.62;5.5;10.62;";
All of the variables are stored as char paiva1[22] etc; however, the sscanf isn't storing anything except the city correctly. I've been trying to stop each variable at ;.
Any help how to get it to store the dates etc correctly would be appreciated.
Or if there's a smarter way to do this, I'm open to suggestions.
There are multiple problems, but BLUEPIXY hit the first one — the scan-set notation doesn't follow %s.
Your first line of the format is:
"%s[^;]%s[^;]%s[^;]%s[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
As it stands, it looks for a space separated word, followed by a [, a ^, a ;, and a ] (which is self-contradictory; the character after the string is a space or end of string).
The first fixup would be to use scan-sets properly:
"%[^;]%[^;]%[^;]%[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
Now you have a problem that the first %[^;] scans everything up to the end of string or first semicolon, leaving nothing for the second %[;] to match.
"%[^;]; %[^;]; %[^;]; %[^;]; %f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
This looks for a string up to a semicolon, then for the semicolon, then optional white space, then repeats for three items. Apart from adding a length to limit the size of string, preventing overflow, these are fine. The %f is OK. The following material looks for an odd sequence of characters again.
However, when the data is looked at, it seems to consist of a city, and then seven sets of 'a date plus three numbers'.
You'd do better with an array of structures (if you've worked with those yet), or a set of 4 parallel arrays, and a loop:
char jokeri[30];
char paiva[7][30];
float keskilampo[7];
float minlampo[7];
float maxlampo[7];
int eoc; // End of conversion
int offset = 0;
char sep;
if (fscanf(str + offset, "%29[^;]%c%n", jokeri, &sep, &eoc) != 2 || sep != ';')
...report error...
offset += eoc;
for (int i = 0; i < 7; i++)
{
if (fscanf(str + offset, "%29[^;];%f;%f;%f%c%n", paiva[i],
&keskilampo[i], &minlampo[i], &maxlampo[i], &sep, &eoc) != 5 ||
sep != ';')
...report error...
offset += eoc;
}
See also How to use sscanf() in loops.
Now you have data that can be managed. The set of 29 separately named variables is a ghastly thought; the code using them will be horrid.
Note that the scan-set conversion specifications limit the string to a maximum length one shorter than the size of jokeri and the paiva array elements.
You might legitimately be wondering about why the code uses %c%n and &sep before &eoc. There is a reason, but it is subtle. Suppose that the sscanf() format string is:
"%29[^;];%f;%f;%f;%n"
Further, suppose there's a problem in the data that the semicolon after the third number is missing. The call to sscanf() will report that it made 4 successful conversions, but it doesn't count the %n as an assignment, so you can't tell that sscanf() didn't find a semicolon and therefore did not set &eoc at all; the value is left over from a previous call to sscanf(), or simply uninitialized. By using the %c to scan a value into sep, we get 5 returned on success, and we can be sure the %n was successful too. The code checks that the value in sep is in fact a semicolon and not something else.
You might want to consider a space before the semi-colons, and before the %c. They'll allow some other data strings to be converted that would not be matched otherwise. Spaces in a format string (outside a scan-set) indicate where optional white space may appear.
I would use strtok function to break your string into pieces using ; as a delimiter. Such a long format string may be a source of problems in future.

Invalid output with fscanf()

The language I am using is C
I am trying to scan data from a file, and the code segment is like:
char lsm;
long unsigned int address;
int objsize;
while(fscanf(mem_trace,"%c %lx,%d\n",&lsm,&address,&objsize)!=EOF){
printf("%c %lx %d\n",lsm,address,objsize);
}
The file which I read from has the first line as follows:
S 00600aa0,1
I 004005b6,5
I 004005bb,5
I 004005c0,5
S 7ff000398,8
The results that show in stdout is:
8048350 134524916
S 600aa0 1
I 4005b6 5
I 4005bb 5
I 4005c0 5
S 7ff000398,8
Obviously, the results had an extra line which comes nowhere.Is there anybody know how this could happen?
Thx!
This works for me on the data you supply:
#include <stdio.h>
int main(void)
{
char lsm[2];
long unsigned int address;
int objsize;
while (scanf("%1s %lx,%d\n", lsm, &address, &objsize) == 3)
printf("%s %9lx %d\n", lsm, address, objsize);
return 0;
}
There are multiple changes. The simplest and least consequential is the change from fscanf() to scanf(); that's for my convenience.
One important change is the type of lsm from a single char to an array of two characters. The format string then uses %1s reads one character (plus NUL '\0') into the string, but it also (and this is crucial) skips leading blanks.
Another change is the use of == 3 instead of != EOF in the condition. If something goes wrong, scanf() returns the number of successful matches. Suppose that it managed to read a letter but what followed was not a hex number; it would return 1 (not EOF). Further, it would return 1 on each iteration until it could find something that matched a hex number. Always test for the number of values you expect.
The output format was tidied up with the %9lx. I was testing on a 64-bit system, so the 9-digit hex converts fine. One problem with scanf() is that if you get an overflow on a conversion, the behaviour is undefined.
Output:
S 600aa0 1
I 4005b6 5
I 4005bb 5
I 4005c0 5
S 7ff000398 8
Why did you get the results you got?
The first conversion read a space into lsm, but then failed to convert S into a hex number, so it was left behind for the next cycle. So, you got the left-over garbage printed in the address and object size columns. The second iteration read the S and was then in synchrony with the data until the last line. The newline at the end of the format (like any other white space in the format string) eats white space, which is why the last line worked despite the leading blank.
A directive that is a conversion specification defines a set of
matching input sequences, as described below for each specifier. A
conversion specification is executed in the following steps:
Input white-space characters (as specified by the isspace function)
are skipped, unless the specification includes a [, c, or n specifier.
An input item is read from the stream, unless the specification
includes an n specifier.
[...]
The first time you call fscanf, your %c reads the first blank space in the file. Your white-space character reads zero or more characters of white-space, this time zero of them. Your %lx fails to match the S character in the file, so fscanf returns. You don't check the result. Your variables contain values that they had from earlier operations.
The second time you call fscanf, your %c reads the first S character in the file. From that point on, everything else succeeds too.
Added in editing, here is the simplest change to your format string to solve your problem:
" %c %lx,%d\n"
The space at the beginning will read zero or more characters of white-space and then %c will read the first non-white-space character in the file.
Here is another format string that will also solve your problem:
" %c %lx,%d"
The reason is that if you read and discard zero or more white-space characters twice in a row, the result is the same as doing it just once.
I think that fsanf reads the first character [space] into lsm then fails to read address and objsize because the format shift doesn't match for the rest of the line.
Then it prints a space then whatever happened to be in address and objsize when it was declared
EDIT--
fscanf consumes the whitespaces after each call, if you call ftell you'll see
printf("%c %lx %d %d\n",lsm,address,objsize,ftell(mem_trace));

Resources