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;
}

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

评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值