简体   繁体   中英

Need help in understanding order of evaluation of expression in C

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!

= 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] .

  1. This is the so called chained assignment, see wiki . To understand it, you only need to know that assignment in C has value! Therefore, you can thing of it as equivalent to a one-liner of multiple successive assignment from right to left, as @hacks mentioned.

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';

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 , ie 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; ie 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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM