简易科学计算器的设计

项目描述:嵌入式数据结构开发实训项目,独立完成简易科学计算器的设计;实现正负数的加、减、乘、除,支持欧拉数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 }

 

posted @ 2013-03-29 07:08  少女时代  阅读(506)  评论(0编辑  收藏  举报