【问题标题】:C Calculator using parameters doesn't output anything使用参数的C计算器不输出任何东西
【发布时间】:2019-09-14 23:44:10
【问题描述】:

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

我收到了一些关于类型转换的警告,主要是在指针和 int 之间。我现在已经修复了所有这些,但最终的 printf 现在没有输出任何东西,当它完成时它给我的只是零,我的 numstack 似乎充满了垃圾,但我不明白为什么;即使明确地将其初始化为 32 0s 也不会改变这一点。最终目标是:

输入

计算 2 3 + 4 *

输出

20

输入可以是任意长度reverse polish notation数学表达式,它会解决它。现在我只关心 + - * / 但最终想添加幂模数等,以及一些练习集。我也意识到我的一些变量的大小写不一致,可能还有其他一些坏习惯,我正在努力解决这些问题

(如果有帮助,我会在 win10 上使用 tcc)

【问题讨论】:

  • pushNum(popNum + popNum); 是错误的。 popNum 是一个函数,在这个表达式中变成了指向函数的指针,不能添加指向函数的指针。您希望在此处调用popNum 返回的值是popNum()。编译器几乎肯定会给你一个错误信息。
  • 包含&lt;stdlib.h&gt; 以声明atoi
  • num = atoi(argv[args]);if(num &gt; 48)。重新考虑你在那里做什么。你如何测试一个字符串是否只包含数字字符?什么是数字字符?为什么要使用48 而不是'0'
  • @EricPostpischil 我完全错过了谢谢!我原以为 tcc 会说些什么,但令人惊讶的是根本没有。它抱怨围绕调用handleOp的指针转换,但从来没有。我看看我能不能把它带给开发者
  • handleOp(argv[args++][0]); 在输入数字后立即出现。但是你怎么知道一个数字后面的参数是一个运算符呢?在您给出的示例中,它不是:在“2 3 + 4 *”中,“2”之后的参数是数字,而不是运算符。

标签: c calculator postfix-notation


【解决方案1】:

由于您的代码中缺少任何合理的间距,您有大量问题变得更加难以发现。不要将多个表达式放在同一行上,您不会因节省的行数而获得报酬,并且请更好地为代码留出空间,这会使您的代码更具可读性(尤其是对于那些眼睛较老的人......)。例如,没有理由没有一个空格:

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 &lt; argtot) 而不是while (args &lt;= argtot)。回想一下,argv[argc] 是一个 NULL 指针。

除此之外,切勿在代码中使用atoi,除非用于测试。它提供了ZERO能力来评估转换是成功还是失败。您可以拥有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(还不错)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-31
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    相关资源
    最近更新 更多