0

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 ) ;
    }
vic
  • 31
  • 2
  • 3
    If it's printing random characters, how can you assert that it "works"? Because it compiles? – JGroven Jun 05 '18 at 16:21
  • I wouldn't call printing random characters working unless you wrote a program designed to randomly generate characters and print them. – Christian Gibbons Jun 05 '18 at 16:21
  • Try just getting rid of the variable "a" and putting the string directly into the printf() call and it should be pretty obvious what's going on. – DaveG Jun 05 '18 at 16:24
  • The actual question is why does it compile? – vic Jun 05 '18 at 16:26
  • 2
    Because C is very naive. It thinks that the programmer knows what they are doing. – Eugene Sh. Jun 05 '18 at 16:31
  • It compiles because variadic arguments are processed at run time and not compile time. However, some compilers do perform compile time validation for arguments against the format string. But they at most through warnings about it. But still compile the program. See my detailed answer below. – Mohammad Azim Jun 05 '18 at 16:32
  • It's Undefined Behaviour, so anything it does counts as "working". – Toby Speight Jun 05 '18 at 16:35
  • Are you sure you copied that code correctly from the test? Or did the test really claim that it worked? Or did the test really ask something else? `printf` expects either a simple string *without format specifiers (`%` items)* or a format specifier string and arguments whose number matches the number of format specifiers. In this case `a` represents a string with a single string format specifier, so `printf` needs two arguments, first `a`, then a string so that the `%s` has something to format. Read the `printf` manual page. – lurker Jun 05 '18 at 16:35
  • @MohammadAzim You're right, but i didn't realize at the time that, that was my actual question. – vic Jun 05 '18 at 16:42
  • @lurker The test's question was whether this code snippet would print anything and if yes, what would it print. – vic Jun 05 '18 at 16:43
  • Ok, so it didn't claim it was "working". As others have mentioned, it is undefined behavior since the format string references an argument you haven't given to `printf`. – lurker Jun 05 '18 at 16:54
  • @lurker One option was "it prints a random number" and another "It won't run at all". – vic Jun 05 '18 at 19:18

3 Answers3

1

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.

Mohammad Azim
  • 2,604
  • 20
  • 21
  • 2
    In the case of this question, the format string is dynamic: at the time `printf` is called, the format string is whatever the array `a` has been modified to at that point. Most compilers are unable to warn about format string mismatch in this case, although this online C interpreter can: https://taas.trust-in-soft.com/tsnippet/t/af45e0e6 . Compilers can at best warn that the format string is dynamic, but this is not systematically an error. – Pascal Cuoq Jun 05 '18 at 16:34
  • @PascalCuoq Very cool compiler! – vic Jun 05 '18 at 16:39
1

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.

Terry Carmen
  • 3,720
  • 1
  • 16
  • 32
1

This question has two parts: the missing quotes and the random characters.

  1. 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).
  2. 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.
kichik
  • 33,220
  • 7
  • 94
  • 114