小型计算器程序
这是一段出现在课本《c程序设计语言》中的程序,请高手解释一下具体的实现原理:
#include<stdio.h>
#include<stdlib.h>
#define MAXOP 100
#define NUMBER '\0'
int getop(char []);
void push(double);
double pop(void);
/* 逆波兰计算器程序 比如: 当输入: 4 5 - 6 8 * + 时, 则输出: 47 */
main()
{
int type;
double op2;
char s[MAXOP];
while ((type = getop(s)) != EOF){
switch (type) {
case NUMBER:
push(atof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if(op2 != 0.0)
push(pop() / op2);
else
printf("error: zero divisor\n");
break;
case '\n':
printf("\t%.8g\n", pop());
break;
default:
printf("error: unknown command %s\n", s);
break;
}
}
getch();
return 0;
}
#define MAXVAL 100
int sp = 0;
double val[MAXVAL];
void push(double f)
{
if (sp < MAXVAL)
val[sp++] = f;
else
printf("error: stack full, can't push %g\n", f);
}
double pop()
{
if(sp > 0)
return val[--sp];
else{
printf("error: stack empty\n");
return 0.0;
}
}
#include<ctype.h>
int getch(void);
void ungetch(int);
/* 请解释此段代码的工作原理 */
int getop(char s[])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0'; /* 此语句的作用? */
if (!isdigit(c) && c != '.')
return c;
i = 0;
if (isdigit(c))
while (isdigit(s[++i] = c = getch())) /* 收集整数部分 */
;
if (c == '.')
while (isdigit(s[++i] = c = getch())) /* 收集小数部分 */
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}
#define BUFSIZE 100
char buf[BUFSIZE];
int bufp = 0;
int getch(void) /* getch()函数在标准库里已定义, 这里再定义一次不会和标准库冲突吗?*/
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c)
{
if(bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
不好意思代码有点长,但觉得此程序很经典,想彻底了解一下,请高手指教。先谢谢啦
[解决办法]
int getop(char s[])
{
int i, c;
/**获取第一个非空字符**/
while ((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0'; /* 此语句的作用? */
/*******************
*答:这句没用。
*******************/
/**返回一个非数字,也非.的字符,也就是返回操作符(+-*/)**/
if (!isdigit(c) && c != '.')
return c;
/**下面获取一个数字**/
i = 0;
if (isdigit(c))
while (isdigit(s[++i] = c = getch())) /* 收集整数部分 */
;
if (c == '.')
while (isdigit(s[++i] = c = getch())) /* 收集小数部分 */
;
/**字符串结束符**/
s[i] = '\0';
/******************************************
*下面把最后一个字符放到缓冲区,
*下一个循环要从buf中读最后一个字符,
*如果buf为空则从stdin中读一个字符。
*其实BUFSIZE为1就够了。
******************************************/
if (c != EOF)
ungetch(c);
return NUMBER;
}
getch()不是标准函数,它是微软发明的函数。
你可以查一下《C参考大全》,或者直接看C99文档。
我这里没有微软的编译器,所以无法测试会不会冲突,
GCC上编译是没有问题的。
在微软编译器上是否会冲突就要看编译器是怎么做的了,
反正是微软自己发明的,微软想让它冲突就冲突,想不冲突也有办法。
[解决办法]
/* * 如果输入的第一个字符不是数字也不是小数点,那么把它写进s并返回此字符 * 否则读取完整的数字写入s,并返回一个标志NUMBER */int getop(char s[]) { int i, c; while ((s[0] = c = getch()) == ' ' || c == '\t') ; // 忽略空格和TAB s[1] = '\0'; // 使s成为一个有结束符的完整字符串 if (!isdigit(c) && c != '.') return c; // 如果第一个子符不是数字也不是小数点,那么就返回这个字符。这时候上面的s[1]=0就有用了,因为main里要把s当作字符串处理 i = 0; if (isdigit(c)) while (isdigit(s[++i] = c = getch())) /* 收集整数部分 */ ; // 把输入的数字保存到s,直到输入一个非数字 if (c == '.') while (isdigit(s[++i] = c = getch())) /* 收集小数部分 */ ; // 把输入的数字保存到s,直到输入一个非数字 s[i] = '\0'; //字符串结束符 if (c != EOF) ungetch(c); // 把一串数字后面紧跟着的第一个字符(很可能是运算符)保存到缓冲区,下次再读取 return NUMBER; }
[解决办法]
//其实是把整个输入的表达式当成一个字符串来看待int getop(char s[]) { int i, c; while ((s[0] = c = getch()) == ' ' || c == '\t') ; s[1] = '\0'; //'0'字符表示字符串结束的标志,当条件不满足时,结束输入。 if (!isdigit(c) && c != '.') //如果不是数字并且不是小数点则返回 return c; i = 0; if (isdigit(c)) //在没遇到小数点之前的数字都是整数部分 while (isdigit(s[++i] = c = getch())) /* 收集整数部分 */ ; if (c == '.')//遇到小数点后就是小数部分了 while (isdigit(s[++i] = c = getch())) /* 收集小数部分 */ ; s[i] = '\0'; //整个表达式输入结束 if (c != EOF) //只要字符串没结束就紧接着进行将数字输入 ungetch(c); return NUMBER; } #define BUFSIZE 100 char buf[BUFSIZE]; int bufp = 0; 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; }