8

The more I try to understand this perplexed enigma the more I want to give up.

char *s = "char *s = %c%s%c; main(){printf(s,34,s,34);}"; main(){printf(s,34,s,34);}

How is happening for this one-line source code to generate exactly the same output when the program executes and is there any common notion for this kind of programs?

Daniel Cheung
  • 4,779
  • 1
  • 30
  • 63
Imobilis
  • 1,475
  • 8
  • 29
  • 2
    Do you know what `printf` does? Can you work out what `printf("char *s = %c%s%c; main(){printf(s,34,s,34);}", 34, "char *s = %c%s%c; main(){printf(s,34,s,34);}", 34)` prints, given that 34 is the ASCII code for a `"`? – user253751 Aug 28 '15 at 09:31
  • Now it is official - I am terribly lacking analyzing skills. – Imobilis Aug 28 '15 at 09:32
  • I know what 34 is and what printf does.. it just semantically confuses me. – Imobilis Aug 28 '15 at 09:33
  • 1
    @Malina 34 is the ASCII code for `"`, the code uses `34` instead of `'"'` as to avoid having to escape the quote character. – fuz Aug 28 '15 at 09:38
  • Since you have the code, did you try [searching for it](http://stackoverflow.com/search?q=main%28%29%7Bprintf%28s%2C34%2Cs%2C34%29%3B%7D) here on stack overflow. **Lots** of related material to look through! – crashmstr Aug 28 '15 at 12:46

3 Answers3

11

This is called a Quine.

So let's see what main() does:

printf(s,34,s,34);

34 is the ASCII code for the character " (double quote), so this is the same as:

printf(s, '"', s, '"');

The first argument to printf(3) is the format string. The string passed is:

"char *s = %c%s%c; main(){printf(s,34,s,34);}"

So, printf(3) will output exactly that, but note the %c, %s and %c format specifiers, which instruct printf(3) to print a character, followed by a string, followed by another character in that place, which are respectively the 2nd, 3rd and 4th arguments.

The characters, as we saw, are both ", and the string is s again (the same string). So the program output is:

char *s = "X"; main(){printf(s,34,s,34);}

Where X is the string s in the program. So we get this as output:

char *s = "char *s = %c%s%c; main(){printf(s,34,s,34);}"; main(){printf(s,34,s,34);}

Which, interestingly, is the program source itself.

Filipe Gonçalves
  • 20,783
  • 6
  • 53
  • 70
  • Inevitably explanatory-obfuscated; so I think not giving this to students is a wonderful idea. Thanks :) – Imobilis Aug 28 '15 at 09:47
  • 1
    @Malina Indeed, it may be trickyfor the untrained student eye, but self-replicating programs are an important part of computability theory. Students should at least learn the concept. – Filipe Gonçalves Aug 28 '15 at 09:50
  • I've also updated the question to make it more valuable to others reading your answer in parallel with the addition. – Imobilis Aug 28 '15 at 09:53
  • @Malina Thanks, it's always good to clarify the question so that others can find it easily. I readded the `quine` tag to your question as it seems you (accidentally?) removed it. I think this is an appropriate tag for your question, but if you disagree, then by all means feel free to undo my actions. – Filipe Gonçalves Aug 28 '15 at 10:00
  • I do feel free, but it was just to not cause confusion towards people "He tagged with something he was asking for??" to avoid people thinking it was a semi self-answered question if you get what I mean. – Imobilis Aug 28 '15 at 10:03
3

take that string from first parameter of printf:

'char *s = %c%s%c; main(){printf(s,34,s,34);}'

and do substitution where

%c = 34 = '"' //(same for both %c)
%s = 'char *s = %c%s%c; main(){printf(s,34,s,34);}'

printf will do substitution only once (not recursive), so result is:

'char *s = "char *s = %c%s%c; main(){printf(s,34,s,34);}"; main(){printf(s,34,s,34);}'
Ormei
  • 91
  • 5
1

To understand the code, first simplify and reformat:

char *s = "some format string";
main() {
    printf(s,34,s,34);
}

so it uses s as a formatting string to print three entities: 34, the string s itself and 34. In this case, the important part of the formatting string s is:

char *s = "... %c%s%c ..."

which means the two 34s become double-quotes (") and the formatting-string s is just printed as a normal string. Now you should see the the rest of the formatting-string s is just a copy of the whole program.

TripeHound
  • 2,721
  • 23
  • 37