Problem with the K&R - Learning C - Arrays - ASCII - c

I'm currently learning C from The C Programming Language by Brian W Kernighan and Dennis M. Ritchie. I've gotten to the arrays section, and ran into a problem. When arrays are discussed in this book, they use this program:
`#include <stdio.h>
/* This program count digits, white space, others */
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; ++i)
ndigit[i] = 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);}
}`
My question is: why the -'0' in ++ndigit[c-'0'];? What does it mean? I noticed when I get rid of it, the program will not function properly. Edit: I heard it has something to do with ASCII. I have no idea what that is.

If c is between '0' and '9', due to c standard '0' to '9' are encoded consecutively, c-'0' will give out the numerical result of c. Say c is '6', then c-'0'==6.

Related

Program occurrences that counts digits, white spaces and other stuff what's best,average and worst case

main()
{
int c, i , nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for(i = 0; i<10; ++i)
{
ndigit[i] = 0;
}
while((c = my_getchar(ndigit,nwhite,nother)) != EOF)
if(c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
}
so this is code from book, what's the best, average and worst case for increment itterations. for best case I realized that it's O(1) like when you have one input you always get only one increment but how about worst and average cases I am getting confused. Like whats worst and average case for increment operations in this code as you see ++ndigit, ++nwhite and ++nother are increment operations and I am wondering am I correct about best case? I would like to get little help with best average and worst cases for this increment operations.

The C programming Language Exercise 1-14

I have been reading and doing the exercises in the book
The C programming Language by Dennis M.Ritchie
The exercise is the 1-14
Write a program to print a histogram of the frequencies of different characters in its input
int c, i, j, k = 0;
int d, ci, nD = 0;
while ((c = getchar()) != EOF) {
if (c == 'a' || c == 'A')
++ci;
else if (c == 'D' || c == 'd')
++nD;
else if (c == 'B' || c == 'b')
++d;
else if (c == '\n')
printf("%d %d %d\n", d, ci, nD);
}
I have written this piece of code
It counts correctly for D but for A and B it just spits out some numbers
I haven't finished drawing the histogram as these numbers make it hard to do that
Here is the Input
Aa Bb Dd
Output
214732904 2293540 2
As for those number aren't they out of range of int type
You should initialize your variables correctly. If you don't they may contain any starting value.
Change
int d,ci,nD = 0 ;
to
int d = 0, ci = 0, nD = 0 ;

Check whether the input is digit or not in C programming

I am currently reading this book: The C Programming Language - By Kernighan and Ritchie (second Edition) and one of the examples I am having trouble understanding how to check whether the input is digit or not. The example is on Page 22, explaining under the array chapter.
Below is the example.
#include <stdio.h>
/* count digits, white space, others */
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; ++i)
{
ndigit[i] = 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);
}
For this example, what confused me is that the author mentioned that the line ++ndigit[c-'0'] checks whether the input character in c is a digit or not. However, I believe that only the if statement ( if (c>= '0' && c<= '9') ) is necessary, and it will check if c is digit or not. Plus, I do not understand why [c-'0'] will check the input(c) is digit or not while the input variable (c) is subtracted from the string-casting ('0').
Any suggestions/explanations would be really appreciated.
Thanks in advance :)
The if statement checks whether the character is a digit, and the ++ndigit[c-'0'] statement updates the count for that digit. When c is a character between '0' and '9', then c-'0' is a number between 0 and 9. To put it another way, the ASCII value for '0' is 48 decimal, '1' is 49, '2' is 50, etc. So c-'0' is the same as c-48, and converts 48,49,50,... to 0,1,2...
One way to improve your understanding is to add a printf to the code, e.g. replace
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
with
if (c >= '0' && c <= '9')
{
++ndigit[c-'0'];
printf( "is digit '%c' ASCII=%d array_index=%d\n", c, c, c-'0' );
}
I would try to explain with an example
suppose the input is abc12323
So the frequency of 1=1
frequency of 2=2
frequency of 3=2
if (c >= '0' && c <= '9') //checks whether c is a digit
++ndigit[c-'0'];
Now if you do printf("%d",c) then you will get the ascii value of the
character
for c='0' the ascii value will be 48,c='1' ascii value will be 49 and it goes
till 57 for c='9'.
In your program you are keeping a frequency of the digits in the input so you need to update the index of the digit in the array every time you get it
if you do ndigit[c]++ then it will update ndigit[48] for c='0',ndigit[49] for c='1'
So either you can do ndigit[c-'0']++ as ascii value of '0'=48 in decimal
or you can simply do ndigit[c-48]++ so for c='0' ndigit[0] is updated,c=1'
ndigit[1] is updated
you can check the re factored code here http://ideone.com/nWZxL1
Hope it helps you,Happy Coding

