使用参数的C计算器不输出任何内容

时间:2019-09-14 23:44:10

标签: c calculator postfix-notation

这里是代码(很抱歉,如果有废话格式,试图从控制台复制出来是愚蠢的(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)

1 个答案:

答案 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通常避免使用camelCaseMixedCase变量和函数名,而建议使用所有小写字母,同时保留大写名称以供宏和常量使用。这是风格问题-因此完全取决于您,但是如果不遵循它,可能会在某些圈子中导致错误的第一印象。参见例如NASA - C Style Guide, 1994(仍然不错)