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