• 简易科学计算器的设计


    项目描述:嵌入式数据结构开发实训项目,独立完成简易科学计算器的设计;实现正负数的加、减、乘、除,支持欧拉数e、圆周率π(pi)、求幂符号^、阶乘!、正弦sin、余弦cos、正切tan、以10为底的对数函数lg、以欧拉数e为底的对数函数ln,输入表达式,能够得出结果;熟练掌握结构体、指针、栈的使用。

    项目代码:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <math.h>
      5 #include <ctype.h>
      6 
      7 #define MAX_TOKEN_LEN 100   //标记最大长度
      8 #define EXPR_INCREMENT 20   //表达式长度的增量
      9 
     10 //栈元素类型
     11 typedef struct
     12 {
     13     double opnd;  //操作数
     14     char optr[11];  //运算符
     15     int flag;     //若为1,则是单目运算符;若为2,则是双目运算符
     16 }SElemType;
     17 
     18 //
     19 typedef struct SNode
     20 {
     21     SElemType data;
     22     struct SNode *next;
     23 }SNode, *Stack;
     24 
     25 //用来存储一个操作数或运算符
     26 struct
     27 {
     28     char str[MAX_TOKEN_LEN];
     29     int type;   //若为0,则是操作数;若为1,则是运算符
     30 }token;
     31 
     32 //用来存储表达式
     33 struct
     34 {
     35     char *str;
     36     int cur;  //标记读取表达式的当前位置
     37 }expr;
     38 
     39 Stack OPND,OPTR;  //操作数栈operand, 运算符栈operator
     40 int expr_size;      //表达式长度
     41 
     42 //初始化栈
     43 void InitStack(Stack *s)
     44 {
     45     *s = (Stack)malloc(sizeof(SNode));
     46     if (NULL == *s)
     47     {
     48         printf("动态内存申请失败.\n");
     49         exit(0);
     50     }
     51     (*s)->next = NULL;
     52 }
     53 
     54 //销毁栈
     55 void DestroyStack(Stack *s)
     56 {
     57     SNode *p;
     58     while (p = (*s))
     59     {
     60         (*s) = p->next;
     61         free(p);
     62     }
     63 }
     64 
     65 //入栈
     66 void Push(Stack s, SElemType e)
     67 {
     68     SNode *p;
     69     p = (SNode *)malloc(sizeof(SNode));
     70     if (NULL == p)
     71     {
     72         printf("动态内存申请失败.\n");
     73         exit(0);
     74     }
     75     strcpy(p->data.optr,e.optr);
     76     p->data.opnd = e.opnd;
     77     p->data.flag = e.flag;
     78     p->next = s->next;
     79     s->next = p;
     80     
     81 }
     82 
     83 //出栈
     84 void Pop(Stack s, SElemType *e)
     85 {
     86     SNode *p;
     87     p = s->next;
     88     if (NULL == p)
     89     {
     90         printf("栈为空,不能出栈.\n");
     91         exit(0);
     92     }
     93     s->next = p->next;
     94     strcpy(e->optr,p->data.optr);
     95     e->opnd = p->data.opnd;
     96     e->flag = p->data.flag;
     97     free(p);
     98 }
     99 
    100 //获取表达式字符串expr
    101 void get_expr()
    102 {
    103     char *p;
    104     int size;
    105     expr.cur = 0;
    106     expr_size = 100;
    107     expr.str = (char *)malloc(expr_size * sizeof(char));
    108     if (NULL == expr.str)
    109     {
    110         printf("动态内存申请失败.\n");
    111         exit(0);
    112     }
    113     size = 0;
    114     p = expr.str;
    115     while ((*p = getchar()) != '\n')
    116     {
    117         if (*p != ' ')
    118         {
    119             if ((*p >= 'A') && (*p <= 'Z'))
    120             {
    121                 *p = *p + 'a' - 'A'; //将大写字母转换成小写字母
    122             }
    123             p++;
    124             size++;
    125             if (size == expr_size - 1) //若expr.str已满,则将其扩大
    126             {
    127                 expr_size += EXPR_INCREMENT;
    128                 expr.str = (char *)realloc(expr.str,expr_size * sizeof(char));
    129                 if (NULL == expr.str)
    130                 {
    131                     printf("内存申请失败.\n");
    132                     exit(0);
    133                 }
    134                 p = &expr.str[size]; //realloc后需要重新指定p    
    135             }
    136         }
    137     }
    138     *p++ = '#';
    139     *p = '\0';
    140 }
    141 
    142 //判断ch是否为操作数的一部分
    143 int IsOpnd(char ch)
    144 {
    145     if (((ch >= '0') && (ch <= '9')) || (ch == '.'))
    146     {
    147         return 1;
    148     }
    149     if ((ch == '-') || (ch == '+'))  //如若+-前面是'#'或'(',则为正负号
    150     {
    151         if ((expr.cur == 0) || (expr.str[expr.cur - 1] == '('))
    152         {
    153             return 1;
    154         }
    155     }
    156     return 0;
    157 }
    158 
    159 //获取一个标记
    160 void gettoken()
    161 {
    162     char *p = token.str;
    163     *p = expr.str[expr.cur];
    164     if (0 != IsOpnd(*p))
    165     {
    166         while (IsOpnd(*++p = expr.str[++expr.cur]))
    167             ;
    168         *p = '\0';
    169         token.type = 0;  //将标记类型设定为操作数
    170         return;    
    171     }
    172     if ((*p >= 'a') && (*p <= 'z')) //接收sin,tan,ln之类的函数运算符或者操作数
    173     {
    174         while ((expr.str[expr.cur + 1] >= 'a') && (expr.str[expr.cur + 1] <= 'z'))
    175         {
    176             *++p = expr.str[++expr.cur];
    177         }
    178     }
    179     ++expr.cur;
    180     *++p = '\0';
    181     if (!strcmp(token.str,"e"))  //e为欧拉数,即自然对数的底数
    182     {
    183         sprintf(token.str,"%.16g",exp(1)); 
    184         token.type = 0;
    185         return;
    186     }
    187     if (!strcmp(token.str,"pi")) //pi为圆周率
    188     {
    189         strcpy(token.str,"3.14159265358997932");
    190         token.type = 0;
    191         return;
    192     }
    193     token.type = 1;  //将标记类型设定为运算符
    194 }
    195 
    196 //返回优先关系
    197 char Precede(SElemType *optr1, SElemType *optr2)
    198 {
    199     char *str1, *str2;
    200     str1 = optr1->optr;
    201     str2 = optr2->optr;
    202     if (!strcmp(str1,"ln") || !strcmp(str1,"lg") || !strcmp(str1,"sin") || !strcmp(str1,"cos") || !strcmp(str1,"tan"))
    203     {
    204         optr1->flag = 1;  //这些为单目运算符
    205         return (!strcmp(str2,"(") || !strcmp(str2,"^") || !strcmp(str2,"!")) ? '<' : '>';
    206     }
    207     if (!strcmp(str1,"!"))
    208     {
    209         optr1->flag = 1;
    210         return '>';
    211     }
    212     optr1->flag = 2;
    213     switch (str1[0])
    214     {
    215     case '+':
    216     case '-':
    217         return (!strcmp(str2,"+") || !strcmp(str2,"-") || !strcmp(str2,")") || !strcmp(str2,"#")) ? '>' : '<';
    218     case '*':
    219     case '/':
    220         return (!strcmp(str2,"+") || !strcmp(str2,"-") || !strcmp(str2,"*") || !strcmp(str2,"/") || !strcmp(str2,")") || !strcmp(str2,"#")) ? '>' : '<';
    221     case '(':
    222         return !strcmp(str2,")") ? '=' : '<';
    223     case ')':
    224         return '>';
    225     case '^':
    226         return (!strcmp(str2,"(") || !strcmp(str2,"!") || !strcmp(str2,"^")) ? '>' : '<';
    227     case '#':
    228         return !strcmp(str2,")") ? '=' : '<';
    229     }
    230 
    231     return 0;
    232 }
    233 
    234 //阶乘
    235 long factorial(long n)
    236 {
    237     return (n <= 1) ? 1 : n * factorial(n - 1);
    238 }
    239 
    240 //计算
    241 SElemType Operate(SElemType opnd1, SElemType optr, SElemType opnd2)
    242 {
    243     SElemType temp;
    244     if (optr.flag == 1)
    245     {
    246         if (!strcmp(optr.optr,"!"))
    247             temp.opnd = factorial((long)opnd2.opnd);
    248         else if (!strcmp(optr.optr,"lg"))
    249             temp.opnd = log10(opnd2.opnd);
    250         else if (!strcmp(optr.optr,"ln"))
    251             temp.opnd = log(opnd2.opnd);
    252         else if (!strcmp(optr.optr,"sin"))
    253             temp.opnd = sin(opnd2.opnd);
    254         else if (!strcmp(optr.optr,"cos"))
    255             temp.opnd = cos(opnd2.opnd);
    256         else if (!strcmp(optr.optr,"tan"))
    257             temp.opnd = tan(opnd2.opnd);
    258         return temp;        
    259     }
    260     
    261     switch (optr.optr[0])
    262     {
    263     case '+':
    264         temp.opnd = opnd1.opnd + opnd2.opnd;
    265         break;
    266     case '-':
    267         temp.opnd = opnd1.opnd - opnd2.opnd;
    268         break;
    269     case '*':
    270         temp.opnd = opnd1.opnd * opnd2.opnd;
    271         break;
    272     case '/':
    273         temp.opnd = opnd1.opnd / opnd2.opnd;
    274         break;
    275     case '^':
    276         temp.opnd = pow(opnd1.opnd, opnd2.opnd);
    277     }
    278     return temp;
    279 }
    280 
    281 int main()
    282 {
    283     SElemType optr, opnd1, opnd2;
    284 
    285     printf("\n欢迎使用简易科学计算器\n");
    286     printf("欧拉数为e,圆周率为pi,退出则输入quit\n");
    287     printf("优先级:括号 > ! > ^ > lg,ln,sin,cos,tan > *,/ > +,-\n");
    288     printf("请输入计算表达式:\n\n");
    289 
    290     while (1)
    291     {
    292         get_expr();
    293         if (!strcmp(expr.str,"quit#"))
    294         {
    295             return 0;
    296         }
    297     
    298         InitStack(&OPTR);
    299         InitStack(&OPND);
    300         strcpy(optr.optr, "#");
    301         Push(OPTR, optr);
    302         gettoken();
    303         while (strcmp(token.str, "#") || strcmp(OPTR->next->data.optr, "#"))
    304         {
    305             if (token.type)
    306             {
    307                 strcpy(optr.optr, token.str);
    308                 switch (Precede(&(OPTR->next->data), &optr))
    309                 {
    310                 case '<':
    311                     strcpy(optr.optr, token.str);
    312                     Push(OPTR, optr);
    313                     gettoken();
    314                     break;
    315                 case '=':
    316                     Pop(OPTR, &optr);
    317                     gettoken();
    318                     break;
    319                 case '>':
    320                     Pop(OPTR, &optr);
    321                     Pop(OPND, &opnd2);
    322                     if (optr.flag == 2)
    323                     {
    324                         Pop(OPND, &opnd1);
    325                     }
    326                     Push(OPND, Operate(opnd1,optr, opnd2));
    327                 }
    328             }
    329             else
    330             {
    331                 opnd1.opnd = atof(token.str);
    332                 Push(OPND, opnd1);
    333                 gettoken();
    334             }
    335         }
    336         printf("%.16g\n\n", OPND->next->data.opnd);
    337         free(expr.str);
    338         DestroyStack(&OPND);
    339         DestroyStack(&OPTR);
    340     }
    341     free(expr.str);
    342     return 0;
    343 }
  • 相关阅读:
    mvc Controller类介绍
    Mvc全局过滤器与Action排除
    MVC项目实践,在三层架构下实现SportsStore-03,Ninject控制器工厂等
    EF查询数据库框架的搭建
    MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等
    BootstrapTable与KnockoutJS相结合实现增删改查功能
    JSON详解
    Asp.net管道模型(管线模型)
    NET/ASP.NET MVC Controller 控制器(一:深入解析控制器运行原理)
    .NET/ASP.NET Routing路由(深入解析路由系统架构原理)
  • 原文地址:https://www.cnblogs.com/luciaark/p/Calculator.html
Copyright © 2020-2023  润新知