小学科学作业计算器c语言,c语言简略科学计算器

c语言简单科学计算器

算符优先法的思想。

#include

#include

#include

#include

#include

#define MAX_TOKEN_LEN 100 //标记最大长度

#define EXPR_INCREMENT 20//表达式长度的增量

typedef struct {

double opnd; //操作数

char optr[11]; //运算符

int flag; //若为1,则为单目运算符,2则是双目运算符

} SElemType; //栈元素类型

typedef struct SNode { //栈

SElemType date;

struct SNode * next;

} SNode, *Stack;

struct { //用来存储一个操作数或运算符

char str[MAX_TOKEN_LEN];

int type; //类型,若为0,则为操作数,若为1则为运算符

} token;

struct { //expression,用来存储表达式

char *str;

int cur; //标记读取expr的当前位置

}expr;

Stack OPND, OPTR; //操作数栈operand,运算符栈operator

int expr_size; //表达式长度

void InitStack(Stack *S) { //初始化栈

*S = (Stack)malloc(sizeof(SNode));

if(!(*S)) {

printf("动态申请内存失败!\n");

exit(0);

} //if

(*S)->next = NULL;

} //InitStack

void DestroyStack(Stack *S) { //销毁栈

SNode *p;

while(p = *S) {

*S = p->next;

free(p);

} //while

} //DestroyStack

void Push(Stack S, SElemType e) { //入栈

SNode *p;

p = (SNode *)malloc(sizeof(SNode));

if(! p) {

printf("动态申请内存失败!\n");

exit(0);

} //if

strcpy(p->date.optr,e.optr);

p->date.opnd = e.opnd;

p->date.flag = e.flag;

p->next = S->next;

S->next = p;

} //Push

void Pop(Stack S,SElemType *e) { //出栈

SNode *p;

p = S->next;

if(! p) {

printf("栈为空,不能出栈!\n");

exit(0);

} //if

S->next = p->next;

strcpy(e->optr,p->date.optr);

e->opnd = p->date.opnd;

e->flag = p->date.flag;

free(p);

} //Pop

void get_expr() { //获取expr字符串

char *p;

int size;

expr.cur = 0;

expr_size = 100;

expr.str = (char*)malloc(expr_size * sizeof(char));

if(! expr.str) {

printf("内存分配失败!\n");

exit(0);

} //if

size = 0;

p = expr.str;

while((*p = getchar()) != '\n') {

if(*p != ' ') {

if((*p >= 'A') && (*p <= 'Z')) {

*p = *p + 32; //将大写转换成小写

} //if

p++;

size++;

if(size == expr_size-1) { //此时expr.str已满,将其扩大

expr_size += EXPR_INCREMENT;

expr.str = (char*)realloc(expr.str,expr_size * sizeof(char));

if(! expr.str) {

printf("内存分配失败!\n");

exit(0);

} //if

p = &expr.str[size]; //realloc后需重新指定p

} //if

} //if

} //while

*p++ = '#';

*p = '\0';

} //get_expr

int IsOpnd(char ch) { //判断ch是否是操作数的一部分

if((ch >= '0') && (ch <= '9') || (ch == '.')) {

return 1;

} //if

if((ch == '-') || (ch == '+')) { //如若+-前面是'#'或'(',则为正负号

if((expr.cur == 0) || (expr.str[expr.cur-1] == '(')) {

return 1;

} //if

} //if

return 0;

} //IsOpnd

void gettoken() { //获取一个标记

char *p = token.str;

*p = expr.str[expr.cur];

if(IsOpnd(*p)) {

while(IsOpnd(*++p = expr.str[++expr.cur])); //注意是分号结尾

*p = '\0';

token.type = 0; //将标记类型设定为操作数

return;

} //if

if((*p >= 'a') && (*p <= 'z')) { //接收sin,tan,ln之类的函数运算符或操作数

while((expr.str[expr.cur+1] >= 'a') && (expr.str[expr.cur+1] <= 'z')) {

*++p = expr.str[++expr.cur];

} //while

} //if

++expr.cur;

*++p = '\0';

if(!strcmp(token.str,"e")) { //e为欧拉数,既自然对数的底数

sprintf(token.str,"%.16g",exp(1));//springf是库函数,功能是将显示在屏幕上的内容储存在字符串中

token.type = 0;

return;

} //if

if(!strcmp(token.str,"pi")) { //pi为圆周率

//sprintf(token.str,"%.16g",exp(1));//springf是库函数,功能是将显示在屏幕上的内容储存在字符串中

strcpy(token.str,"3.1415926535897932");

token.type = 0;

return;

} //if

token.type = 1; //将标记类型设定为运算符

} //gettoken

