【C语言】计算器(支持括号和长式子)

  1. 目标:输入像(1+2*(3-4))/5+6=这样的计算式,程序可以识别并且得出最终结果。
  2. 思路:将计算式子存在一个数组里,然后进行有限次化简直至得出最简形式(一个值)。要化简的形式分为两种:
    1. 长式子的化简:即连续运算,比如:1+2+3
    2. 多余括号的化简:即这种形式:(数值),比如(1)+2,就变成1+2。
  3. 进程:已完成,未成功。由于发现了一个底层的问题,改动量太大,并且空闲时间不够了,所以放弃。
  4. 程序的问题:使用了char数组来存放计算式,而计算出非整数的时候,是无法储存的。用string数组也许可以解决这个问题。
  5. 收获:
    1. 技术上:
      1. 提醒了自己把int赋给char之后,再直接转型,即(int)char,得到的是原int的ASCII码。
      2. 对于数值的判断和在类型上的转换,活用ASCII码有时候比寻找各种冷门函数好。
    2. 思路上:没有完全落实结构化编程的思想(自顶向下;逐步细化;模块化设计;结构化编码),还是“脚踩西瓜皮,滑倒哪算哪”。用于在草稿纸上画思维导图、整理思路的时间太少了(比如:对于变量:哪些放在全局、哪些放在部分,如何命名以获得形式上的统一;对于功能:划分成哪几块、划分要细致到什么程度;对于进度的安排:编写程序的顺序是什么(如果有一个好的顺序,就可以边写边测,不会导致全部写完才能第一次测试,结果发现一开头就写错了)),导致后期要频繁更改前期的代码。事实上,最后放弃这个程序的原因,就是最前期的东西出错了。

以下是源代码:(编译器:VS 2017)

// 计算器支持括号.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"

char    allChar[100];
char    ch;
int     lenth = 0;

int main()
{
    void    newCalculate();



    newCalculate();


    return 0;
}

double  operateBasic(double x,double y,char ch) {
    //基本的四则运算
    double result;
    switch (ch)
    {
    case '+':   result = x + y; break;
    case '-':   result = x - y; break;
    case '*':   result = x * y; break;
    case '/':   result = x / y; break;
    default:printf("Error!\n");
    }

    return char(int(result+48));
}

void    newCalculate() {
    //一次新的计算
    int     getLenth();
    double  operatePro();
    char    ch;
    int     i=0;

    printf("Please put in your algebraic expression (End with '='):\n");
    //system("pause");

    while ((ch=getchar())!='\n')
    {
        allChar[i] = ch;
        i++;
    }
    lenth = getLenth();
    //system("pause");
    //调试:
    /*for (int i = 0; i < 5; i++)
    {
        printf("%c", allChar[i]);
    }*/
    operatePro();
}

double  operatePro() {
    //核心计算
    void    Simple_Sign();
    void    Simple_LongExpression();
    char    result;

    while (allChar[1]!='=')//即,代数式没有化到最简的形式(“数字”+“=”)
    {   
        Simple_LongExpression();
    }

    result = allChar[0];

    printf("\nThe result of your algebraic expression is:%c\n", result);

    system("pause");

    return result;
}

void    Simple_Sign() {
    //去掉 多余的括号【当出现这样的形式时,视为多余:(1)】,以及运算过程里出现的“#”
    void    operateDelete(int point);
    int     getLenth();
    for (int i = 0; i < lenth ; i++) {
        if (allChar[i] == '#')operateDelete(i);
    }

    for (int i = 0; i < lenth ; i++)
    {
        if (allChar[i] == '(' && (int)allChar[i + 1] >= 48 && (int)allChar[i + 1] <= 57 && allChar[i + 2] == ')') {
            operateDelete(i);
            operateDelete(i + 1);//不是(i+2)  因为operateDelete(i)之后,已经往前一位了
        }
    }

}

void    Simple_LongExpression() {
    //去掉多余的括号,以及运算过程里出现的#;化简长计算式
    double  operateBasic(double x, double y, char ch);
    void    Simple_Sign();
    int     getLenth();
    for (int i = 0; i < lenth ; i++)
    {
        //先乘除
        if (
            //(int)allChar[i] >= 48 && (int)allChar[i] <= 57 && (int)allChar[i+2] >= 48 && (int)allChar[i+2] <= 57 && 
            ((int)allChar[i + 1]==42 || (int)allChar[i + 1]==47 && allChar[i] != 42 && allChar[i] != 47 && allChar[i + 2] != 42 && allChar[i + 2] != 47)
            ) {
            allChar[i] = operateBasic((double)allChar[i] - 48, (double)allChar[i + 2] - 48, allChar[i + 1]);
            allChar[i + 1] = allChar[i + 2] = '#';
            Simple_Sign();
        }

        //后加减
        if (
            //(int)allChar[i] >= 48 && (int)allChar[i] <= 57 && (int)allChar[i + 2] >= 48 && (int)allChar[i + 2] <= 57 && 
            ((int)allChar[i + 1] == 43 || (int)allChar[i + 1] == 45) && allChar[i]!=43 && allChar[i] != 45 && allChar[i+2]!=43 && allChar[i + 2] != 45) {
            allChar[i] = operateBasic((double)allChar[i] - 48, (double)allChar[i + 2] - 48, allChar[i + 1]);
            allChar[i + 1] = allChar[i + 2] = '#';
            Simple_Sign();
        }
    }
}

