I'm currently reading 'The C Programming Language' by Kernighan & Richie and I'm struggling to work out what a line does. I think I'm just being a little stupid, and not quite understanding their explanation.
++ndigit[c-'0'];
I've had to change the program ever so slightly as ndigit
was previously giving me garbage values, so I just instantiate the array to 0, instead of traversing it with a for loop, and changing the values that way.
#include <stdio.h>
main()
{
int c, i, nwhite, nother;
int ndigit[10]= {0};
nwhite = nother = 0;
while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
printf("digits =");
for (i = 0; i < 10; i++)
printf (" %d", ndigit[i]);
printf (", white space = %d, other = %d\n", nwhite, nother);
}
Using the program as its input, we get this printed to the console -
digits = 7 2 0 0 0 0 0 0 0 1, white space = 104, other = 291
I understand that 7 2 0 0 0 0 0 0 0 1
is a count of how many times the single numbers appear in the input 0 appears 7 times, 1 appears twice etc.)
But, how does the ...[c-'0'];
'work'?
'0' is a char and it has value 48. You can look up any ASCII table in the google. It works this way because you read from the input char value not the int, so if you don't add "-'0'" part it will increment 48th cell of an array. Instead of "-'0'" you can put "-48", in my opinion it's more readable this way.
In C, when you have a variable
c
of type char, it actually stores some integer encoding of the char (usually the ASCII code). Soc-'0'
means the difference of the code of the character contained inc
and the character0
. Since the digits are in natural order it convert the digit in the associated number.Ascii is an encoding which gives consecutive id's to consecutive digits. As Eric Postpischil pointed out, the standard demands that property, even though the underlying encoding need not be ascii. Ascii is quite common though.
So whatever number
'0'
is mapped to,'1'
will be that number + 1. In essence:Subtracting
'0'
from a character which is a digit, will return its numeric value:Loog at ASCII wikipedia.
So In the ASCII Scheme the '0' char is the number 48, the char '1' is 41, and so on. So c - '0' is equivalent to c - 48. If c is '1' the expression became 49 - 48 = 1. So in few word 'c' - '0' convert a digit char ['0'-'9'] into an integer [0-9].
Edit 1 As suggested by @Eric Postpischil, ASCII is not part of ANSi C (nor c++). But is very common and all compiler I know use ASCII set.
The C standard requires that the characters '0' to '9' have consecutive values.
'0'
represents the value zero as a character and c is the value you enter it calculates to be like this :and so on ... i.e equal to the value of
c
ifc
is a digitc
gives you the current character. With the range checking you confirm it is a number by using its ASCII value Checkchr
column for0
, it says48
and for8
it says56
.So,'8'- '0'
gives56 - 48
=8
ndigit
is used to keep track of how many times a number occurs in with each element of the array representing the number of times its subscript has occured.ndigit[0]
will ggive you number of times0
has occurred and so on..ndigit[x]
gives number of timesx
appearedsuppose your
c
i.e current character is8
then'8' - '0'
will give you8
. so you getndigit[8]
and you++
that value [you initialised it to0
at start]