经典项目实战——C语言实现多功能计算器,支持带括号等复杂运算,支持文本计算

前言:

​ 近期复习了数据结构与算法,于是刚好就写个小程序来巩固一下自己的记忆。知道大家很烦看长篇大论,因此简单的写了下。

功能描述

  1. 实现基本数学运算 +、-、*、/
  2. 实现带括号()复杂混合运算
  3. 实现开方,幂次运算(不使用官方C标准库)
  4. 针对输入的表达式具有异常判断及提示功能
  5. 可实现从文本文件中读取多个运算表达式进行计算

实现效果

因为本程序的主要目的是为了复习数据结构与算法,因此没有写的很复杂。下图为功能1、2、3、4的实现效果,成功实现。其中@代表开方运算,^代表幂方运算

在这里插入图片描述
提前准备一个文件,写入需要计算的表达式,如图下:

在这里插入图片描述
进行测试,测试结果如下:

在这里插入图片描述

同时将结果存于文本文件中:
在这里插入图片描述

实现原理

程序主要包括计算模块、输入处理模块、显示模块、窗口句柄设置模块等。

  • 输入处理模块:
    为了方便后续进行计算等操作,需要对用户输入的字符串进行简单的处理,处理结果就是每个数字(不是单个数字字符,是一组数字)。比如将输入的1+4.432*3+ (3 -1)处理为1 + 4.432 * 3 + ( 3 - 1 ),这样更方便于后期根据' '字符进行分割提前数字或操作符
  • 显示模块:
    显示模块没有很大的难度,就是根据Windows窗口句柄来设置输出的颜色等信息,展示一个彩色界面
  • 计算模块:
    计算模块就是根据处理后的字符串进行对应的计算,方法有很多,比较方便的是将输入的中缀表达式转换为后缀表达式,然后进行求值处理。比较关键的就是操作符优先级的处理规则

    为了方便计算,需要将中缀表达式转为后缀表达式,转换过程利用了栈

采用主要的数据结构:栈、字符串

主要代码

/*计算表达式*/
void calculateExpression(myStrs* expression, double* resultBuf, unsigned int* errBuf)
{
	for (int i = 0; i < expression->size; i++)
	{
		errBuf[i] = getValue(expression->data[i].str, &resultBuf[i]);
	}
}

