Confusion about calculator program - c

int getop(char s[])
{
int i = 0, c, next;
/* Skip whitespace */
while((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';
/* Not a number but may contain a unary minus. */
if(!isdigit(c) && enter code herec != '.' && c != '-')
return c;
if(c == '-')
{
next = getch();
if(!isdigit(next) && next != '.')
return c;
c = next;
}
else
c = getch();
while(isdigit(s[++i] = c)) //HERE
c = getch();
if(c == '.') /* Collect fraction part. */
while(isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if(c != EOF)
ungetch(c);
return NUMBER;
};
what if there is no blank space or tab than what value will s[0] will initialize .......& what is the use of s[1]='\0'

what if there is no blank space or tab than what value will s[0] will intialize
The following loop will continue executing until getch() returns a character that's neither a space nor a tab:
while((s[0] = c = getch()) == ' ' || c == '\t')
;
what is the use of s[1]='\0'
It converts s into a C string of length 1, the only character of which has been read by getch(). The '\0' is the required NUL-terminator.

If there is no space or tab, you're stuck with an infinite loop.
s[1]='\0' is a way of marking the end so functions like strlen()
know when to stop reading through c strings. it's called "Null-Terminating" a string: http://chortle.ccsu.edu/assemblytutorial/Chapter-20/ass20_2.html

while((s[0] = c = getch()) == ' ' || c == '\t')
Read character until its not a tab or space.
s[1] = '\0';
Convert char array s to a proper string in C format (all strings in c must be terminated with a null byte, which is represented by '\0'.

Related

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.

Clarification in getop()

In Dennis Ritchie's "C programming Language" book,
In getop func,
he states that s[1]='\0'
why does he end the array on index 1? What's the significance and need?
In later part he does uses other parts of the array..
int getch(void);
void ungetch(int);
/* getop: get next character or numeric operand */
int getop(char s[])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';
if (!isdigit(c) && c != '.')
return c; /* not a number */
i = 0;
if (isdigit(c)) /* collect integer part */
while (isdigit(s[++i] = c = getch()))
;
if (c == '.') /* collect fraction part */
while (isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}
Because the function might return before the remaining input is read, and then s needs to be a complete (and terminated) string.
The zero char will be overwritten later, unless the test if (!isdigit(c) && c != '.') is true so that the function returns early. Some coding guidelines would discourage returns from the middle of a function, btw.
Only when the function returns early is the s[1] = '\0' relevant. Therefore, one could have coded
int getop(char s[])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t')
;
if (!isdigit(c) && c != '.')
{
s[1] = '\0'; /* Do this only when we return here */
return c; /* not a number */
}
i = 0;
if (isdigit(c)) /* collect integer part */
/* ... */
It is terse code. These guys knew their language and algorithms. But the snippet lacks error handling and thus depends on correct input (invalid input may let s be empty or let s overflow).
That is not untypical. Processing of valid data is often straightforward and short; handling all the contingencies makes the code convoluted and baroque.
s[] might be only a numeric operand like "+","-" etc.
In this case s[1] have to be '\0' to let s be a proper string.

query regarding getop() in K&R C

In the function below:
Why it is terminating the string initially by s[1] = '\0';?
after i = 0, why starting to take values from s[1] not from s[0]?
#define NUMBER '0'
#define MAXSIZE 100
char s[MAXSIZE];
/* getop: get next character or numeric operand */
int getop(char s[ ])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';
if (!isdigit(c) && c != '.')
return c; /* not a number */
i = 0;
if (isdigit(c)) /* collect integer part */
while (isdigit(s[++i] = c = getch()))
;
if (c == '.') /* collect fraction part */
while (isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}
The function appears to store its result in a pointer to a string, in C style zero terminated. The first getch line stores its result in s[0], and if it's not a digit or the period, it immediately returns. Storing a zero as the 2nd character makes sure the returned string is properly ended -- it contains only one character.
After that initial step you already have one valid character, and it's stored in s[0]. So, all next getch calls need to store from 1 onwards, or it would overwrite the first character entered.

How does `ungetch` work?

I searched everywhere, but I cannot find the answer to this! I'm working on the exercise from the K&R C books with a function they call getop. When it peeks at the next character from the input and sees that it isn't a digit, where does the character get stored when unget is called? I can compile and run the code so I know it works, I just want to know where the character has been stored.
int getop(char s[])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';
if (!isdigit(c) && c != '.')
return c; /* not a number */
i = 0;
if (isdigit(c)) /*collect integer part*/
while (isdigit(s[++i] = c = getch()))
;
if (c == '.') /*collect fraction part*/
while (isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}
It doesn't really peek, it reads the char into the stream's buffer. On an unbuffered stream, or when you've read nothing after opening the file or seeking, ungetc() isn't guaranteed to work.

Trying to understand this code and the getchar function

I'm trying to understand this code and I'm very confused:
I can't understand why is needed three time of the getchar function and I can't understand when the program is use that getchar functions.
The code is working very well and its took from here:
http://www.zetadev.com/svn/public/k&r/exercise.1-13.c
#include <stdio.h>
/* Exercise 1-13: Write a program to print a histogram of the lengths of words
in its input. It is easy to draw the histogram with the bars horizontal; a
vertical orientation is more challenging. */
/* At this point we haven't learned how to dynamically resize an array, and we
haven't learned how to buffer input, so that we could loop through it twice.
Therefore, I'm going to make an assumption that no word in the input will be
longer than 45 characters (per Wikipedia). */
#define MAX_WORD_LENGTH 45 /* maximum word length we will support */
main()
{
int i, j; /* counters */
int c; /* current character in input */
int length; /* length of the current word */
int lengths[MAX_WORD_LENGTH]; /* one for each possible histogram bar */
int overlong_words; /* number of words that were too long */
for (i = 0; i < MAX_WORD_LENGTH; ++i)
lengths[i] = 0;
overlong_words = 0;
while((c = getchar()) != EOF)
if (c == ' ' || c == '\t' || c == '\n')
while ((c = getchar()) && c == ' ' || c == '\t' || c == '\n')
;
else {
length = 1;
while ((c = getchar()) && c != ' ' && c != '\t' && c != '\n')
++length;
if (length < MAX_WORD_LENGTH)
++lengths[length];
else
++overlong_words;
}
printf("Histogram by Word Lengths\n");
printf("=========================\n");
for (i = 0; i < MAX_WORD_LENGTH; ++i) {
if (lengths[i] != 0) {
printf("%2d ", i);
for (j = 0; j < lengths[i]; ++j)
putchar('#');
putchar('\n');
}
}
}
This getchar() is used to make sure that when EOF is reached, the program
gets out of the while loop.
while((c = getchar()) != EOF)
This getchar is also in a while loop. It makes sure that the whitespace characters ' ', '\t', and '\n' are skipped.
while ((c = getchar()) && c == ' ' || c == '\t' || c == '\n')
;
To make the program more robust, the above line should really be:
while ((c = getchar()) != EOF && isspace(c))
This getchar is also in a while loop. It thinks that any character that is not a ' ', '\t', or '\n' is a word character and increments length for each such character.
while ((c = getchar()) && c != ' ' && c != '\t' && c != '\n')
++length;
Once again, to make the program more robust, the above line should really be:
while ((c = getchar()) != EOF && !isspace(c))
The function getchar() reads and returns a character from the standard input device.
Syntax is variable name = getchar(), variable can be of type int or char.
Here is the explanation for each getchar() call.
while((c = getchar()) != EOF)
This will check if you input EOF (i.e Ctrl+D in unix and Ctrl+Z in Windows system)
if (c == ' ' || c == '\t' || c == '\n')
while ((c = getchar()) && c == ' ' || c == '\t' || c == '\n');
This will check if you input space, tab and new line character if yes then skip those and return to while((c = getchar()) != EOF)
length = 1;
while ((c = getchar()) && c != ' ' && c != '\t' && c != '\n')
++length;
Anyother character other than space, tab and new line character will result in executing ++length.

Resources