The C programming Language Exercise 1-14 - c

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 ;

Related

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

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.

How does the function getop() from "The C Programming Book" work?

int getop(char *s) {
int i, c;
while((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';
if(!isdigit(c) && c != '.') {
return c;
}
i = 0;
if(isdigit(c))
while(isdigit(s[++i] = c = getch()))
;
if(c == '.')
while(isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if(!isdigit(c))
ungetch(c);
return NUMBER;
}
I came across this fucntion while working on an example named "Reverse polish calculator".
we can input numbers for calculator operations via this function, but I'm not getting the working of this function. Like.,
if we enter some input like ---->
12.34 11.34 +
From
while((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';
s will contain 1. But from where does the remaining input goes inside s ?
I've gone through this function well and I came to know it's working but then I want to know the deep working, like the complete flow.
Any help is highly appriciated.
edit:-
After testing various inputs I came to the conclusion that what is the need for getch() and ungetch(), I mean yeah they are there to unread character that is not needed but than look at the test cases.,
int getop(char *s) {
int i, c;
while((s[0] = c = getchar()) == ' ' || c == '\t')
;
s[1] = '\0';
if(!isdigit(c) && c != '.') {
return c;
}
i = 0;
if(isdigit(c))
while(isdigit(s[++i] = c = getchar()))
;
if(c == '.')
while(isdigit(s[++i] = c = getchar()))
;
s[i] = '\0';
/* if(!isdigit(c))
ungetch(c);*/
return NUMBER;
}
Here I replaced getch() with getchar() and it still accepted the input
12a 12 -
and the output was absolutely correct and it unread 'a' character as well
144
and so was the case when I was using getch() ?
Lets break it down piece by piece:
while((s[0] = c = getch()) == ' ' || c == '\t') skips all spaces and tabulation from the beginning fo the string. At the end of this loop s[0] contains the first char which is not either of the two mentioned before.
Now if c is something other than . or a digit we simply return that.
if(!isdigit(c) && c != '.') {
return c;
}
If c is not a digit we are done and it's quite right to set s[1] to null!
Otherwise, if c is a digit we read as much digit chars as we can overwriting s from position 1. s[1] was '\0' but it does not matter because s[++i] would be s[1] at the very first iteration of
i = 0;
if(isdigit(c))
while(isdigit(s[++i] = c = getch()))
so s is kept in a consistent status.

How can I get the numbers from tupple?

I want to get an input from the user like (4,5).But I just want to get the integer values.(4 and 5) I wrote a code for this.But it did not work.How can I fix the problem.
int x, y;
int c;
c = getchar();
while (c != EOF) {
while (c != '(' && c != EOF) {
c = getchar();
}
while (c != ',' && c != EOF) {
c = getchar();
}
x = c;
while (c != ',' && c != EOF) {
c = getchar();
}
while (c != ')' && c != EOF) {
c = getchar();
}
y = c;
}
I get input(1,4). outputs is x= 44 and y= 45 ?
After you find the opening parenthesis, read characters while they are digits (see e.g. isdigit), and create your number.
When the character is not a digit, make sure it's a comma. If it is you read the next number the same as above. Finally make sure you got the closing parenthesis.
The above assumes that there are no whitespace between the parentheses and the numbers, or between the numbers or the comma. Those can be handled by looping and isspace.
As for converting digits to numbers, assuming your system is using ASCII encoding (which is standard on modern PC-like systems) then it's easy since you just subtract '0' from the character to get the digit (see the linked ASCII table to help you understand why). Store the value in a variable, initialized to zero, and multiply by ten as needed.
Depending on the parser you're writing, you could do the handling and recognition of tuples in the parser instead of the lexer. That would make it more flexible.
follow your code flow x value will be character comma.
int c ,x ,y;
c = getchar();
while (c != EOF) {
while (c != '(' && c != EOF) {
c = getchar();
}
c = getchar();
x = c;
while (c != ',' && c != EOF) {
c = getchar();
}
/*x = c;
while (c != ',' && c != EOF) {
c = getchar();
}
*/
c = getchar();
y = c;
while (c != ')' && c != EOF) {
c = getchar();
}
//y = c;
printf("x = %c ,y = %c ",x,y);
}

How does getchar_unlocked() work?

My question is based on a CodeChef problem called Lucky Four.
This is my code:
int count_four() {
int count = 0;
char c = getchar_unlocked();
while (c < '0' || c > '9')
c = getchar_unlocked();
while (c >= '0' && c <= '9') {
if (c == '4')
++count;
c = getchar_unlocked();
}
return count;
}
int main() {
int i, tc;
scanf("%d", &tc);
for (i = 0; i < tc; ++i) {
printf("%d\n", count_four());
}
return 0;
}
Let's say I make a slight change to count_four():
int count_four() {
int count = 0;
char c = getchar_unlocked();
while (c >= '0' && c <= '9') {
if (c == '4')
++count;
c = getchar_unlocked();
}
while (c < '0' || c > '9') // I moved this `while` loop
c = getchar_unlocked();
return count;
}
This is my output after moving the while loop below the other one:
0
3
0
1
0
instead of:
4
0
1
1
0
The input used to test the program:
5
447474
228
6664
40
81
Why is this happening? How do getchar() and getchar_unlocked() work?
getchar_unlocked is just a lower level function to read a byte from the stream without locking it. In a single thread program, it behaves exactly like getchar().
Your change in the count_four function changes its behavior completely.
The original function reads the standard input. It skips non digits, causing an infinite loop at end of file. It then counts digits until it gets a '4'. The count is returned.
Your version reads the input, it skips digits, counting occurrences of '4', it then skips non digits, with the same bug on EOF, and finally returns the count.

C - Noob error with simple 3-way comparison

Apologies for the dumb question, I'm a bit of a beginner and am having trouble understanding why the following code will not work correctly.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int j = ' ';
int check = 0;
printf("\nPlease enter A, B, or C\n");
j = getch();
while(check == 0)
{
if(j != 'A' || 'B' || 'C')
{
printf("\nInvalid entry, please enter either an A, B, or C\n");
j = getch();
}
else
{
check = 1;
}
}
}
All I want this simple program to do is take in either A, B, or C using getch() (Yes, I need to use getch()) and use my while loop to confirm the entry actually is either an A, a B, or a C. However, I run the program, and even when I enter an A, B, or a C, the program tells me my entry is not valid. Can someone help me here and tell me what I'm doing wrong?
I have a feeling this has to do with the fact that it reads in the character as an ASCII integer, but I'm really not sure how to fix this.
if(j != 'A' || 'B' || 'C')
is equivalent to
if(j != 'A' || 'B' != 0 || 'C' != 0)
Both 'B' and 'C' have non-zero value so the condition will always evaluate true.
I think you want to check that j isn't any of the values listed. If so, the line should be
if(j != 'A' && j != 'B' && j != 'C')
Do the following replacements:
int j = ' '; /* to */ char j = ' ';
if(j != 'A' || 'B' || 'C') /* to */ if(j != 'A' && j != 'B' && j != 'C')
j = getch(); /* to */ j=getchar();
Also, for getchar() to work, include <conio.h> if required.

Resources