char Precede(SElemType *optr1, SElemType *optr2) { //返回优先关系

char *str1,*str2;

str1 = optr1->optr;

str2 = optr2->optr;

if(!strcmp(str1,"ln") || !strcmp(str1,"lg") || !strcmp(str1,"sin") || !strcmp(str1,"cos") || !strcmp(str1,"tan")) {

optr1->flag = 1; //这些均为单目运算符

return (!strcmp(str2,"(") || !strcmp(str2,"^") || !strcmp(str2,"!")) ? '';

} //if

if(!strcmp(str1,"!")) {

optr1->flag = 1;

return '>';

} //if

optr1->flag = 2;

switch(str1[0]) {

case '+': case '-': return (!strcmp(str2,"+") ||!strcmp(str2,"-") || !strcmp(str2,")") || !strcmp(str2,"#")) ? '>' : '

case '*': case '/': return (!strcmp(str2,"+") || !strcmp(str2,"-") ||!strcmp(str2,"*") ||

!strcmp(str2,"/") || !strcmp(str2,")") || !strcmp(str2,"#")) ? '>' : '

case '(': return !strcmp(str2,")") ? '=' : '

case ')': return '>';

case '^': return (!strcmp(str2,"(") || !strcmp(str2,"!") || !strcmp(str2,"^")) ? '';

case '#': return !strcmp(str2,"#") ? '=' : '

} //switch

} //Precede

long factorial(long n) { //阶乘

return (n <= 1) ? 1 : n * factorial(n-1);

} //factorial

SElemType Operate(SElemType opnd1, SElemType optr, SElemType opnd2) { //计算

SElemType temp;

if(optr.flag == 1) {

if(!strcmp(optr.optr,"!")) temp.opnd = factorial((long)opnd2.opnd);

else if(!strcmp(optr.optr,"lg")) temp.opnd = log10(opnd2.opnd);

else if(!strcmp(optr.optr,"ln")) temp.opnd = log(opnd2.opnd);

else if(!strcmp(optr.optr,"sin")) temp.opnd = sin(opnd2.opnd);

else if(!strcmp(optr.optr,"cos")) temp.opnd = cos(opnd2.opnd);

else if(!strcmp(optr.optr,"tan")) temp.opnd = tan(opnd2.opnd);

return temp;

} //if

switch(optr.optr[0]) {

case '+': temp.opnd = opnd1.opnd + opnd2.opnd; break;

case '-': temp.opnd = opnd1.opnd - opnd2.opnd; break;

case '*': temp.opnd = opnd1.opnd * opnd2.opnd; break;

case '/': temp.opnd = opnd1.opnd / opnd2.opnd; break;

case '^': temp.opnd = pow(opnd1.opnd,opnd2.opnd);

} //switch

return temp;

} //Operate

int main() {

SElemType optr,opnd1,opnd2;

printf("\n欢迎使用简易科学计算器!\n");

printf("欧拉数为e,圆周率为pi,退出则输入quit!\n");

printf("优先级:括号高于'!'高于'^'高于lg,ln,sin,cos,tan高于*,/高于+,-\n");

printf("请输入计算表达式:\n\n");

while(1) {

get_expr();

if(!strcmp(expr.str,"quit#")) {

return 0;

} //if

InitStack(&OPTR);

InitStack(&OPND);

strcpy(optr.optr,"#");

Push(OPTR, optr);

gettoken(); //从expr.str中获取一个标记(操作数或运算符)

while(strcmp(token.str,"#") || strcmp(OPTR->next->date.optr,"#")) {

if(token.type) { //说明token存储的是运算符

strcpy(optr.optr,token.str);

switch(Precede(&(OPTR->next->date),&optr)) {

case '

strcpy(optr.optr,token.str);

Push(OPTR,optr);

gettoken();

break;

case '=': //脱括号并接收下一字符

Pop(OPTR,&optr);

gettoken();

break;

case '>': //退栈并将运算结果入栈

Pop(OPTR,&optr);

Pop(OPND,&opnd2);

if(optr.flag == 2) { //是双目运算符才需另一个操作符

Pop(OPND,&opnd1);

} //if

Push(OPND,Operate(opnd1,optr,opnd2));

} //switch

} //if

else { //说明token存储的是操作数

opnd1.opnd = atof(token.str);

Push(OPND,opnd1);//atof将token.str转换为双精度数

gettoken(); //获取下一个标记

} //else

} //while

printf("%.16g\n\n",OPND->next->date.opnd);

free(expr.str);

DestroyStack(&OPTR);

DestroyStack(&OPND);

} //while

free(expr.str);

return 0;

} //main

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值