Explain this C code snippet — what will happen with printf() function arguments? - c

Can anyone please explain what will be the output and how? I am unable to understand the printf() function arguments. I want to know the difference between
1 and 2, and 3 and 4 printf() statements. Normally in printf(), we should give control string as first argument. But even though interchanging arguments, will I get the same output?
#include <stdio.h>
int main()
{
char *str;
str = "%s";
printf("%s\n", str); //.....1
printf(str, "%s\n"); //.......2
printf(str, "K\n"); //.......3
printf("K\n", str); //........4
return 0;
}

It is better to put the code into a compiler and look at the output. It will probably give better insight of things than asking in Stack Overflow.
The expected output is:
[%s\n] because str contains %s and it will be printed as is.
[%s\n] because str contains the format and the second argument will be printed. This form is very dangerous if str comes from the user.
[K\n] same as 2.
[K\n] str is ignored. gcc will warn you if configured correctly through command-line arguments.
Conclusion — always use #1.

The printf function arguments are comprised of
(1) an initial shift state
(2) format string
(3) list of arguments
In your case you have:
printf("%s\n",str); //.....1
No shift, a format string that takes the sting str = %s and prints it literally.
printf(str, "%s\n");//.......2
The values of str has no numeric shift (again 0) and a literal %s which is printed.
printf(str, "K\n"); //.......3
Here again you have a value of str and initial shift 0, but include a literal format string K which is printed.
printf("K\n",str); //........4
Finally, you have a format string with an insufficient number of conversion specifiers which generates the warning:
foo.c:11:1: warning: too many arguments for format [-Wformat-extra-args]
printf("K\n",str); //........4
but which contains the literal format string K which again is printed. In sum the output of the code being:
%s
%s
K
K

Related

String Unexpected Behavior in C

I was writing a simple program to read a string and then print it.
#include<stdio.h>
// void printString(char *str){
// while(*str!='\0'){
// printf("%c",*str);
// str++;
// }
// printf("\n");
// }
int main(){
char str[50];
printf("Enter Your Name:-");
scanf("%s",&str); // scanf adds '\0' automatically at the end.
char *ptr = str;
// printString(ptr);
printf("Your Name is %s%s",ptr);
return 0;
}
I wrote the above code. At first I didn't know that scanf stops when encounters a space. So I thought that I need to have two %s for printing two words but when I got to know the former part about scanf. I understood the problem but in the process, I encountered another problem which I think is unexpected behavior.
OUTPUT:-
Enter Your Name:-Rachit Mittal
Your Name is Rachit Mittal
This Output, from my understanding is unexpected.
If scanf only reads till it encounter space or new line then string contains only "RACHIT" So in the output screen even after using double %s, It should only print "Rachit" instead of "Rachit Mittal"
I wanna ask why is this so? Is this unexpected behavior because of double %s or something else?
You are invoking undefined behavior by not passing enough arguments to printf. %s%s contains two format specifiers, so printf expects two string arguments to be passed, but you only gave one. In this case, the result could be anything.
Consider enabling warnings to help diagnose these errors (e.g. compiling with -Wall).
You have two %s in the format string, but only one additional argument. So there's no argument corresponding to the second %s. This causes undefined behavior. This means that anything can happen, so nothing should be "unexpected".
It's a bit surprising that this causes it to print the second name from the input. The register or memory location that would have contained an additional argument just happened to point to the remainder of the input buffer used by stdio. This is purely coincidence.
For starters the second argument expression in this call of scanf
scanf("%s",&str);
is incorrect. The type of the expression &str is char ( * )[50] while the conversion specifier %s expects an argument of the type char *. You have to write
scanf( "%s", str );
As for your problem then according to the C Standard (7.21.6.1 The fprintf function)
2 The fprintf function writes output to the stream pointed to by
stream, under control of the string pointed to by format that
specifies how subsequent arguments are converted for output. If
there are insufficient arguments for the format, the behavior is
undefined. If the format is exhausted while arguments remain, the
excess arguments are evaluated (as always) but are otherwise ignored.
The fprintf function returns when the end of the format string is
encountered.
You could write to read several words
scanf( "%49[^\n]", str );

