四则运算(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. 关于RecyclerView(二)设置EmptyView

    首先重写一个RecyclerView类 package com.onepilltest.others; import android.content.Context; import android.s ...

  2. std:ios:sync_with_stdio (false)以及局限性

    如何在输入输出上提高一下效率emmmm #include<iostream> #include<stdio.h> #include<stdlib.h> #inclu ...

  3. SpringBoot环境下使用测试类注入Mapper接口报错解决

    当我们在进行开发中难免会要用到测试类,而且测试类要注入Mapper接口,如果测试运行的时候包空指针异常,看看测试类上面的注解是否用对! 正常测试我们需要用到的注解有这些: @SpringBootTes ...

  4. gerrit安装指南

    Gerrit的基本介绍 Gerrit 是一个Git服务器,它基于 git 版本控制系统,使用网页界面来进行审阅工作.Gerrit 旨在提供一个轻量级框架,用于在代码入库之前对每个提交进行审阅,更改将上 ...

  5. JavaScript Set对象

    JavaScript Set对象 Set 用于存储任何类型的唯一值,无论是基本类型还是引用类型. 只有值没有键 严格类型检测存储,字符串数字不等同于数值型数字 存储的值具有唯一性 遍历顺序是添加的顺序 ...

  6. PHP filetype() 函数

    定义和用法 filetype() 函数返回指定文件或目录的类型. 如果成功,该函数返回 7 种可能的值之一.如果失败,则返回 FALSE. 可能的返回值: fifo char dir block li ...

  7. php getimagesize 函数 - 获取图像信息

    getimagesize() 函数用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息. 语法格式:高佣联盟 www.cgewang.co ...

  8. PHP sin() 函数

    实例 返回不同数的正弦: <?php高佣联盟 www.cgewang.comecho(sin(3) . "<br>");echo(sin(-3) . " ...

  9. 代码扫描Sonar使用教程

    Sonar是一个用于代码质量管理的开源平台,用于管理源代码的质量,可以从多个维度检测代码质量: 可靠性 安全性 可维护性 覆盖率 重复率 通过插件形式,可以支持包括Java,C#,C/C++,PL/S ...

  10. K近邻算法(一)

    K 近邻算法思想: 寻找该点周围最近的K个点.根据这K 个点的类别来判断该点的类别: 核心: 数据归一化.(在必要的时候必须进行数据归一化处理,防止某一特征在计算数据时占比较重) 计算欧拉距离 . 使 ...