这里是代码(很抱歉,如果有废话格式,试图从控制台复制出来是愚蠢的(vim)):
#include <stdio.h>
void printhelp(){
printf("\nhelp\n"); /* TODO make this more accurate */
}
int numstack[32];
char numpointer = 0;
char pushNum(int in){
if(numpointer < 31)
numstack[numpointer++] = in;
else return 1;
return 0;
}
int popNum(){
printf("%i", numstack[numpointer]);
if(numpointer)
return numstack[numpointer--];
else return -1;
}
void handleOp(char op){
switch(op){
case '+':
pushNum(popNum + popNum);
break;
case '-':
pushNum(popNum - popNum);
break;
case '*':
pushNum(popNum * popNum);
break;
case '/':
pushNum(popNum / popNum);
break;
}
}
/* MAIN */
int main(int argc, char *argv[]){
switch(argc){
case 1:
printhelp();
return 0;
case 2:
if(argv[1][0] == '-'){
if(argv[1][1] == 'h')
printhelp();
return 0;
}
}
int args = 1;
int argtot = argc;
int num;
while(args <= argtot){
num = atoi(argv[args]);
if(num > 48)
pushNum(atoi(argv[args]));
handleOp(argv[args++][0]);
}
printf("total: %i", popNum());
return 0;
}
我有一些关于类型转换的警告,主要是在指针和整数之间。我现在已经修复了所有这些问题,但是最终的printf现在不输出任何东西,当它完成时,给我的结果是零,我的numstack似乎充满了垃圾,但是我不明白为什么;即使将其显式初始化为32 0也不会改变它。最终目标是为了实现以下目标:
输入
计算2 3 + 4 *
输出
20
其中输入可以是任何长度的reverse polish notation数学表达式,它将解决该问题。现在,我只关心+-* /,但最终想增加幂模数,并进行一些练习。我也意识到我的一些变量和其他一些不良习惯的大小写不一致,我正在努力解决这些问题
(如果有帮助,请在win10上使用tcc)
答案 0 :(得分:0)
由于代码中没有合理的间距,您有很多问题变得更加难以发现。不要在同一行上放置多个表达式,您不会从保存的行数中获得报酬,并且可以更好地间隔代码,这使您的代码更具可读性(尤其是对于那些老眼睛的人而言……)。例如,没有理由在以下位置没有空格:
pushNum(atoi(argv[args]));
在代码的每个步骤中添加验证,并为所有可能成功或失败的功能提供有意义的返回类型,以指示成功或失败。例如,如果传递给void handleOp(int op)
[1] 的字符是'z'
而不是运算符之一,该怎么办?更好:
int handleOp(int op)
{
switch(op){
...
default:
return 0;
}
return 1;
}
现在继续看代码中的基本逻辑错误。在popNum()
中,您return numstack[numpointer--];
是错误的。在将numpointer
用作索引之前,必须先将其递减。当前,您的代码也可能是return numstack[numpointer];
,因为这就是表达式的计算结果。为了正确起见,您可能需要使用前缀增量return numstack[--numpointer];
,或更简单的方法是:
int popNum()
{
if (numpointer--) /* must decrement numpointer BEFORE return */
return numstack[numpointer];
return -1;
}
接下来,您的代码不应像您尝试的那样进行编译,例如pushNum(popNum + popNum);
中的popNum
是函数指针,而不是popNum()
的求值返回。您的handleOp()
函数应该使用函数本身的返回值,例如
int handleOp(int op)
{
switch(op){
case '+':
pushNum(popNum() + popNum()); /* note the '()' making the function call */
break;
...
此外,此后,您的部门实际上被评估为divisor / dividend
(相反),而应为dividend / divisor
,以解决您可以使用的问题:
case '/':
{
int a = popNum(), b = popNum();
pushNum (b / a);
break;
}
在main()
中,您必须使用while (args < argtot)
而不是while (args <= argtot)
。回想一下,argv[argc]
是NULL
指针。
除此之外,除测试外,请勿在代码中使用atoi
。它提供零功能来评估转换是成功还是失败。您可能有atoi("dog")
,但它仍然不会告诉您事情出了问题,而您所知道的就是您从中得到了0
。相反,请始终使用strtoX
系列函数(例如strtol, strtoul, strtod, etc..
),在那里您可以完全验证每次转换。
这些是主要问题,尽管肯定还有更多。解决这些问题可以使其在您的示例中正常工作,该部门现在也可以正常工作。将这些修补程序放在一起,您可以执行以下操作:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
void printhelp() /* you are not paid on the no. of lines you save */
{
printf("\nhelp\n"); /* TODO make this more accurate */
}
int numstack[32]; /* avoid the use of global variables */
int numpointer = 0;
char pushNum(int in)
{
if (numpointer < 31) {
numstack[numpointer++] = in;
return 0;
}
return 1;
}
int popNum()
{
if (numpointer--) /* must decrement numpointer BEFORE return */
return numstack[numpointer];
return -1;
}
int handleOp(int op)
{
switch(op){
case '+':
pushNum(popNum() + popNum());
break;
case '-':
pushNum(popNum() - popNum());
break;
case '*':
pushNum(popNum() * popNum());
break;
case '/':
{
int a = popNum(), b = popNum();
pushNum (b / a);
break;
}
default:
return 0;
}
return 1;
}
/* MAIN */
int main(int argc, char *argv[]) {
int args = 1; /* declares vars at beginning of scope for those */
int argtot = argc; /* pour souls still stuck with C89 compilers */
int num;
switch (argc) {
case 1:
printhelp();
return 0;
case 2:
if (argv[1][0] == '-') {
if(argv[1][1] == 'h')
printhelp();
return 0;
}
}
while (args < argtot) {
if (isdigit (*argv[args])) { /* validate digit */
char *endptr = NULL;
num = strtol (argv[args], &endptr, 0); /* never use atoi */
if (endptr == argv[args]) { /* atoi provides ZERO validation */
fputs ("error: no digits converted.\n", stderr);
return 1;
}
else if (errno) {
fputs ("error: over/underflow occured.\n", stderr);
return 1;
}
else if (num < 0 || INT_MAX < num) {
fputs ("error: value negative or exceeds INT_MAX.\n", stderr);
return 1;
}
pushNum (num);
}
else {
if (!handleOp (*argv[args])) {
fputs ("error: unrecognized OP.\n", stderr);
return 1;
}
}
args++;
}
printf("total: %d\n", popNum());
return 0;
}
(注意:函数名后的'{'
开头通常在下一行(main() {
除外,在空格之前可以有空格)
使用/输出示例
$ ./bin/calcpostfix 2 3 + 4 '*'
total: 20
带除法:
$ ./bin/calcpostfix 2 3 + 4 '*' 5 '*' 10 /
total: 10
仔细检查一下,如果还有其他问题,请告诉我。
脚注:
1)尽管不是错误,但C通常避免使用camelCase
或MixedCase
变量和函数名,而建议使用所有小写字母,同时保留大写名称以供宏和常量使用。这是风格问题-因此完全取决于您,但是如果不遵循它,可能会在某些圈子中导致错误的第一印象。参见例如NASA - C Style Guide, 1994(仍然不错)