177

This code prints the map of India. How does it work?

#include <stdio.h>
main()
{
    int a,b,c;
    int count = 1;
    for (b=c=10;a="- FIGURE?, UMKC,XYZHello Folks,\
    TFy!QJu ROo TNn(ROo)SLq SLq ULo+\
    UHs UJq TNn*RPn/QPbEWS_JSWQAIJO^\
    NBELPeHBFHT}TnALVlBLOFAkHFOuFETp\
    HCStHAUFAgcEAelclcn^r^r\\tZvYxXy\
    T|S~Pn SPm SOn TNn ULo0ULo#ULo-W\
    Hq!WFs XDt!" [b+++21]; )
    for(; a-- > 64 ; )
    putchar ( ++c=='Z' ? c = c/ 9:33^b&1);
    return 0;
}
Sankalp
  • 2,796
  • 3
  • 30
  • 43
narayanpatra
  • 5,627
  • 13
  • 51
  • 60
  • 67
    It's just obfuscated C... there's whole societies dedicated to this sort of madness. – Mark Aug 20 '10 at 17:33
  • 12
    Output: http://codepad.org/ngiITeZ4 – Andreas Rejbrand Aug 20 '10 at 17:35
  • 1
    I asked it here because I am quite new to C and can't understand a line of it. Since This code prints map of India and I am an Indian, I got little curious. People here assume too much. If it is something bad, They should have told me. -2 rep , without any reason. May be some great people exist here . If they can't understand the code, they will -rep to the author. – narayanpatra Aug 20 '10 at 17:42
  • 2
    #include "Stdio.h" : Does that work on all compilers? I'm surprised to see that you can get working code with miscaps. Maybe its on Windows (non case sensitive FS) – alternative Aug 20 '10 at 17:44
  • 2
    For more fun code like that see [The International Obfuscated C Code Contest][http://www.ioccc.org/]. – DarkDust Aug 20 '10 at 17:44
  • 14
    Just be aware that the code is *intentionally* difficult to understand, and there's not much to be gained from figuring it out, as far as learning C from a beginner's level is concerned. – Tyler McHenry Aug 20 '10 at 17:45
  • @monadic stdio.h is a filename. If you're running on an OS with a case-insensitive file system (Windows, for instance), it shouldn't matter. – 3Dave Sep 02 '11 at 17:28
  • 1
    @David Lively "Does that work on _all_ compilers?" – alternative Sep 02 '11 at 21:18
  • I'd expect so. The compiler has no special knowledge of "stdio.h" or any other header. #include causes the preprocessor to find the file and literally include its text in the source prior to compilation. It'll probably throw an error on Linux, but should be fine on Windows. – 3Dave Sep 02 '11 at 21:43
  • @monadic: Maybe. In principle the standard library headers are accessed with `<>` instead of `""`. The distinction is rather muddy in the standard but basically `<>` can access *non-file* objects (say someone wanted to put the standard library in a database. I've never seen that and if the standard library headers *are* files then `""` should get them. – dmckee --- ex-moderator kitten Sep 03 '11 at 03:10
  • @David Lively All compilers include compilers that aren't compiling on windows. Nonportable code like that is just inexcusable. – alternative Sep 03 '11 at 13:38
  • @DavidLively "Does that work on all compilers?" "I'd expect so... "It'll probably throw an error on Linux" -- Contradict yourself much? – Jim Balter Mar 29 '13 at 05:11
  • @JimBaitler I'm sure I had a good reason for putting it that way two years ago. Of course, "stdio" will work, "Stdio" will fail on Linux. – 3Dave Mar 29 '13 at 13:16
  • "does it work on all compilers?" defenetly not! give me me 1 minute and I produce a compiler by my self on which THIS code doesn't work. As the code is producing undefined behavior in many cases. A compiler is allowed to do anything by compiling this code. And I can code you a programm which does something with this as input and acording to this code its still allowed to get called c compiler in view of the ISO C standards. So in short: NO! – dhein Sep 20 '13 at 16:59
  • Turns out "#include "Stdio.h" seems to work on UNIX based systems, at least on clang. – jviotti Aug 12 '16 at 22:28

2 Answers2

158

The long string is simply a binary sequence converted to ASCII. The first for statement makes b start out at 10, and the [b+++21] after the string yields 31. Treating the string as an array, offset 31 is the start of the "real" data in the string (the second line in the code sample you provided). The rest of the code simply loops through the bit sequence, converting the 1's and 0's to !'s and whitespace and printing one character at a time.

Less obfuscated version:

#include "stdio.h"
int main (void) {
    int a=10, b=0, c=10;
    char* bits ="TFy!QJu ROo TNn(ROo)SLq SLq ULo+UHs UJq TNn*RPn/QPbEWS_JSWQAIJO^NBELPeHBFHT}TnALVlBLOFAkHFOuFETpHCStHAUFAgcEAelclcn^r^r\\tZvYxXyT|S~Pn SPm SOn TNn ULo0ULo#ULo-WHq!WFs XDt!";
    a = bits[b];
    while (a != 0) {
        a = bits[b];
        b++;
        while (a > 64) {
            a--;
            if (++c == 'Z') {
                c /= 9;
                putchar(c);
            } else {
                putchar(33 ^ (b & 0x01));
            }
        }
    }
    return 0;
}

The strange clever part is in the putchar statements. Take the first putchar. ASCII 'Z' is 90 in decimal, so 90 / 9 = 10 which is a newline character. In the second, decimal 33 is ASCII for '!'. Toggling the low-order bit of 33 gives you 32, which is ASCII for a space. This causes ! to be printed if b is odd, and a blank space to be printed if b is even. The rest of the code is simply there to walk the "pointer" a through the string.

bta
  • 43,959
  • 6
  • 69
  • 99
  • 22
    The string is not a bit sequence (note that there are no bit-shift operations in the code). It is a run-length encoding of the image. – interjay Aug 20 '10 at 18:04
91

Basically, the string is a run-length encoding of the image: Alternating characters in the string say how many times to draw a space, and how many times to draw an exclamation mark consecutively. Here is an analysis of the different elements of this program:

The encoded string

The first 31 characters of this string are ignored. The rest contain instructions for drawing the image. The individual characters determine how many spaces or exclamation marks to draw consecutively.

Outer for loop

This loop goes over the characters in the string. Each iteration increases the value of b by one, and assigns the next character in the string to a.

Inner for loop

This loop draws individual characters, and a newline whenever it reaches the end of line. The number of characters drawn is a - 64. The value of c goes from 10 to 90, and resets to 10 when the end of line is reached.

The putchar

This can be rewritten as:

++c;
if (c==90) {       //'Z' == 90
    c = 10;        //Note: 10 == '\n'
    putchar('\n');
}
else {
    if (b % 2 == 0)
        putchar('!');
    else
        putchar(' ');
}

It draws the appropriate character, depending on whether b is even or odd, or a newline when needed.

interjay
  • 107,303
  • 21
  • 270
  • 254