tags:

views:

152

answers:

4

I'm trying to understand how this exactly works (I know what it does, I just don't understand how). As far as I know, this reads a char until EOF is reached, and if its a digit, put it in the array:

while ((c = getchar()) != EOF)
  if (c >= '0' && c <= '9')
    ++ndigit[c-'0'];

I understand I can index an array like this:

some_array[1] = 12;

which will put 12 in the second element.

What does the c-'0' do ?

(I got this from the book The C programming language 2nd edition from K&R)

+5  A: 

'0' is a char which has a decimal value of 48 when coerced to an integer. It works because char is a built-in ordinal type.

If you look at the disassembly, you can see this in action:

      if (c >= '0' && c <= '9')
004135E3  movsx       eax,byte ptr [ebp-9] 
004135E7  cmp         eax,30h 
004135EA  jl          wmain+6Eh (41360Eh) 
004135EC  movsx       eax,byte ptr [ebp-9] 
004135F0  cmp         eax,39h 
004135F3  jg          wmain+6Eh (41360Eh)

Notice we're comparing against 30 hex and 39 hex, not '0' and '9'.

jeffamaphone
how can I reveal the disassembly ?
zlack
I used visual studio. Just set a breakpoint at the beginning of the function, then when it hits, RightClick->Go to disassembly...
jeffamaphone
+3  A: 

Actually what that's doing is counting how many times you count each digit. So you have an array like:

int ndigit[10] = { 0 }; // Start with all zeros

Given an ASCII digit from '0' to '9', c-'0' converts it from an ASCII digit to a simple integer from 0 to 9. That is, the character '0' which is 48 in ASCII is subtracted from each character, so they go from 48 through 57 to 0 through 9.

Then this number 0 through 9 is used an an index into the array, and that index is incremented by one. Thus ndigit counts how many times each digit is typed.

John Kugelman
+1  A: 

According to the ASCII table, character 0 is the ASCII representation of the value 48. Since characters 0 to 9 are representations of numbers 48 to 57, you can convert each character to the actual digit by subtracting 48.

So, instead of writing ndigit[c-48], common practice is to write it as ndigit[c-'0'] to indicate that you are converting the ASCII value of your character to a digit.

You can easily check this:

 char c = '0';
 printf("%d", c); // prints 48
 printf("%d", c - `0`); // prints 0 -- that's what we are looking for
Groo
A: 

c is a char, which can be converted to an int using a widening conversion (8 bits to however many bits an int has on your platform).

c - '0' subtracts the integer value of '0' from the integer value of 'c'.

The ASCII values for the characters '0' to '9' are sequential, so for characters in the range '0' to '9', subtracting the value of '0' from the value of c gives you an integer in the range 0 - 9.

richj