Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C, why is %s working without giving it a value?

Tags:

c

According to my knowledge and some threads like this, if you want to print strings in C you have to do something like this:

printf("%s some text", value);

And the value will be displayed instead of %s.

I wrote this code:

char password[] = "default";
printf("Enter name: \n");
scanf("%s", password);
printf("%s is your password", password); // All good - the print is as expected

But I noticed that I can do the exact same thing without the value part and it will still work:

printf("%s is your password");

So my question is why does the %s placeholder get a value without me giving it one, and how does it know what value to give it?

like image 902
Tamir Abutbul Avatar asked Dec 04 '22 18:12

Tamir Abutbul


2 Answers

This is undefined behavior, anything can happen included something that looks like correct. But it is incorrect. Your compiler can probably tell you the problem if you use correct options.

Standard says (emphasized is mine):

7.21.6.1 The fprintf function

  1. 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.
like image 161
Jean-Baptiste Yunès Avatar answered Dec 06 '22 06:12

Jean-Baptiste Yunès


The printf() function uses a C language feature that lets you pass a variable number of arguments to a function. (Technically called 'variadic functions' - https://en.cppreference.com/w/c/variadic - I'll just say 'varargs' for short.)

When a function is called in C, the arguments to the function are pushed onto the stack(*) - but the design of the varargs feature provides no way for the called function to know how many parameters were passed in.

When the printf() function executes, it scans the format string, and the %s tells it to look for a string in the next position in the variable argument list. Since there are no more arguments in the list, the code 'walks off the end of the array' and grabs the next thing it sees in memory. I suspect what's happening is that the next location in memory still has the address of password from your prior call to scanf, and since that address points to a string, and you told printf to print a string, you got lucky, and it worked.

Try putting another function call (for example: printf("%s %s %s\n","X","Y","Z") in between your call to scanf("%s", password); and printf("%s is your password"); and you will almost certainly see different behavior.

Free Advice: C has a lot of sharp corners and undefined bits, but a good compiler (and static analysis or 'lint' tool) can warn you about a lot of common errors. If you are going to work in C, learn how to crank your compiler warnings to the max, learn what all the errors and warnings mean (as they happen, not all at once!) and force yourself to write C code that compiles without any warnings. It will save you a lot of unnecessary hassle.

(*) generalizing here for simplicity - sometimes arguments can be passed in registers, sometimes things are inlined, blah blah blah.

like image 25
JVMATL Avatar answered Dec 06 '22 06:12

JVMATL