C++寒假第三次作业
这个作业属于哪个课程 | 2020年面向对象程序设计 |
---|---|
这个作业要求在哪里 | 寒假第三次作业要求 |
这个作业的目标 | 优化编程题,使其输入的数字范围扩大,支持负数等,制作编译脚本和测试脚本 |
作业正文 | 见下文 |
其他参考文献 | Windows 批处理(bat)语法大全 GitHub使用指南 |
编程题
·优化架构,思考代码的拓展性,比如我需要增加其他功能,如选择,循环语句怎么办。
·思考:可以参考现有的编程语言,把这些语言的内容加入。如选择、循环语句、函数、或者扩大数字范围,支持负数等。
完成过程
回看分析第二次作业编程题的代码,仍存在不少问题:如主函数仍然过于繁杂,报错函数还不够完善,以及汉字和阿拉伯数字之间的转换(我打算尝试新的方法)、十以上数字的相加,引入乘除法和负数还未完成。
首先
我将第一行的输入写一个兼具赋值和判错功能的函数。
使用循环达到能使用户在输入错误后能够重新输入,在结尾调用change_1函数(该函数会在后面展开分析),进行变量赋值
void start(char temp[],char num[],int*p)
{
while(1){
scanf("%s",temp);
if(strcmp(temp,"等于")!=0){
scanf("%s",temp);
cout<<"请正确使用赋值关键字"<<endl;
}
else{
scanf("%s",num);
break;
}
}
(*p)=change_1(num);
}
其次
我进行了有关汉字数字转阿拉伯数字的函数优化
这是最开始的函数声明以及相关量的提前准备
int charge(int n[]);
void cut(char temp[],int first);
int change_1(char temp[]);
int len=strlen("一");
char model[11][4]={"零","一","二","三","四","五","六","七","八","九","十"};
char store[10];
我一共写了三个函数来完成这一转化,总结起来可以分为三部分:统领函数,切割函数,以及计算函数
思考过程
对于该部分的优化,我看了助教的直播,感觉受到了很大的启发,比如将负、零、一、二到十,十二个汉字用二维数组储存,在汉字数字转化为阿拉伯数字的过程中直接用循环来枚举寻找。在优化中,我将该部分的转化分为三部分来写,change_1函数作为主要框架,通过cut函数切割字符串,charge函数判断字符串类型并进行计算。并且这一次我成功把输入的数字扩大到了一百以内。我将输入的字符串通过循环分开,逐个分析。然后开一个a数组,在循环过程中对a数组赋值,循环结束后,对a[0],a[1],a[2]进行特判,便可以得知所输入的汉字字符串的类型(如单个汉字“一”“十”,两个汉字“十二”,“二十”,三个汉字“二十二”),接着再进行相应的组合运算。把“负”字也加入这个数组是为了方便引入负数,在正常的转化之前,先对第一个汉字是否为“负”进行特判,做好标记,在返回时乘上“-1”即可。如此,便可以将输入的数字范围扩大到大于负一百,小于一百。
统领函数
int change_1(char temp[])
{
int i,j,k=0,res,n[3];
mark=0;
for(i=0;i<3;i++) n[i]=0;
for(i=0;i<strlen(temp);i+=len){
cut(temp,i);
if(strcmp(store,"负")==0){
mark=1;
continue;
}
for(j=0;j<11;j++){
if(strcmp(model[j],store)==0){
n[k++]=j;
break;
}
}
}
res=charge(n);
if(mark==1) return res*(-1);
else return res;
}
切割函数
void cut(char temp[],int first)
{
int i,j=0;
for(i=first;i<len+first;i++){
store[j]=temp[i];
j++;
}
store[j]='\0';
}
计算函数
int charge(int n[])
{
int res;
if(n[1]==0) return n[0];
else if(n[0]==10){
res=10+n[1];
return res;
}
else if(n[1]==10){
res=10*n[0]+n[2];
return res;
}
}
再者
接着是对除第一行以外部分的优化。我写了一个错误判断并进行存储无用数据的函数。进行整行输入如“钱包 增加 十”时,若第一个关键字非已定义变量关键字(如“钱包”)或已定义操作关键字(如“看看”),则进入错误数据的后续处理(即用数组吸收掉剩下两组已经没用的字符串),并进行报错提示,返回相应值。若判断第一个字符串为正确输入,则返回特定值,代表对不同关键字(如“钱包”和“看看”)的反馈,以此进行选择要进入运算,还是准备输出。
这一部分的代码的简化较上次来看是很明显的,自定义函数的使用使主函数部分大大精简了。
代码如下:
主函数部分
while(1){
scanf("%s",s);
flag=pre(s,markname);//该函数可对输入的首个字符串进行判断,确定是运算操作(检测到已定义变量关键字),输出操作(检测到“看看”),还是其他不合理操作
if(flag==1){
index1=0;
order=0;
scanf("%s",operate);
scanf("%s",num);
operatejudge(operate,&index1,&order);
if(index1==1) calculate(&sum,order,num);
}
else if(flag==-1) break;
else continue;
}
自定义函数部分
判错函数
用了两个指针,一个用于后续判断是否应该进行预算(即有没有输入错误),一个用于记录可进行运算时是何种符号
void operatejudge(char operate[],int*p,int*o)
{
int i;
for(i=0;i<4;i++) if(!strcmp(operate,op[i])){
(*p)=1;
(*o)=i;
break;
}
if(i==4) cout<<"出现未定义运算关键字"<<endl;
}
进行加减乘除的运算
void calculate(int*p,int order,char num[])
{
switch(order){
case 0:(*p)+=change_1(num);break;
case 1:(*p)-=change_1(num);break;
case 2:(*p)*=change_1(num);break;
case 3:(*p)=(*p)/change_1(num);break;
}
}
还是先用一个数组来存“增加”“减少”“乘”“除以”的操作关键字,然后直接循环寻找即可。值得注意的是我把与运算有关的部分都写在calculate函数里头了,这样一来,主函数部分相比上次,算是精简了许多。
最后
阿拉伯数字转化为汉字数字的相关代码,可支持负数
主函数部分
进行正负判断
if(sum<=10){
if(flag==3) printf("负");
change_2(sum);
}
else link(sum,flag);
自定义了两个函数
void link(int sum,int flag)
{
if(flag==3) cout<<"负";
if((sum/10)>1) change_2(sum/10);
printf("十");
if((sum%10)!=0) change_2(sum%10);
}
void change_2(int sum)
{
switch(sum){
case 0:printf("零");break;
case 1:printf("一");break;
case 2:printf("二");break;
case 3:printf("三");break;
case 4:printf("四");break;
case 5:printf("五");break;
case 6:printf("六");break;
case 7:printf("七");break;
case 8:printf("八");break;
case 9:printf("九");break;
case 10:printf("十");break;
}
}
完整代码
如下
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<cmath>
using namespace std;
void start(char temp[],char num[],int*p);//
void errorstore(int n);//存无用数组和提示报错
void operatejudge(char operate[],int*p,int*o);//判断操作关键字是否合理
int pre(char temp[],char markname[]);//处理从第二行开始的首个字符串,进行正误判断并在必要时储存无用数组和提示报错
void calculate(int*p,int order,char num[]);//进行加减乘除运算
int charge(int n[]);//在汉字数字转阿拉伯数字时判断汉字字符串类型并整合转化为阿拉伯数字
void cut(char temp[],int first);//切割字符串,便于分析汉字字符串类型
int change_1(char temp[]);//汉字数字转阿拉伯数字主体框架
void change_2(int sum);// 将阿拉伯数字转为汉字数字
void link(int sum,int flag);
int len=strlen("一");//得到一个汉字字符长度
char model[11][4]={"零","一","二","三","四","五","六","七","八","九","十"};
char store[10];//用于截取字符串中的单个汉字
char index[10],op[4][5]={"增加","减少","乘","除以"};
int mark;//检测到"负"时做标记
int main()
{
int flag,index1,order,sum;
char s[10],markname[10],operate[10],num[10];
scanf("%s",s);
scanf("%s",markname);
start(s,num,&sum);
while(1){
scanf("%s",s);
flag=pre(s,markname);
if(flag==1){
index1=0;
order=0;
scanf("%s",operate);
scanf("%s",num);
operatejudge(operate,&index1,&order);
if(index1==1) calculate(&sum,order,num);
}
else if(flag==-1) break;
else continue;
}
if(sum<0) flag=3;
sum=fabs(sum);
if(sum<=10){
if(flag==3) printf("负");
change_2(sum);
}
else link(sum,flag);
return 0;
}
void start(char temp[],char num[],int*p)
{
while(1){
scanf("%s",temp);
if(strcmp(temp,"等于")!=0){
scanf("%s",temp);
cout<<"请正确使用赋值关键字"<<endl;
}
else{
scanf("%s",num);
break;
}
}
(*p)=change_1(num);
}
int pre(char temp[],char markname[])
{
int i;
char depot[10];
if(!strcmp(temp,markname)) return 1;
else if(!strcmp(temp,"看看")){
scanf("%s",index);
return -1;
}
else{
errorstore(1);
cout<<"出现未定义变量\n";
return 0;
}
}
void errorstore(int n)
{
int i;
char depot[10];
for(i=1;i<=2;i++) scanf("%s",depot);
}
void operatejudge(char operate[],int*p,int*o)
{
int i;
for(i=0;i<4;i++) if(!strcmp(operate,op[i])){
(*p)=1;
(*o)=i;
break;
}
if(i==4) cout<<"出现未定义运算关键字"<<endl;
}
void calculate(int*p,int order,char num[])
{
switch(order){
case 0:(*p)+=change_1(num);break;
case 1:(*p)-=change_1(num);break;
case 2:(*p)*=change_1(num);break;
case 3:(*p)=(*p)/change_1(num);break;
}
}
int change_1(char temp[])
{
int i,j,k=0,res,n[3];
mark=0;
for(i=0;i<3;i++) n[i]=0;
for(i=0;i<strlen(temp);i+=len){
cut(temp,i);
if(strcmp(store,"负")==0){
mark=1;
continue;
}
for(j=0;j<11;j++){
if(strcmp(model[j],store)==0){
n[k++]=j;
break;
}
}
}
res=charge(n);
if(mark==1) return res*(-1);
else return res;
}
void cut(char temp[],int first)
{
int i,j=0;
for(i=first;i<len+first;i++){
store[j]=temp[i];
j++;
}
store[j]='\0';
}
int charge(int n[])
{
int res;
if(n[1]==0) return n[0];
else if(n[0]==10){
res=10+n[1];
return res;
}
else if(n[1]==10){
res=10*n[0]+n[2];
return res;
}
}
void link(int sum,int flag)
{
if(flag==3) cout<<"负";
if((sum/10)>1) change_2(sum/10);
printf("十");
if((sum%10)!=0) change_2(sum%10);
}
void change_2(int sum)
{
switch(sum){
case 0:printf("零");break;
case 1:printf("一");break;
case 2:printf("二");break;
case 3:printf("三");break;
case 4:printf("四");break;
case 5:printf("五");break;
case 6:printf("六");break;
case 7:printf("七");break;
case 8:printf("八");break;
case 9:printf("九");break;
case 10:printf("十");break;
}
}
制作脚本
编译脚本
测试脚本
测试代码如下
#include<stdio.h>
#include<string.h>
#include<math.h>
int charge(int n[]);
void cut(char temp[],int first);
int change_1(char temp[]);
int len=strlen("一");
char model[11][4]={"零","一","二","三","四","五","六","七","八","九","十"};
char store[10];
char mark;
char test[15][10]={"零","三","十","十一","二十","二十二","负二十二","负一","负十","负十九","负二十","负三十三","负九十九","九十九","负三十"};
int answer[15]={0,3,10,11,20,22,-22,-1,-10,-19,-20,-33,-99,90,-29};
int main()
{
int i;
for(i=0;i<15;i++){
printf("输入 %s 输出 %d ",test[i],answer[i]);
if(change_1(test[i])==answer[i]) printf("pass\n");
else printf("error\n");
}
return 0;
}
int change_1(char temp[])
{
int i,j,k=0,res,n[3];
mark=0;
for(i=0;i<3;i++) n[i]=0;
for(i=0;i<strlen(temp);i+=len){
cut(temp,i);
if(strcmp(store,"负")==0){
mark=1;
continue;
}
for(j=0;j<11;j++){
if(strcmp(model[j],store)==0){
n[k++]=j;
break;
}
}
}
res=charge(n);
if(mark==1) return res*(-1);
else return res;
}
void cut(char temp[],int first)
{
int i,j=0;
for(i=first;i<len+first;i++){
store[j]=temp[i];
j++;
}
store[j]='\0';
}
int charge(int n[])
{
int res;
if(n[1]==0) return n[0];
else if(n[0]==10){
res=10+n[1];
return res;
}
else if(n[1]==10){
res=10*n[0]+n[2];
return res;
}
}