ERROR_TYPE getValue(const char* expression, double* result)
{
	ERROR_TYPE error;
	if ((error = checkOperator(expression)) != NONE_ERROR) {
		return error;
	}
	myStrs infix;
	myStrs posfix;
	myDoubleStack doubleStack;
	initmyDoubleStack(&doubleStack);
	initMyStrs(&infix, DEFAULT_SIZE);
	initMyStrs(&posfix, DEFAULT_SIZE);
	separateString(expression, " ", &infix);
	if ((error = infixToPosfix(&infix, &posfix)) != NONE_ERROR)
	{
		return error;
	}
	for (int i = 0; i < posfix.size; i++)
	{
		if (!isContainOperator(posfix.data[i].str))//数字直接入栈
		{
			double num = atof(posfix.data[i].str);
			pushmyDoubleStack(&doubleStack, num);
		}
		else {
			if (strstr(posfix.data[i].str, "@")) {//((@4 + 2))
				double a = popmyDoubleStack(&doubleStack);
				pushmyDoubleStack(&doubleStack, sqrt(a));
			}
			else {
				double a = popmyDoubleStack(&doubleStack);
				double b = popmyDoubleStack(&doubleStack);
				if (strstr(posfix.data[i].str, "+"))
				{
					pushmyDoubleStack(&doubleStack, b + a);
				}
				else if (strstr(posfix.data[i].str, "-")) {
					pushmyDoubleStack(&doubleStack, b - a);
				}
				else if (strstr(posfix.data[i].str, "*")) {
					pushmyDoubleStack(&doubleStack, b * a);
				}
				else if (strstr(posfix.data[i].str, "/")) {
					if (a >= -DOUBLE_ZERO_NUM && a <= DOUBLE_ZERO_NUM)
					{
						return ERROR_DIVISOR_ZERO;
					}
					pushmyDoubleStack(&doubleStack, b / a);
				}
				else if (strstr(posfix.data[i].str, "^")) {
					pushmyDoubleStack(&doubleStack, pow(b, a));
				}
			}
		}
	}
	*result = topmyDoubleStack(&doubleStack);
	destoryMyStrs(&infix);
	destoryMyStrs(&posfix);
	return NONE_ERROR;
}
/*中缀转后缀*/
ERROR_TYPE infixToPosfix(myStrs* infix, myStrs* posfix)
{
	myCharStack charStack;
	initmyCharStack(&charStack);
	int index = 0;
	char posfixBuf[MAX_BUF_LEN] = { 0 };
	for (int i = 0; i < infix->size; i++)
	{
		char ch = infix->data[i].str[0];
		if (!isContainOperator(infix->data[i].str))//数 或 括号
		{
			//如果是 括号
			if (isParentheses(infix->data[i].str))
			{
				if (ch == '(')
				{
					pushmyCharStack(&charStack, ch);
				}
				else {// ')'
					while (!isEmptymyCharStack(&charStack) && topmyCharStack(&charStack) != '(')
					{
						char topChar = popmyCharStack(&charStack);
						posfixBuf[index++] = topChar;
						posfixBuf[index++] = ' ';
					}
					if (isEmptymyCharStack(&charStack)) return ERROR_FORMAT;
					else popmyCharStack(&charStack);
				}
			}
			else {//是数字
				strcat(posfixBuf, infix->data[i].str);
				index += strlen(infix->data[i].str);
				posfixBuf[index++] = ' ';
			}
		}//操作符
		else {
			//栈空 或者 栈顶是左括号 或者 优先级大于栈顶优先级,则入栈
			while (!isEmptymyCharStack(&charStack) && topmyCharStack(&charStack) != '(' && lessOrEqualTop(ch, topmyCharStack(&charStack)))
			{
				char topChar = popmyCharStack(&charStack);
				posfixBuf[index++] = topChar;
				posfixBuf[index++] = ' ';
			}
			pushmyCharStack(&charStack, ch);
		}
	}
	while (!isEmptymyCharStack(&charStack))
	{
		char topChar = popmyCharStack(&charStack);
		posfixBuf[index++] = topChar;
		posfixBuf[index++] = ' ';
	}
	if (strstr(posfixBuf, "("))
	{
		return ERROR_FORMAT;
	}
	separateString(posfixBuf, " ", posfix);
	return NONE_ERROR;
}

可进一步设计方向

  1. 实现超大数的 +、-、*、/运算,例如:1821293854612893461023894562349817 * 2346189460234192384617361238946 = ?

    需要考虑问题:
    	直接采用C语言原本的基本数据类型long long int 计算,溢出怎么半?改怎样解决?
    
    采用字符串来存储数据
    
  2. 进一步完善交互界面设计

  3. 加入更多运算方式sin、cos

  4. Qt设计界面

  • 7
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,下面是一个基于 C 语言的实现多位数括号且能运算负数的计算器的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define MAX_EXPR_LEN 100 int eval(char *expr); int get_num(char *expr, int *idx); int get_term(char *expr, int *idx); get_factor(char *expr, int *idx); int main() { char expr[MAX_EXPR_LEN + 1]; printf("请输入表达式:\n"); fgets(expr, MAX_EXPR_LEN, stdin); // 从标准输入中获取表达式 printf("结果是:%d\n", eval(expr)); return 0; } // 计算表达式的值 int eval(char *expr) { int idx = 0; int result = get_term(expr, &idx); while (expr[idx] != '\0') { if (expr[idx] == '+') { idx++; result += get_term(expr, &idx); } else if (expr[idx] == '-') { idx++; result -= get_term(expr, &idx); } else { break; } } return result; } // 获取数字 int get_num(char *expr, int *idx) { int num = 0; int sign = 1; if (expr[*idx] == '-') { sign = -1; (*idx)++; } while (isdigit(expr[*idx])) { num = num * 10 + (expr[*idx] - '0'); (*idx)++; } return sign * num; } // 获取项 int get_term(char *expr, int *idx) { int result = get_factor(expr, idx); while (expr[*idx] != '\0') { if (expr[*idx] == '*') { (*idx)++; result *= get_factor(expr, idx); } else if (expr[*idx] == '/') { (*idx)++; result /= get_factor(expr, idx); } else { break; } } return result; } // 获取因数 int get_factor(char *expr, int *idx) { int result; if (expr[*idx] == '(') { (*idx)++; result = eval(expr); (*idx)++; } else { result = get_num(expr, idx); } return result; } ``` 这个计算器可以处理加、减、乘、除和括号的多位数运算,同时还能处理负数。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值