C语言 如何计算一个算术表达式使用递归,有问题的括号

62lalag4  于 2023-04-29  发布在  其他
关注(0)|答案(1)|浏览(125)

我正在尝试编写一段代码,它将从用户那里获取数学输入[示例:(1+2x3)、(2x(3+4))、(2x(3+4)-(6/2))。..]并使用递归打印结果。
我能够想出一个代码,适用于像例子中的表达式,然而,似乎表达式包含了太多的括号(例如:(2x((3+4)-(6/2))),((2x 3 +4)-(6/2))]给了我错误的答案。
不允许使用数组,所以我单独检查每个字符。另外,实际操作顺序并不相关,所有计算都需要从左到右进行,唯一重要的是括号。例如,(1+ 2x 3)= 9,而不是7。(1+(2x3))= 7。基本表达式必须以“(”开头,以“)”结尾。我也可以假设所有的数字都是从0到9。
这是主要功能。目前,我假设表达式是以有效的方式构建的,并且我通过确保第一个字符是“(”来启动递归,然后将0作为sort的默认值,因此nptnum在启动时已经是下一个字符。
中间的“1”用于括号计数,但是到目前为止,我还没有在代码中找到它的用途。

int main() {
    printf("enter an expression:\n") ;
    char nptnum ;
    int num = 0 ;

    scanf(" %c", &nptnum) ;
    if(nptnum == '('){
        scanf(" %c", &nptnum) ;
        num = elevator(0, 1, nptnum) ;
    }
    printf("this is num %d\n", num) ;

return 0 ;
}

这是递归代码。同样,到目前为止,bracketcounter还没有以有意义的方式使用
其目的是:
1.当到达(调用函数。
1.计算里面的一切直到到达)。
1.把这个数还回来。
1.重复

int elevator(int number, int brackets, char nptnum) {
    int bracketcount = brackets ;
    int num ;
    char operand ;

    num = number ;
   
    if(nptnum >= '0' && nptnum <= '9') {
        num = (nptnum - 48) ;
        scanf(" %c", &nptnum) ;
    }

    //if the first character is ) that means there is no calculation to be made
    if(nptnum == ')'){
        bracketcount--;
        return num ;
    }

    //get the operand  
    if(nptnum == '+' || nptnum == '-' || nptnum == '*' || nptnum == '/') {
        operand = nptnum ;
        scanf(" %c", &nptnum) ;
    }

    int num2 ;
    //recursion in case of new brackets
    if(nptnum == '(') {
        while(nptnum == '('){
            bracketcount++ ;
            scanf(" %c", &nptnum) ;
        }
        num2 = elevator(0, bracketcount, nptnum) ;
        scanf(" %c", &nptnum) ;

    } else if (nptnum >= '0' && nptnum <= '9') {
        num2 = (nptnum - 48) ;
        scanf(" %c", &nptnum) ;
        printf("third char: %c\n", nptnum) ;

    }
    int sum ;
    printf("num is: %d, num2 is: %d, op is : %c\n", num, num2, operand) ;

    //operator is a simple arithmetic calculation function 
    sum = operator(num, num2, operand) ;

    printf("op result %d\n", sum) ;
    printf("before check %c and bracket %d\n", nptnum, bracketcount) ;
    //a recursive call for the rest of the expression when there are no new brackets
    if(nptnum != ')'){
        bracketcount-- ;
        sum = elevator(sum, bracketcount, nptnum) ;
        printf("this is sum: %d\n", sum) ;
    }
    return sum ;
}

算子函数

int operator (int num1, int num2 , char op) {
    switch (op) {
        case '+' : {
            return (num1 + num2) ;
            break ;
        }
        case '-' : {
            return num1 - num2 ;
            break ;
        }
        case '*' : {
            return num1 * num2 ;
            break ;
        }
        case '/' : {
            return num1 / num2 ;
            break ;
        }
    }
}
vkc1a9a2

vkc1a9a21#

在评论的基础上,再加上一些我自己的评论:

  • 如果不验证输入表达式,则不需要显式计算括号的个数。相反,在读取左括号时进行递归,并在使用右括号时从该递归调用返回。这将自然地创建一个适当的左括号和右括号配对。
  • 如果你确实想验证,那么你可能仍然不需要 count 嵌套级别,但是你可能想传递一个参数,告诉你的解析器是否需要一个右括号。顶级调用(参见下一个)不需要右括号,而所有其他调用都需要右括号。
  • main()中,您不需要(可能也不应该)通过检查输入是否以括号开头并为这种情况提供特殊处理来启动计算。你的表达式计算器函数没有理由不能自己处理这个问题。
  • 这将非常自然地被写成递归下降解析器。Steve建议 * 重构 * 您现有的elevator()函数(奇怪的名字--您的意思是 evaluator 吗?)划分为几个职责范围更窄的职能部门。这将基于沿着以下路线建模表达式(Steve推荐了一个不同的,更传统的模型,包括乘法运算优先于加法运算):
    • 表达式 * 采用以下形式之一:
  • a primary,或
  • expressionoperatorprimary 的序列
  • primary 采用以下形式之一:
  • a(非负整数)* 数字 *,或
  • 序列'',* 表达式 *,''
  • operator 是其中之一:+-、*/(还是要x进行乘法运算?这个问题是不一致的,但有理由选择x。)

现有的代码解决了大部分问题,但如果将其重构为几个函数,这些函数更直接地Map到模型上,它会更清晰,更容易调试,并处理括号嵌套问题:

  • 顶级函数是get_expression()(或您首选的类似名称)。它这样做:

1.通过调用函数来解析 primary 以获得初始左操作数。
1.尝试读取一个 * 运算符 *(如果你喜欢,你可以有一个函数)。

  • 其中之一:
  • 如果读取了一个运算符,则解析另一个 primary 以获得右侧操作数,并使用该操作数以及左侧操作数和运算符来计算新的左侧操作数。然后回到(2);
  • 否则,左操作数是结果。如果读取的是右括号而不是运算符,那么应该将其推回,或者该函数应该有一种方法向其调用者发出信号。
  • 这取决于一个函数get_primary()(或类似的)来解析 primary。根据下一个字符,它执行以下操作之一:
  • 如果下一个字符是'',则此函数调用get_expression()来解析表达式,然后消耗结束'';
  • 否则,解析并返回一个 number

相关问题