Can't understand this code?

419 views Asked by At

Can anyone help me in understanding the following code:-

int r, countIt(int n) {
    while (r += "            2  "[n % 10] & 3, n /= 10);
    return r;
}

I found this code in one of the challenges of codefights.com, https://codefights.com/challenge/v5Zg8trjoun3PTxrZ/solutions/Aj3ppbhSShixt4nBi

This is a solution for counting number of holes in a number.
e.g.

1111 = 0  
0000 = 4  
1234 = 0  
8888 = 8   

I am not able to understand the following things:
1. Logic of this code
2. comma (,) operator used in return data type of the function
3. Use of []operator after string.
4. And actually the whole code.

3

There are 3 answers

2
BlessonThomas On BEST ANSWER

I looked up the link you provided. After carefully observing the code i came to following conclusion.

int r, countIt(int n) {.....}

is equivalent to writing as

int r;
int countIt(int n){.....}

now for

while (r += "            2  "[n % 10] & 3, n /= 10);

is equivalent to:

do{
    r += "           2  "[n % 10] & 3;
    n/=10;
}while(n);

Now comes the logical part of the code

r += "           2  "[n % 10] & 3;

let me give you some basics.

  1. In c++

cout<<"abcde"[2];

will give you output

c

now if you watch carefully the code in link which you provided its something like this:

r += "           2  "[n % 10] & 3;

is nothing but

r += "TAB,SPACE,SPACE,SPACE,SPACE,SPACE,TAB,SPACE,2,TAB"[n % 10] & 3;

Now its time to explain how this code is calculating number of holes. The ASCII value of TAB is 9 whose binary equivalent is 1001. The ASCII value of SPACE is 32 whose binary equivalent is 100000.

so bit wise anding TAB with 3 will result

            1001 & 0011 = 0001    which is 1

bit wise anding SPACE with 3 will result

            100000 & 000011 = 000000   which is 0

replacing TABs with 1 and SPACEs with 0 hence this concludes as writing

do{
    r += "1000001021"[n % 10] & 3;
    n/=10;
}while(n);

n % 10 is the low-order decimal digit of n. We use that as an index into a string literal, which contains information about how many holes is there in that low-order decimal digit then add it to result r.

0
cpatricio On

Using special chars in browsers can be a problem, from Ascii Table we can use all chars that in octal ends in 0 to 2 or 4 to 6, using those 2 bits to know how many holes the number have (% 3 is the same as % 0b11, an and with the last 2 bits).

One solution with ascii chars is:

int countIt(int n) {
    int r;
    while (r += "1000101021"[n % 10] & 3, n /= 10);
    return r;
}

Instead of "0" to "2", i could use something like this:

int countIt(int n) {
    int r;
    while (r += "! X0) I@*9"[n % 10] & 3, n /= 10);
    return r;
}

I don't know what chars he tried to use, but didn't work in the challenge website.

4
Igor Tandetnik On

Is that some kind of obfuscated C contest submission? Or code golf?


First, the weird declaration. It's just combining two unrelated declarations on one line. Just as

int x, y;

is equivalent to

int x;
int y;

so is your code equivalent to

int r;
int countIt(int n) {...}

It's a little known and, thankfully, little used quirk of the C grammar that you can do that.


The loop would become clearer if written this way:

do {
  r += "            2  "[n % 10] & 3;
  n /= 10;
} while (n);

It basically iterates over digits in the decimal representation of n.


Now the part of r += " 2 "[n % 10] & 3;. n % 10 is the low-order decimal digit of n. We use that as an index into a string literal (which is just an array of chars), then extract two low-order bits of the character's ASCII code and discard the rest. I'm pretty sure that, in the original program you copied this code from, the characters in that literal were not spaces, but rather certain unprintable characters chosen in such a way that the two low-order bits of their ASCII codes gave precisely the number of "holes" in the corresponding digit. 2 character is a red-herring - it's in position 12, but only characters 0 through 9 are actually used.

In other words, this part can be more clearly written this way:

static const int numHoles[10] = {1, 0, 0, 0, 1, 0, 1, 0, 2, 1};
int digit = n % 10;
r += numHoles[digit];

Put together, we have:

int countIt(int n) {
  // number of holes in digit      0  1  2  3  4  5  6  7  8  9
  static const int numHoles[10] = {1, 0, 0, 0, 1, 0, 1, 0, 2, 1};
  int r = 0;
  do {
    int digit = n % 10;
    r += numHoles[digit];
    n /= 10;
  } while (n);
  return r;
};