四则运算(c语言实现)

合伙人:魏甫——3118004973  ,温钦益——3118004975

 https://github.com/iamdate/work/tree/master 

一.项目及其要求

  1.题目:实现一个自动生成小学四则运算题目的命令行程序(也可以用图像界面,具有相似功能)。

  2说明:

    自然数:0, 1, 2, …。

    •   真分数:1/2, 1/3, 2/3, 1/4, 1’1/2, …。
    •   运算符:+, −, ×, ÷。
    •   括号:(, )。
    •   等号:=。
    •   分隔符:空格(用于四则运算符和等号前后)。
    •   算术表达式:

      e = n | e1 + e2 | e1 − e2 | e1 × e2 | e1 ÷ e2 | (e),

      其中e, e1和e2为表达式,n为自然数或真分数。

    •   四则运算题目:e = ,其中e为算术表达式。

  3需求:

  1.   使用 -n 参数控制生成题目的个数,例如Myapp.exe -n 10将生成10个题目。
  1.   使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如

Myapp.exe -r 10

将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。

  1. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1− e2的子表达式,那么e1≥ e2。
  2. 生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数。
  3. 每道题目中出现的运算符个数不超过3个。
  4. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。

生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:

  1. 四则运算题目1
  2. 四则运算题目2

……

其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。

  1. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:
  1. 答案1
  2. 答案2

特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。

  1. 程序应能支持一万道题目的生成。
  2. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:

Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt

统计结果输出到文件Grade.txt,格式如下:

Correct: 5 (1, 3, 5, 7, 9)

Wrong: 5 (2, 4, 6, 8, 10)

其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。

二、所遇困难及解决办法

  1.如何实现随机运算符和数字?

   解:1.1:每道题目中出现的运算符个数不超过3个相当于e=a*b/c+d,其中未知数有4个,运算符最大值为三个。问:如何产出最多含4个数字的题目

     1.2:经百度得可使用random()函数随机生成数字及运算符,后使用switch语句判断生成题目类型。待续~

   2.如何进行计算?

  解:2.1:题目中所有参数为随机,只有生成后的题目为已知。问:如何读取已知的题目,并进行计算测试?

    2.2:第一次测试:采用数组储存题目,利用switch语句判断运算符。结果:失败,运算符多,计算式复杂,数组可能太少。

    2.3:第二次测试:经询问,采用链表方式,编写逆波兰式将中缀表达式转为后缀表达式进行计算。结果:成功,一般情况下中缀表达式计算比较复杂,但将其转为后缀表达式简洁很多,创建两个栈,一个存放操作数,一个存放运算符,计算时将其拿出。

  3.如何将程序写进文件

  解:3.1:由于之前用java写个人项目的缘故,得知了io数据流,但c和java用法不一,故前去学习。后用fprintf()将生成表达式一并写入文件,再将答案数组也写入文件1。

三、关键代码

  1.中缀转后缀并计算

void qiuzhi(char *bds)//中转后并求值
{  FILE *fp;
int i = 0;
stack *ysf = (stack*)malloc(sizeof(stack));//为表达式开辟一个stack
ysf->size = 0;
float num[50];//用于求值的数组
int numpos = 0;//用于求值的数组位置,因使用较少为提高效率选择数组
printf("后缀表达式为:");//附加
while (bds[i] != '=')
{
if (bds[i] == '\0')
{
printf("表达式应该有=");
return;
}
if (bds[i] <= '9'&&bds[i] >= '0')//转化数字
{
num[++numpos] = 0;
while (bds[i] <= '9'&&bds[i] >= '0')
{
num[numpos] *= 10;
num[numpos] += (bds[i] - '0');
++i;
}
if (bds[i] == '.')
{
double f_car = 0.1;//定义基数
++i;
while (bds[i] <= '9'&&bds[i] >= '0')
{
num[numpos] += ((bds[i] - '0')*f_car);
f_car *= 0.1;
++i;
}
}//计算小数点
}
else
{
if (empty(ysf))
push(ysf, bds[i]);
else
{
if (bds[i] == '(')
push(ysf, bds[i]);
else if (bds[i] == ')')
{
while (top(ysf) != '(')
{
reckon(&num[numpos - 1], num[numpos], top(ysf));
printf("%c", pop(ysf));
--numpos;
}
pop(ysf);//弹出右括号
}
else
{
while (compare(bds[i])<=compare(top(ysf)))
{
reckon(&num[numpos - 1], num[numpos], top(ysf));
printf("%c", pop(ysf));
--numpos;
}
push(ysf, bds[i]);
}
}
++i;
}
}
while (!empty(ysf))
{
reckon(&num[numpos - 1], num[numpos], top(ysf));
printf("%c", pop(ysf));
--numpos;
}

    fopen("/练习程序/answer.txt","w+");
      printf("\n运算结果为:%.2f\n", num[1]);
        fprintf(fp,"%.2f\n",num[1]);

}

void reckon(float *a, float b, char c)//用于将两数字合并,前数传地址
{ //表达式运算定义
int t;
if (c == '-')
{ if(*a<b)//非负
{ t=*a;*a=b;b=t;}
(*a)-=b;
}
else if (c == '+')
{
(*a) += b;
}
else if (c == '*')
{
(*a) *= b;
}
else
if(b!=0)
(*a) /= b; }

 2.分数运算

void qiuzhi1(int a,int b,int c,int d,char s)
{  int x,y,t,m;
float p,q;//中间数
int re1,re2,u;//分子分母 x=getGcd(a,b);//对a,b约分
a/=x;
b/=x;
y=getGcd(c,d);//对c,d约分
c/=y;
d/=y;
FILE *fp=fopen("/练习程序/subject.txt","w+");//读写文件位置 switch(s)//选取运算符
{
case '+':
re1=a*d+c*b;
re2=b*d;
t=getGcd(re1,re2);
re1/=t;
re2/=t;
printf("%d/%d + %d/%d=%d/%d\n",a,b,c,d,re1,re2);
fprintf(fp, "%d/%d + %d/%d=%d/%d\n",a,b,c,d,re1,re2);
break;
case '-':
p=a/b;
q=c/d;
if(p<q)//判断结果不为负
{
u=a;
a=c;
c=u;
u=b;
b=d;
d=u;
}
re1=a*d-c*b;//结果分子的运算
re2=b*d;
t=getGcd(re1,re2);//约分
re1/=t;
re2/=t;
printf("%d/%d - %d/%d=%d/%d\n",a,b,c,d,re1,re2);
fprintf(fp, "%d/%d - %d/%d=%d/%d\n",a,b,c,d,re1,re2); break;
case '*':
re1=a*c;
re2=b*d;
t=getGcd(re1,re2);
re1/=t;
re2/=t;
if(a==0||c==0)//有分数为0时
{
printf("%d/%d * %d/%d=0",a,b,c,d);
fprintf(fp, "%d/%d * %d/%d=0",a,b,c,d);
}
else
printf("%d/%d * %d/%d=%d/%d\n",a,b,c,d,re1,re2);
fprintf(fp, "%d/%d * %d/%d=%d/%d\n",a,b,c,d,re1,re2); break;
case '/': re1=a*d;
re2=b*c;
t=getGcd(re1,re2);
re1/=t;
re2/=t;
if(a==0)
{printf("%d/%d / %d/%d=0",a,b,c,d);//结果为0
fprintf(fp, "%d/%d / %d/%d=0",a,b,c,d);
}
else{
printf("%d/%d / %d/%d=%d/%d\n",a,b,c,d,re1,re2);
fprintf(fp, "%d/%d / %d/%d=%d/%d\n",a,b,c,d,re1,re2);
} } }

  3.读取题目信息

void creat1(int num,int r)
{
char a[]={'+','-','*','/'};
int X,c,t;
int i,j,b,count;
int x,y,x1,y1,z,e;
int n=sizeof(a);
srand(time(NULL)); FILE *fp = NULL;//打开文件
fp = fopen("/练习程序/test.txt", "w+"); for(j=0;j<num;j++)
{ x=rand()%r;
y=rand()%r;
x1=rand()%r;
y1=rand()%r;
z=rand()%r;
X=rand()%4;
i=rand()%n;
b=rand()%n;
c=rand()%n;
x!=y;
switch(X)//控制符号数
{ case 0:
printf("第%d题:%d%c%d= \n",j+1,x,a[i],y);
fprintf(fp, "%d%c%d= \n",x,a[i],y); break;
case 1:
printf("第%d题:%d%c%d%c%d= \n",j+1,x,a[i],y,a[b],z);
fprintf(fp, "%d%c%d%c%d= \n",x,a[i],y,a[b],z);
break;
case 2:
fprintf(fp, "%d%c%d%c%d%c%d= \n",x,a[i],y,a[b],x1,a[c],z);
printf("第%d题:%d%c%d%c%d%c%d= \n",j+1,x,a[i],y,a[b],x1,a[c],z);
break; } }
fclose(fp); }
void save()
{ stack *p;
char bds[50];
FILE *fx;//读取文件
int line,i;
if((fx = fopen("/练习程序/test.txt","r")) == NULL)
{
printf("error\n");
exit (1) ;
}
char buf[1024];
for (i = 0; i < 1024; i++)
{ while(fgets(bds,50,fx) != NULL)//输出文件
{ line = strlen(bds);
bds[line-1] = '\0'; /*去掉换行符*/
printf("%s \n",bds);
qiuzhi(bds); }
fclose (fx);
}
}

  4.主函数

int main()

{
int num1,num2,m,n,r,type;
printf("请选择输出类型:1or2");
scanf("%d\n",&type);
if(type==1)
{ printf("请输入生成题目数量: ");
scanf("%d \n",&num1);
printf("请输入分子分母取值范围: ");
scanf("%d %d",&m,&n);
creat2(num,m,n);
}
else if(type==2)
{ printf("请输入生成题目数量: ");
scanf("%d \n",&num2);
printf("请输入取值范围: ");
scanf("%d %d",&r);
creat1(num,r);
save();//输出答案
}
return 0;
}

 四、测试

    1.分数计算

    

    2.文件生成

   

   

五、psp表格

    

 六、总结

  魏甫:这次的项目不能说是很完美的运行,由于基础较差,在经过很多天的学习,实验下,我们仅仅只是完成了个大概,我在我们队伍里是负责测试,审核代码。为了让代码更加美观好看,我将代码整体结构改正了一下,导致我们总体的程序出现了bug,例如整数有时会运行不出,但调试却没有问题。这是我的责任,同时对我来说这个项目并没有结束,之后我会仔细检查debug,让它更完美些。最后一次总结会议上我们在总结自己收获的同时,也互相反思自己在项目上出现了什么问题,有什么不足之处。我们的问题主要有:沟通不到位,由于第一次进行结对项目,难免会有些个人思想,在反思过程中,明显发现,函数中参数设置和定义有很大区别,这让我们不得不去仔细对照查看代码含义。也告诉我在下次结对时,一定一定要在一开始就定好函数和参数的各类功能和类型,提高效率,节省时间。这次的结对对我们来说是一个很好的经历,弥足珍贵。

  温钦益:这次的结对项目,一开始看到题目感觉并不是很难,等到和同伴开始对题目的各个要求完成代码时,才感受到了题目中复杂的地方。我们首先先确定了使用的语言,由于没有对其他语言的学习,故选择了C语言。在完成要求的过程中,我们首先开了个会,先各自完成自己认为能完成的部分。然后把对方的代码发出来一起审核,进行测试。在判断运算符优先级时,意识到要运用数据结构的内容时,又抽出了时间去复习。除此,我们是第一次做结对项目,,在讨论和交流时出现来了偏差。原因是函数定义及参数设置不一,想法未沟通好。在其他的一些功能要求上,由于我们的能力有限,只能完成一部分内容。另外,在交流代码的过程中,学习到了代码的规范的重要性,写的时候要想到如何写才能让对方也能理解你的意思。最后,此次结对项目让我们有了交流的对象,不再是自己一个人的苦思冥想,我们能分享自己遇到的困难,分享自己的经验,让我收获到了许多。