int     getLenth() {
    //获得数组有效长度
    for (int i = 0; i < 100; i++) {
        if (allChar[i] == '=') {
            lenth = i;
            break;
        }
    }

    return lenth;
}

void    operateDelete(int point){
    //去杂
    int getLenth();

    for (int i = point; i < lenth ; i++) {
        allChar[i] = allChar[i + 1];
    }
}
  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对您的要求,我可以给您提供一些思路和代码示例。 首先,计算器需要支持负数,我们可以在输入表达式时,判断符号位是否为负号,如果是,则将后面的数字取反。具体的实现可以参考下面的代码: ```c #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define MAX_STACK_SIZE 100 //栈的最大容量 struct stack { int top; double data[MAX_STACK_SIZE]; }; //初始化栈 void init_stack(struct stack *s) { s->top = -1; } //判断栈是否为空 int is_empty(struct stack *s) { return s->top == -1; } //入栈 void push(struct stack *s, double val) { if (s->top == MAX_STACK_SIZE - 1) { printf("Stack overflow!\n"); exit(1); } s->top++; s->data[s->top] = val; } //出栈 double pop(struct stack *s) { if (is_empty(s)) { printf("Stack underflow!\n"); exit(1); } double val = s->data[s->top]; s->top--; return val; } //获取栈顶元素 double peek(struct stack *s) { if (is_empty(s)) { printf("Stack underflow!\n"); exit(1); } return s->data[s->top]; } //判断字符是否为数字 int is_digit(char c) { return c >= '0' && c <= '9'; } //计算表达式 double evaluate(char *expr) { struct stack nums, ops; init_stack(&nums); init_stack(&ops); int len = strlen(expr); int i = 0; while (i < len) { if (expr[i] == ' ') { i++; continue; } else if (is_digit(expr[i])) { double num = 0; while (i < len && is_digit(expr[i])) { num = num * 10 + (expr[i] - '0'); i++; } if (i < len && expr[i] == '.') { i++; double frac = 0.1; while (i < len && is_digit(expr[i])) { num += (expr[i] - '0') * frac; frac *= 0.1; i++; } } if (!is_empty(&ops) && peek(&ops) == '-') { num = -num; pop(&ops); push(&ops, '+'); } push(&nums, num); } else if (expr[i] == '(') { push(&ops, expr[i]); i++; } else if (expr[i] == ')') { while (peek(&ops) != '(') { char op = pop(&ops); double b = pop(&nums); double a = pop(&nums); switch (op) { case '+': push(&nums, a + b); break; case '-': push(&nums, a - b); break; case '*': push(&nums, a * b); break; case '/': push(&nums, a / b); break; } } pop(&ops); i++; } else { while (!is_empty(&ops) && peek(&ops) != '(' && peek(&ops) != ')') { char op = pop(&ops); double b = pop(&nums); double a = pop(&nums); switch (op) { case '+': push(&nums, a + b); break; case '-': push(&nums, a - b); break; case '*': push(&nums, a * b); break; case '/': push(&nums, a / b); break; } } push(&ops, expr[i]); i++; } } while (!is_empty(&ops)) { char op = pop(&ops); double b = pop(&nums); double a = pop(&nums); switch (op) { case '+': push(&nums, a + b); break; case '-': push(&nums, a - b); break; case '*': push(&nums, a * b); break; case '/': push(&nums, a / b); break; } } return pop(&nums); } int main() { char expr[100]; printf("请输入表达式:"); fgets(expr, sizeof(expr), stdin); double result = evaluate(expr); printf("计算结果为:%g\n", result); return 0; } ``` 接下来,计算器需要支持括号,我们可以在计算表达式时,遇到左括号就将其压入操作符栈中,遇到右括号就将操作符栈中的操作符依次弹出,并对数字栈中的数字进行相应的计算,直到遇到左括号为止。具体的实现可以参考上面的代码。 至此,我们就实现了一个支持负数和括号计算器

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值