C array push, why subtract '0'?

I'm learning C from The C Programming Language, Second Edition. In it, there is the following code:
#include <stdio.h>
/* count digits, white space, others */
main() {
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i=0; i<10; ++i) {
ndigit[i] = 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);
}
Now, I can understand what this code is doing. It is counting how many times each digit appears in the input, and then putting that count into the index of the digit, ie 11123 = 0 3 1 1 0 0 0 0. I'm just curious about 1 line of it:
++ndigit[c-'0'];
This adds 1 to the index c of the array, but why does it subtract 0 from c? Surely that's pointless, right?
The expression c - '0' is converting from the character representation of a number to the actual integer value of the same digit. For example it converts the char '1' to the int 1
I think it makes a bit more sense to look at complete examples here
int charToInt(char c) {
return c - '0';
}
charToInt('4') // returns 4
charToInt('9') // returns 9
It's not subtracting zero... It's subtracting the ASCII value of the character '0'.
Doing so gives you an ordinal value for the digit, rather than its ASCII representation. In other words, it converts the characters '0' through '9' to the numbers 0 through 9, respectively.

Nothing showing up C beginner

I'm following along with a book on C to learn it and I am writing all the code in the book to follow along, the latest one to do with arrays is supposed to say how many white spaces, tabs etc. There are but when I execute it, nothing shows up, it's just blank, as in I can type something then press enter and nothing happens, is it supposed to tell me how many of each thing there is?
I am too new to understand if this program is actually supposed to output anything so I thought I would post it on here and get an opinion, it compiles and runs fine, no errors, but the book sort of refers to it outputting stuff, but nothing happens when I'm running it and typing stuff in, can just keep typing stuff forever.
Here is the code
#include <stdio.h>
int main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; ++i)
ndigit[i] = 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[1]);
printf(", white space = %d, other = %d\n", nwhite, nother);
}
The application takes in input some values and then counts the number of digits (0-9) and the white spaces. The key combination to interrupt the cycle is not ENTER but EOF which in Linux is CRTL-D and in WINDOWS is CTRL-Z.
Then, in you application there is a bug :
for (i = 0; i < 10; ++i)
printf(" %d", ndigit[1]);
In order to show the number of digits this should be :
for (i = 0; i < 10; ++i)
printf(" %d", ndigit[i]);
Unfortunately, getting interactive input is quite problematic when using scanf(), getchar(), fgets(), etc. That's why most people usually write their own custom functions, often getting a whole line from stdin and then parsing it according to their needs. However, if you want to use ENTER to stop the cycle you can modify the code as follows, but you will lose the possibility to count the number of new lines in the input.
#include <stdio.h>
int main(void)
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; ++i)
ndigit[i] = 0;
while ((c = getchar()) != '\n')
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);
return 0;
}
This should work as you expected. However, you should consider to write a better input function, there are several interesting solution online.
EDIT
The main() must return int. Not void, not bool, not float. int. Just int, nothing but int, only int. Some compilers accept void main(), but that is non-standard and shouldn't be used.
Check some examples here : http://www.parashift.com/c++-faq-lite/main-returns-int.html
You can provide a EOF using following
WINDOWS:
Press F6 then ENTER
or
Ctrl+Z
LINUX:
Ctrl+D
Change
printf(" %d", ndigit[1]);
to
printf(" %d", ndigit[i]);
Press ctrl+d to give EOF after entering value
Input:
2 4 6 8 //3 white space + 1 new line = 4 white space
[ctrl + d]
Output:
digits = 0 0 1 0 1 0 1 0 1 0, white space = 4, other =0

Resources