四则运算(C语言实现)的更多相关文章

  1. 四则运算C语言程序

    #include<stdio.h> #include<Windows.h> #include<time.h> void main() { int a, b, c, ...

  2. 随机四则运算 C语言

    设计思想:出三十道一百以内数的随机四则运算题目,先随机两个一百以内的数字,再通过随机数确定四则运算算符,最后通过for循环输出三十道 源代码程序: #include <stdlib.h># ...

  3. 四则运算Java语言实验设计过程1

    题目要求: 像二柱子那样,花二十分钟写一个能自动生成三十道小学四则运算题目的 “软件”.要求:除了整数以外,还要支持真分数的四则运算(需要验证结果的正确性).题目避免重复.可定制出题的数量. 设计思路 ...

  4. 四则运算 C 语言

    #include<stdio.h>void main(){ char c; float x,y; int result; scanf("%c %f %f",&c ...

  5. 简单的C语言小学四则运算设计

    题目:设计一个简单的四则运算编辑器 思路:我使用的是C语言编程,看到题目首先要随机出3个随机数,其中两个为100以内的随机数(a,b),一个为0~3的随机数(k). k值的变化使得+ - * /的变化 ...

  6. 深入浅出数据结构C语言版(8)——后缀表达式、栈与四则运算计算器

    在深入浅出数据结构(7)的末尾,我们提到了栈可以用于实现计算器,并且我们给出了存储表达式的数据结构(结构体及该结构体组成的数组),如下: //SIZE用于多个场合,如栈的大小.表达式数组的大小 #de ...

  7. 数据结构课程设计四则运算表达式求值(C语言版)

    本系统为四则运算表达式求值系统,用于带小括号的一定范围内正负数的四则运算标准(中缀)表达式的求值.注意事项:    1.请保证输入的四则表达式的合法性.输入的中缀表达式中只能含有英文符号"+ ...

  8. java语言编写矩阵的四则运算

    题目要求如下: 设计程序实现矩阵的四则运算 设计要求: (1) 实现矩阵的四则运算. (2) 考虑实现带变元的矩阵计算. (3)考虑实现矩阵的特征值和特征向量的计算. 我使用java语言写的 目录结构 ...

  9. 【软件工程Ⅱ】作业四 |个人项目-小学四则运算 “软件”之初版(C语言)

    本次作业的要求来自于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/2186 本次作业代码的github地址:https://gith ...

  10. 第二次作业利用java语言编写计算器进行四则运算

    随着第一次作业的完成,助教 牛老师又布置了第二次作业:用java语言编写一个程序然后进行四则运算用户用键盘输入一个字符来结束程序显示统计结果.一开始看到这个题目我也着实吓了一跳 因为不知道如何下手而且 ...

随机推荐

  1. 性能分析(1)- Java 进程导致 CPU 使用率升高,问题怎么定位?

    性能分析小案例系列,可以通过下面链接查看哦 ps:这些分析小案例不能保证百分比正确,是博主学习过程中的总结,仅做参考 前提 本机有一个很占用 CPU 的项目,放在了 Tomcat 下启动着 如何定位 ...

  2. WSGI应用程序示例

    import time # WSGI允许开发者自由搭配web框架和web服务器 def app(environ,start_response): status = '200 OK' response_ ...

  3. IDEA、maven创建webapp项目

      maven官方入门指南:http://maven.apache.org/guides/getting-started/index.html 推荐跟着官方文档学习噢~   IDEA.maven创建w ...

  4. MySQL(版本8.0.19)服务的启动/停止、登录/登出、修改密码

      [先说明一点 ,windows系统下,英文字母不分大小写.] MySQL 服务的 启动 / 停止 方式一: (我的系统是windows10) 找到 此电脑 图标 右键点击,选择"管理&q ...

  5. 卷积神经网络 part1

    [任务一]视频学习心得及问题总结 根据下面三个视频的学习内容,写一个总结,最后列出没有学明白的问题. [任务二]代码练习 在谷歌 Colab 上完成代码练习,关键步骤截图,并附一些自己的想法和解读. ...

  6. 数据库允许空值(null),往往是悲剧的开始

    原文: 58沈剑   架构师之路   https://mp.weixin.qq.com/s/XRSPITgWWK-2Ee-cSIqw1w 数据库字段允许空值,会遇到一些问题,此处包含的一些知识点,和大 ...

  7. 8月份Python招聘情况怎么样?Python爬取招聘数据,并进行分析

    前言 拉勾招聘是专业的互联网求职招聘平台.致力于提供真实可靠的互联网招聘求职找工作信息.今天我们一起使用 python 采集拉钩的 python 招聘信息,分析一下找到高薪工作需要掌握哪些技术 开发环 ...

  8. 迭代列表不要For循环,这是Python列表推导式最基本的概念

    如果你还在使用 For 循环迭代列表,那么你需要了解了解列表推导式,看看它的基本概念都是什么. 列表解析式(List comprehension)或者称为列表推导式,是 Python 中非常强大和优雅 ...

  9. 标星7000+,这个 Python 艺术二维码生成器厉害了!

    微信二维码,相信大家也并不陌生,为了生成美观的二维码,许多用户都会利用一些二维码生成工具. 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手 ...

  10. 什么才是定制化IDE的核心价值?

    写在前面 自 2018 年初,就与 VSCode 结下了不解之缘,从一份选型报告开始,一蹉跎就是 2 年多 期间反复思索着一个挥之不去的问题:定制化 IDE 产品的核心价值是什么? 事实上,答案并不唯 ...