Pass string literal as the argument to the print function with out any format specifier?

Why I am not getting error even though I am not not passing any format specifier but passing a string literal. There is no error in the case of string literal but there is an error in the case of character,integer. Why ?
#include<stdio.h>
int main()
{
printf("Hello World");
return 0;
}
The first argument to printf should be a format string1. "Hello World" is a format string2.
Per paragraph 7.21.6.1 3 in the C 2018 standard, the format string is composed of zero or more directives:
A % character starts a directive for a conversion specification.
Any other character is a directive to output that character unchanged.
So "Hello World" is a format string that says to print “H”, “e”, “l”, “l”, “o”, “ ”, “W”, “o”, “r”, “l”, and “d”. It is simply a format string with only ordinary characters, no conversion specifications. It is the proper type and data for the first parameter of printf, so no errors occurs.
In contrast, when a char or int is passed as the first argument to printf, the compiler knows it is the wrong type for the argument and issues a warning or error message.
Footnotes
1 Technically, the argument should be a pointer to the first character of the format string.
2 "Hello World" is passed as a pointer because, while it is an array of characters, it is automatically converted to a pointer to its first character.
The documentation on printf is as follows:
int printf ( const char * format, ... );
Print formatted data to stdout
Writes the C string pointed by format to the standard output (stdout). If format includes format specifiers (subsequences beginning with %), the additional arguments following format are formatted and inserted in the resulting string replacing their respective specifiers.
putting a char or int variable in place of format above will fail
It is possible with a help of preprocessor and Generic Selection introduced in C11 to select a proper format string basing on argument's type.
Try:
#define FMT(X) _Generic(X, int: "%d", char*: "%s", float: "%f")
#define print(X) printf(FMT(X), (X))
Now the program:
int main() {
print(1);
print("abc");
print(3.0f);
return 0;
}
Produces an expected output of 1abc3.00000.

Too many arguments for format (printf function)

Keep getting the following warning: “too many arguments for format” for the printf function below. Do not know what is causing this warning. I provided the type values of pos and str_pos along with the printf function. I excluded all other code as I did not think it was necessary for this question.
int pos;
char str_pos;
printf("The character at index %d is %c",pos,str_pos, "\n");
The corect way of writing that printf() statement would be
printf("The character at index %d is %c\n", pos, str_pos);
You need to change
“ to "s.
Use the format string correctly, including the newline.
use pos and string_pos as the argument (not part of the format string itself), in the variadic list.
Also, I presume that variables are initialized before you're printing them.

printf() working without double quotes, prints random characters [duplicate]

This question already has answers here:
Behaviour of printf when printing a %d without supplying variable name
(6 answers)
Closed 4 years ago.
I stumbled upon this C code in a college test and when I tested it on Dev-C++ 5.11 compiler, it printed random characters. I can't understand how or why this code works. Can someone enlighten me?
int main() {
char a[10] = "%s" ;
printf( a ) ;
}
This question has two parts: the missing quotes and the random characters.
printf() is just a function. You can pass strings and other values to functions as arguments. You don't have to use a literal. You can use both char *a = "something"; printf(a) (passing a variable as an argument) and printf("something") (passing a string literal as an argument).
printf() is also a variadic function. This means it can accept any number of arguments. You can use printf("hello world"), printf("%s", "hello world") and even printf("%s %s", "hello", "world"). Some older compilers don't verify you actually passed the right number of arguments based on the first argument which is the format string. This is why your code compiles even though it's missing an argument. When the program runs the code goes over the format string, sees "%s" and looks for the second argument to print it as a string. Since there is no second argument it basically reads random memory and you get garbage characters.
printf function signature is:
int printf(const char *format, ...);
It expects format string as the first argument and variable number of arguments that are handled and printed based on the format specifiers in the format string. variable a in your question is providing it the format string. Reason for random characters is that the argument for format specifier %s is missing. Following will correctly print a string:
printf( a, "Hello World!" );
A list of format specifiers can be seen here https://en.wikipedia.org/wiki/Printf_format_string
Why does it compile?
Because variadic arguments accepted by printf are processed at run time. Not all compilers do compile time checks for validating arguments against the format string. Even if they do they would at most throw a warning, but still compile the program.
It's using the string "%s" as a format string, and using uninitialized memory as the "data".
The only reason it does "something" is because the compiler was apparently not smart enough to recognize that the format string required one parameter and zero parameters were supplied. Or because compiler warnings were ignored and/or errors were turned off.
Just an FYI for anybody who bumps into this: "Always leave all warnings and errors enabled and fix your code until they're gone" This doesn't guarantee correct behaviour but does make "mysterious" problems less likely.

