C语言:四则计算器(支持小数,括号和次方幂 组合输入计算)

之前已经写过一个计算器,每次回顾都觉得很复杂,一直在考虑重新写一个

  1. 支持小数运算
  2. 存储数据改为了double类型
  3. 支持整数次方
  4. 运算中乘法可以用x或者*表示,两个都支持
  5. 平台visual 存储数据改为了double类型
  6. 平台visual studio 2015通过,macOS上gcc通过
  7. 另外:输入的时候输入法最好是英文状态另外:输入的时候输入法最好是英文状态

公式读入后存储模式如下:
这里写图片描述

大概说一下计算流程:
1:将输入的文本提取出运算符,数字,次方和等级四类
2:每次运算找到当前的最高等级,先计算次方,再计算四则运算
3:计算结果覆盖至第二个aNum结构体的data,并废弃第一个结构体
4:2、3循环

输入的公式拆分成data,oper(operator)和class三类 data:即为公式中的每个数字 oper:±*/运算符
class:符号的运算等级(类似于优先级)

讲一下我构造class的这个思路:
在括号外的公式中,±的运算等级(class)为1,/的运算等级为2
在括号内的公式中,±对应等级为3(大于括号外的
/等级),而*/的等级为4

在这次的计算中,我把计算单独拿了出来
函数:float compute(float num1, float num2, char opt)
一次只运算一对数字,而每对计算的先后顺序就根据class等级值

每一个struct aNum用了链表来连接,利于计算后的数据处理

例:

输入:3+5x(2+1)-7
第一次运算时,找到最高的class,即存储“data=2,oper=’+’,class=3”的struct,2+1=3,而当前struct就不能再留下了,此时就把结果3覆盖到下一个struct的data上,然后抛弃当前存储“data=2”的struct,即p_front->next=p->next;每次计算如此循环

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define INIT_STRING_SIZE 100
#define True 1
#define False 0
int saved_class[4] = { 0, 0, 0, 0 };
typedef struct aNum {
	double data;
	char oper;
	int dataClass;
	int power;
	struct aNum *next;
}num;
typedef struct {
	char *formula;
	int length;
}string;

void setNULL(char *num)//清空一个字符串
{
	int i = 0;
	while (i<5)
	{
		num[i] = NULL;
		++i;
	}
}
int countOperators(string *input, int &counter)//processing step 1
{//计算运算符个数
	int i = 0;
	while (input->formula[i] != '\0')
	{
		switch (input->formula[i++])
		{
		case '+':
		case '-':
		case '*':
		case '/':++counter; break;
		default:break;
		}
		++input->length;
	}
	return 1;
}
int getData(string *input, num *nums)//processing step 2
{//把数字,符号和class存入nums的结构体
	int i = 0;    //counter of input->formula
	int k = 0;  //counter of temp;
	int power = 0;
	char temp[5];
	int inBracket = False;
	num *p = nums;
	num *body;

	while (i <= input->length)
	{
		if ((input->formula[i]<'0' || input->formula[i]>'9')&&input->formula[i]!='.'&&input->formula[i]!='^')
		{//进入此处时数据已经收集完毕
			if (input->formula[i] == '(')
			{
				inBracket = True;
				++i;
				continue;
			}
			if (input->formula[i] == ')')
			{
				inBracket = False;
				++i;
				continue;
			}
			body = (num *)calloc(1, sizeof(num));

			body->data = atof(temp);    //得到数字
			setNULL(temp);              //归零temp
			k = 0;

			switch (input->formula[i])
			{
			case '+':body->dataClass = inBracket == False ? 1 : 3;  //计算当前运算符的等级
				++saved_class[body->dataClass - 1];                 //在等级数组里记录一次
				body->oper = input->formula[i];                     //得到运算符
				break;

			case '-':body->dataClass = inBracket == False ? 1 : 3;
				++saved_class[body->dataClass - 1];
				body->oper = input->formula[i];
				break;

			case 'x':
			case '*':body->dataClass = inBracket == False ? 2 : 4;
				++saved_class[body->dataClass - 1];
				body->oper = input->formula[i];
				break;

			case '/':body->dataClass = inBracket == False ? 2 : 4;
				++saved_class[body->dataClass - 1];
				body->oper = input->formula[i];
				break;

			default:break;
			}
			if (power != 0)
			{
				body->power = power;
				power = 0;
			}
			p->next = body;
			p = p->next;
		}
		else if (input->formula[i] == '^')
		{
			power = input->formula[++i] - 48;
		}
		else
		{
			temp[k++] = input->formula[i];
		}
		++i;
	}
	return 1;
}
double compute(double num1, double num2, char opt)
{//每次运算单独提取
	double result;
	switch (opt)
	{
	case '-':result = num1 - num2; break;
	case '+':result = num1 + num2; break;
	case 'x':
	case '*':result = num1 * num2; break;
	case '/':result = num1 / num2; break;
	}
	return result;
}
int processingData(num *nums)//processing step 3
{//nums作为头结点是没有数据的
	int s = 3;//saved_class
	int i = 0;
	num *p = nums;
	num *p_front;
	while (saved_class[s] == 0&&s>0)
		--s;
	while (p->next->next != NULL)//class oper next 都可以
	{
		if (p->next->dataClass != s + 1)
		{
			p = p->next;
			continue;
		}
		p_front = p;
		p = p->next;//p此时指向待计算的第一个struct aNUm
		if(p->power != 0)
		{
			p->data = pow(p->data, p->power);
			p->power = 0;
		}
		if (p->next->power != 0)
		{
			p->next->data = pow(p->next->data, p->next->power);
			p->next->power = 0;
		}
		p->next->data = compute(p->data, p->next->data, p->oper);

		p_front->next = p->next;
		free(p);
		--saved_class[s];
		while (saved_class[s] == 0&&s!=0)
			--s;
		p = nums;


	}
	if (nums->next->power != 0)//处理单个数字输入的情况,比如2^2
	{
		nums->next->data = pow(nums->next->data, nums->next->power);
	}


	printf("result=%lf\n", nums->next->data);
	return 1;
}
int main()
{
	int counter = 0;
	num *nums = NULL;
	string *input;
	input = (string *)calloc(1, sizeof(string));
	input->formula = (char *)calloc(INIT_STRING_SIZE, sizeof(string));


	puts("Input formula:");
	scanf("%s", input->formula);

	//得到运算符和运算符个数
	countOperators(input, counter);
	//根据运算符个数申请存储数字的空间
	nums = (num *)calloc(1, sizeof(num));
	//存储数字和运算符
	getData(input, nums);
	processingData(nums);

	free(input->formula);
	free(input);
	free(nums->next);
	free(nums);
	system("pause");//如果你是linux或者macos,可能需要去掉这句
	return 0;
}

