Reputation: 39
I have troubles understanding how expression is evaluated in the below code. I do not understand how code works here
while (isdigit(s[++i] = c = getch()))
;
and why do we need
s[1] = '\0';
Full code
#include <ctype.h>
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;
}
Thank you for any help!
Upvotes: 0
Views: 157
Reputation: 141554
This whole function has a design flaw in that it is not possible to prevent a buffer overflow. It needs to know the size of buffer that s
is pointing to, to avoid that.
Anyway, while (isdigit(s[++i] = c = getch()));
has the same meaning as:
for (;;)
{
++i;
c = getch();
s[i] = c;
if ( ! isdigit(s[i]) )
break;
}
There is a reason that c
is used instead of just writing s[++i] = getch()
.
Here I am assuming that getch
(not a standard function) refers to some function which has the same return specification as getchar
, i.e. it returns either unsigned char
value or EOF
.
The int c;
is needed so that EOF
can be detected. If we did not have c
then there is no way of performing the test if ( c != EOF )
at the end of the function. Doing s[i] == EOF
would not work because it might mistake a valid character for EOF
(or EOF
might be out of range of char
).
However the code still has a bug. The isdigit
function expects the same sort of int
value; i.e. in my unpacked version, the final test should be:
if ( !isdigit(c) )
I'd guess that the code author knew about the issue with EOF
but either didn't know about isdigit
, or assumed his code would only be run on an implementation of it that accepted negative chars.
Writing it more compactly, the line could be replaced with:
i = 1;
// ...
while ( isdigit(c = getch()) )
s[i++] = c;
Upvotes: 1
Reputation: 4821
2.
s[1] = '\0';
This is a safety concern and a normal coding practice: you always pad the end of a string with '\0' in C. Since the input argument s[] is supposed to be a char array, thus you need to pad it.
Note that
s[1] will be overwritten if s[0] is a digit or '.',
in which case the 2nd or 3rd while loop will be executed. As before, you also need to pad the s[i] with '\0';
Upvotes: 1
Reputation: 106012
=
is right associative and therefore isdigit(s[++i] = c = getch())
will be grouped as
isdigit( s[++i] = (c = getch()) )
. getch
will read and assign a char
to c
and then c
is assigned to s[++i]
.
Upvotes: 2