how can I printf in c

How can I make this print properly without using two printf calls?
char* second = "Second%d";
printf("First%d"second,1,2);
The code you showed us is syntactically invalid, but I presume you want to do something that has the same effect as:
printf("First%dSecond%d", 1, 2);
As you know, the first argument to printf is the format string. It doesn't have to be a literal; you can build it any way you like.
Here's an example:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *second = "Second%d";
char format[100];
strcpy(format, "First%d");
strcat(format, second);
printf(format, 1, 2);
putchar('\n');
return 0;
}
Some notes:
I've added a newline after the output. Output text should (almost) always be terminated by a newline.
I've set an arbitrary size of 100 bytes for the format string. More generally, you could declare
char *format;
and initialize it with a call to malloc(), allocating the size you actually need (and checking that malloc() didn't signal failure by returning a null pointer); you'd then want to call free(format); after you're done with it.
As templatetypedef says in a comment, this kind of thing can be potentially dangerous if the format string comes from an uncontrolled source.
(Or you could just call printf twice; it's not that much more expensive than calling it once.)
Use the preprocessor to concatenate the two strings.
#define second "Second%d"
printf("First%d"second,1,2);
Do not do this in a real program.
char *second = "Second %d";
char *first = "First %d";
char largebuffer[256];
strcpy (largebuffer, first);
strcat (largebuffer, second);
printf (largebuffer, 1, 2);
The problem with using generated formats such as the method above is that the printf() function, since it is a variable length argument list, has no way of knowing the number of arguments provided. What it does is to use the format string provided and using the types as described in the format string it will then pick that number and types of arguments from the argument list.
If you provide the correct number of arguments like in the example above in which there are two %d formats and there are two integers provided to be printed in those places, everything is fine. However what if you do something like the following:
char *second = "Second %s";
char *first = "First %d";
char largebuffer[256];
strcpy (largebuffer, first);
strcat (largebuffer, second);
printf (largebuffer, 1);
In this example the printf() function is expecting the format string as well as a variable number of arguments. The format string says that there will be two additional arguments, an integer and a zero terminated character string. However only one additional argument is provided so the printf() function will just use what ever is next on the stack as being a pointer to a zero terminated character string.
If you are lucky, the data that the printf() function interprets as a pointer will a valid memory address for your application and the memory area pointed to will be a couple of characters terminated by a zero. If you are less lucky the pointer will be zero or garbage and you will get an access violation right then and it will be easy to find the cause of the application crash. If you have no luck at all, the pointer will be good enough that it will point to a valid address that is about 2K of characters and the result is that printf() will totally mess up your stack and go into the weeds and the resulting crash data will be pretty useless.
char *second = "Second%d";
char tmp[256];
memset(tmp, 0, 256);
sprintf(tmp, second, 2);
printf("First%d%s", 1,tmp);
Or something like that
I'm assuming you want the output:
First 1 Second 2
To do this we need to understand printf's functionality a little better. The real reason that printf is so useful is that it not only prints strings, but also formats variables for you. Depending on how you want your variable formatted you need to use different formatting characters. %d tells printf to format the variable as a signed integer, which you already know. However, there are other formats, such as %f for floats and doubles, %l% for long integers, and %s for strings, or char*.
Using the %s formatting character to print your char* variable, second, our code looks like this:
char* second = "Second";
printf ( " First %d %s %d ", 1, second, 2 );
This tells printf that you want the first variable formatted as an integer, the second as a string, and the third as another integer.

Resources