I'm studying K&R book. Currently i'm reading function getop() at p.78. I do understand the code but i need clarifications about 2 things.
The code of getop() is as follows:
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;
}
My question is about: s[0]
in:
while ((s[0] = c = getch()) == ' ' || c == '\t')
The idea behind the while loop is to skip spaces and horizontal tab, so why are we saving 'c' in s[0]? Why the authors didn't simply write:
while (c= getch() == ' ' || c == '\t')
We are not going to use spaces and tabs later on, why do we need to save c in s[0]
for? What is the need for s[0]
here?
My second question is about:
s[1] = '\0';
Why are we assigning '\0' (end of string) to s[1]
here?
I have read some of the previous answers posted on stackoverflow.com about it but i'm not totally convinced!
The accepted answer about the above question is: "Because the function might return before the remaining input is read, and then s needs to be a complete (and terminated) string."
Ok. But what if input has one white space at the beginning and followed by an operand or operator? In this case, s[1] = '\0'
will close the string too early? isn't it?
In answer to your first question, the assignment to s[0]
in this case is a convenient coding shortcut. The value of c
is copied to s[0]
for every character read by getch()
, regardless of whether it will be used or discarded. If it is to be discarded, no big deal; it will be overwritten on the next iteration of the while()
loop. If it is to be used, then it has already been copied into its necessary location in the destination array s[]
.
In answer to your second question,
But what if input has one white space at the beginning and followed by an operand or operator?
Note that the previous while()
loop prevents white space characters (spaces and tabs) from appearing in s[0]
after exit from the loop. Therefore, after execution of
s[1] = '\0';
the s[]
string will consist of a single character that is neither a space nor a tab, followed by a string terminator.
In the next statement
if (!isdigit(c) && c != '.')
return c; /* not a number */
the function will return if the character is anything but a digit or a decimal point. This is why it was necessary to terminate the string.
But what if input has one white space at the beginning and followed by an operand or operator? In this case, s[1] = '\0' will close the string too early? isn't it?
Nope,
i = 0;
if (isdigit(c)) /* collect integer part */
while (isdigit(s[++i] = c = getch()))
This makes sure, that if there is something to be read, it will get overwritten on \0
, as i=0
and s[++i]
would mean, storing in s[1]
, which contains the \0
for your first question about: s[0] in:
while ((s[0] = c = getch()) == ' ' || c == '\t')
because the saving 'c' in s[0] help to storing first number in advanced so that we can start our next code from simply i equal to 1.
i = 0;
if (isdigit(c)) /* collect integer part */
while (isdigit(s[++i] = c = getch()))
the above code is used for storing next string character which is start from index i = 1
About your second question :
we can not do
s[0] = '\0';
because at that time we already stored first number in string at s[0]
see
(s[0] = c = getch())
来源:https://stackoverflow.com/questions/33299349/getop-function-kr-book-p-78