uewik
uewik

Reputation: 15

C: Pressing "Enter" works like EOF in terminal window

Recently I went through the section about pointer in the book C Programming Language from K&R. I wrote a C program that converts a word description to valid C:

//This program converts a word description like "x is a function returning
//a pointer to an array of pointers to functions returning char," which we will express as
//              x () * [] * () char
//                      to
//              char (*(*x())[])()

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAXTOKEN 100
#define BUFSIZE 100

enum { NAME, PARENS, BRACKETS};

char buf[BUFSIZE];
int bufp = 0;
int gettoken(void);
int tokentype;
char token[MAXTOKEN];
char out[1000];

main() {
    int type;
    char temp[MAXTOKEN];

    while (gettoken() != EOF) {
        strcpy_s(out, 1000, token);
        while ((type = gettoken()) != '\n')
            if (type == PARENS || type == BRACKETS)
                strcat_s(out, 1000, token);
            else
            if (type == '*') {
                sprintf_s(temp, MAXTOKEN, "(*%s)", out);
                strcpy_s(out, 1000, temp);
            } else
            if (type == NAME) {
                sprintf_s(temp, MAXTOKEN, "%s %s", token, out);
                strcpy_s(out, 1000, temp);
            } else
                printf("invalid input at %s\n", token);
        printf("%s\n", out);
    }
    return 0;
}

int gettoken(void) {
    int c, getch(void);
    void ungetch(int);
    char *p = token;

    while ((c = getch()) == ' ' || c == '\t')
        ;
    if (c == '(') {
        if ((c = getch()) == ')') {
            strcpy_s(token, MAXTOKEN, "()");
            return tokentype = PARENS;
        } else {
            ungetch(c);
            return tokentype = '(';
        }
    } else
    if (c == '[') {
        for (*p++ = c; (*p++ = getch()) != ']'; )
            ;
        *p = '\0';
        return tokentype = BRACKETS;
    } else
    if (isalpha(c)) {
        for (*p++ = c; isalnum(c = getch());)
            *p++ = c;
        *p = '\0';
        ungetch(c);
        return tokentype = NAME;
    } else
        return tokentype = c;
}

int getch(void) {
    return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c) {
    if (bufp >= BUFSIZE)
        printf("ungetch: too many characters\n");
    else
        buf[bufp++] = c;
}

The problem is that I can only input one line in terminal window. If I try to input the second line and press "Enter" button, the converted result will come out. It seems like Enter works like EOF(Ctrl+Z and Enter) in this program. Why could this happen? Do I miss some important point here? I am new to C so maybe some stupid mistakes have been made. I use Visual Studio 2015 so some library functions like strcpy are replaced with _s alternatives. Thanks for you time and help!

Upvotes: 1

Views: 77

Answers (1)

chqrlie
chqrlie

Reputation: 144780

Your code has several problems:

  • You do not handle EOF consistently: you should not let ungetch(EOF) store character \377 to buf. Re-reading it from buf may or may not produce -1, depending on whether char is signed or not by default. Non ASCII characters are not handled correctly because of this. You should make buf an array of int.
  • Why you parse the bracketed characters, you do not test EOF, check buffer boundaries . You would invoke undefined behavior if EOF is encountered during this phase, or if too many characters are read before the ].
  • You should not declare getch() and ungetch() at local scope inside gettoken(). These forward declarations belong in the global scope.
  • The prototype for main should be int main(void) or int main(int argc, char *argv[]), not an obsolete incomplete main().
  • In main, the inner loop iterates until '\n' is read. You will not detect EOF correctly here. Incidentally, it should have the exact opposite effect to what you observe.
  • Note that you should use {} braces around any non trivial block: the 11 line if statement that forms the body of the while ((type = gettoken()) != '\n') in main is a single statement, but for readability and sturdiness, it is recommended that you put that in a block.

I am not sure which issue causes your problem or if it comes from some other source, but you should try and fix these first.

Upvotes: 1

Related Questions