测试数据不多,有错误欢迎指出^^

  • 18
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
以下是一个简单的命令行复杂计算器示例代码,实现了加减乘除、运算、括号和优先级等功能: ```c #include <stdio.h> #include <stdlib.h> #include <math.h> // 定义符号常量 #define ADD '+' #define SUB '-' #define MUL '*' #define DIV '/' #define POW '^' #define LEFT_BRACKET '(' #define RIGHT_BRACKET ')' // 定义运算符优先级 int get_priority(char op) { switch (op) { case LEFT_BRACKET: return 1; case ADD: case SUB: return 2; case MUL: case DIV: return 3; case POW: return 4; default: return 0; } } // 计算两个数的运算结果 double calculate(double num1, double num2, char op) { switch (op) { case ADD: return num1 + num2; case SUB: return num1 - num2; case MUL: return num1 * num2; case DIV: return num1 / num2; case POW: return pow(num1, num2); default: return 0; } } // 中缀表达式转后缀表达式 void infix_to_postfix(char *infix, char *postfix) { int i = 0, j = 0; char stack[100], ch; while ((ch = infix[i++]) != '\0') { if (ch >= '0' && ch <= '9') { // 数字直接输出 postfix[j++] = ch; } else if (ch == LEFT_BRACKET) { // 左括号入栈 stack[++stack[0]] = ch; } else if (ch == RIGHT_BRACKET) { // 右括号弹出栈内元素直到遇到左括号 while (stack[stack[0]] != LEFT_BRACKET) { postfix[j++] = stack[stack[0]--]; } stack[0]--; } else { // 运算符弹出并输出优先级大于等于当前运算符的栈内元素 while (stack[0] > 0 && get_priority(stack[stack[0]]) >= get_priority(ch)) { postfix[j++] = stack[stack[0]--]; } stack[++stack[0]] = ch; } } // 弹出栈内剩余元素 while (stack[0] > 0) { postfix[j++] = stack[stack[0]--]; } postfix[j] = '\0'; } // 计算后缀表达式的值 double evaluate_postfix(char *postfix) { int i = 0; char stack[100], ch; double num1, num2; while ((ch = postfix[i++]) != '\0') { if (ch >= '0' && ch <= '9') { // 数字入栈 stack[++stack[0]] = ch - '0'; } else { // 运算符弹出栈内两个元素进行运算 num2 = stack[stack[0]--]; num1 = stack[stack[0]--]; stack[++stack[0]] = calculate(num1, num2, ch); } } return stack[1]; } int main() { char infix[100], postfix[100]; printf("请输入中缀表达式:"); scanf("%s", infix); infix_to_postfix(infix, postfix); printf("后缀表达式为:%s\n", postfix); printf("计算结果为:%lf\n", evaluate_postfix(postfix)); return 0; } ``` 该计算器的实现基于经典的“中缀表达式转后缀表达式”算法和后缀表达式求值算法,具有一定的扩展性和灵活性,可以根据具体需求进行修改和扩展。同时,需要注意的是该计算器输入和输出均为字符串类型,需要进行适当的类型转换和错误处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值