最近,我浏览了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替代品。谢谢你的时间和帮助!
答案 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
。顺便说一下,它应该与你观察到的效果完全相反。{}
括号:构成if
中while ((type = gettoken()) != '\n')
的主体的11行main
语句是单个语句,但为了便于阅读和坚固,建议您将其放在一个区块内。我不确定哪个问题会导致您的问题,或者它是否来自其他来源,但您应该先尝试修复这些问题。