C:按“Enter”在终端窗口中像EOF一样工作

时间:2016-03-13 21:46:58

标签: c visual-studio

最近,我浏览了K& R的C Programming Language一书中关于指针的部分。我写了一个C程序,将单词描述转换为有效的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;
}

问题是我只能在终端窗口中输入一行。如果我尝试输入第二行并按“Enter”按钮,转换后的结果将会出现。在这个程序中,Enter似乎像EOF(Ctrl + Z和Enter)一样工作。为什么会这样?我在这里错过了一些重点吗?我是C的新手,所以也许有些愚蠢的错误。我使用Visual Studio 2015,因此某些库函数(如strcpy)将替换为_s替代品。谢谢你的时间和帮助!

1 个答案:

答案 0 :(得分:1)

您的代码有几个问题:

  • 您不能始终如一地处理EOF:您不应让ungetch(EOF)将字符\377存储到buf。从buf重新读取它可能会产生-1,也可能不会产生-1,具体取决于默认情况下char是否已签名。因此,未正确处理非ASCII字符。您应该将buf数组int
  • 为什么要解析括号中的字符,不要测试EOF,检查缓冲区边界。如果在此阶段遇到EOF,或者在]之前读取了太多字符,则会调用未定义的行为。
  • 您不应在getch()内的本地范围内声明ungetch()gettoken()。这些前瞻性声明属于全球范围。
  • main的原型应该是int main(void)int main(int argc, char *argv[]),而不是过时的不完整main()
  • main中,内循环迭代直到读取'\n'。您不会在此处正确检测到EOF。顺便说一下,它应该与你观察到的效果完全相反。
  • 请注意,您应该在任何非平凡的块周围使用{}括号:构成ifwhile ((type = gettoken()) != '\n')的主体的11行main语句是单个语句,但为了便于阅读和坚固,建议您将其放在一个区块内。

我不确定哪个问题会导致您的问题,或者它是否来自其他来源,但您应该先尝试修复这些问题。