What will be the output, if we print a string that contains "%s" in it?
Asked Answered
I

5

7

I'd like to know what the result would be if we print a string that contains "%s" in its content?

I tried printing it as "hi%s".

char *ptr="hi%s";
printf(ptr);

I expected the output to be as "hi". but i got it as "hi hi%s".

"hi hi%s"

Internationalism answered 16/7, 2019 at 14:29 Comment(7)
Why not just compile this code and see for yourself what happens?Legendre
This will be undefined behavior as printf expects extra parameter passed for %sNonesuch
@RoelBalink Because this will prove nothing.Nonesuch
@RoelBalink Because that will just give you one particular instance of Undefined Behaviour, which could be very different when compiled in an even slightly different context.Transcurrent
Did you mean printf("%s\n", ptr);?Holoblastic
To avoid this mistake and just output the string raw, you could fwrite(ptr, 1, strlen(ptr), stdout) or printf("%s", ptr).Sonometer
@MadPhysicist no,what i meant is : printf("hi%s"); will this %s give some garbage value ? because when i execute it it's giving an output as: "hi hi%s"Internationalism
S
11

As specified in other answered, a undefined behavior will occur.

What the undefined behavior means in this context: When printf receives a string with n number of format specifiers (such as %s) it is going to expect n number of parameters to be passed to the function in addition to the string. So, when you have a statement like this printf("hi%s"), the function will behave as if you passed a parameter (in this case the second parameter should be a char *) even though there is not. The function is just going to get the next value on the stack which is some junk value in this case. Then the function will deference this junk value and will treat it as a buffer of characters. The reasons why this behavour is undefined is there is no telling what the junk value on the stack could be.

Possible Outcomes

  1. The junk value on the stack is 0 -> Segmentation fault when junk value is dereferenced.

  2. The junk value on the stack happens to be a valid memory address -> The bytes at the memory location will keep getting inserted into the string (appended to "hi" in this case) until either a byte of value 0 is encountered or a segmentation fault occurs.

  3. The junk value on the stack is not 0 but is not a valid memory location -> Segmentation fault when junk value is dereferenced.

Producing the same situation The below portion of code is a very similar situation to printf("hi%s")

void foo() {
   char * myJunkValue;  // Since not a global/static variable, this is not guaranteed to be 0
   printf(myJunkValue); // Undefined behavior
}
Shannon answered 16/7, 2019 at 15:6 Comment(3)
No problem, glad to help! @chetanvamshiShannon
Your second paragraph is a conjecture and the behaviour might be quite different for the same code in other cases. There are plenty of other possible outcomes, including formatting the hard drive; it is dangerous to suggest to the reader that the behaviour might be limited to what you have describedShattuck
@Shattuck Its says "Possible" for a reason.Shannon
A
6

Your program invokes undefined behaviour.

Your code is equivalent to

 printf("hi%s");

where %s is a conversion specifier and it expects an argument to be supplied.

Quoting C11, chapter §7.21.6.1

[...] If there are insufficient arguments for the format, the behavior is undefined. [....]

Suggestion: If you just have to print a string, without a need of any conversion (formatting), you can use puts().

Agrarian answered 16/7, 2019 at 14:31 Comment(4)
puts() appends a newline.Bowe
@AndrewHenle in this case, I don't think it really matters.Agrarian
@AndrewHenle Is fputs() the best compromise?Expellee
@Expellee I would think so. puts( s ) is not equivalent to printf( "%s", s ), but fputs( s, stdout ) is.Bowe
C
5

You're not "printing a string which has %s in its content". You're passing such a string as the format string to printf, and by doing so without a matching argument for the format field, your program has undefined behavior. The first argument to printf is not a string you want to print. It's a format string that controls how the remaining arguments are interpreted/converted, and which can also contain literal text to merge them into.

"Printing a string which has %s in its content" (where ptr points to that string, as in your question) can be accomplished by printf("%s", ptr) or puts(ptr).

Chemiluminescence answered 16/7, 2019 at 14:32 Comment(0)
S
4

There will be undefined behavior.:)

This part of the string literal %s is considered by the function as a format specifier.

From the C Standard (7.21.6.1 The fprintf function)

  1. ... If there are insufficient arguments for the format, the behavior is undefined.

If you want to output the string "hi%s" as is you should define the literal like "hi%%s".

Here is a demonstrative program

#include <stdio.h>

int main(void) 
{
    char *ptr = "hi%%s";

    printf( ptr );

    return 0;
}

Its output is

hi%s
Slander answered 16/7, 2019 at 14:31 Comment(3)
thanks you are correct but, in the exact program of yours if *ptr = "hi%s" then ?... can u explain again .Internationalism
if i execute it as *ptr = "hi%s" then the output is as "hi hi%s" can u explain why its like that?Internationalism
@chetanvamshi I have not understood what you are asking. The format specifier %s that is present in the string literal requires a corresponding argument that is absent. So the function call has undefined behavior.Slander
S
0

As other answered have mentioned, what you're doing invokes undefined behavior because you're calling printf without enough arguments for the given format specifier. In your case you got junk output, but your program could have just as easily crashed.

To expand on this, code that looks like this:

printf(ptr);

Is almost always wrong. If the string that ptr points to can be controlled by the user in any way, you open yourself up to a format string vulnerability. The user could supply a specially crafted string using %s, %x, etc. that could dump the contents of memory and expose sensitive data, or a string using %n that could write to memory and allow an attacker to take over your program.

Many static analyzers will throw a warning if the first argument to printf is not a string constant for this reason.

Story answered 16/7, 2019 at 15:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.