面向对象程序设计寒假作业2编程题

这个作业属于哪个课程 2020年面向对象程序设计 (福州大学 - 数学与计算机科学学院)
这个作业要求在哪里 面向对象程序设计寒假作业2
这个作业的目标 1.继续完成编程题。
2.新建一个github仓库,并把作业推送到该仓库。
3.发布博客。
作业正文 面向对象程序设计寒假作业2实践题
面向对象程序设计寒假作业2编程题
Mac下Shell脚本使用学习笔记(一)
Mac下Shell脚本使用学习笔记(二)
其他参考文献 Macbook中使用Vim和GCC编译C程序
c语言中所有文件操作函数详解
C语言命令行参数详解
freopen()函数的使用

编程题

1.题目要求:

(1)继续完成作业一的编程题。
(2)优化架构,一般要求每个函数长度不超过15行。
(3)优化规范,尤其是命名规范。
(4)制作一个编译脚本,运行该脚本可以编译你的代码,可选的脚本语言,python(2.7),windows批处理,powershell,shell。
(5)进行单元测试,即测试每一个函数,并制作一个测试脚本,运行该脚本可以进行测试,并显示测试结果。
(6)添加以下功能:通过命令行读取一个文件,然后运行这个文件。如我的程序叫lang,lang 1.txt代表我要运行1.txt这个文本中的代码

2.分解需求:

(1)对代码进行进一步优化:

①首先,我注意到在上次编程题的代码中,在一下这两个函数中,其功能存在重复赘余:

int beginning(int wallet,char d[]){
    if(strcmp(d,"零")==0) return 0;
    else if(strcmp(d,"一")==0) return 1;
    else if(strcmp(d,"二")==0) return 2;
    else if(strcmp(d,"三")==0) return 3;
    else if(strcmp(d,"四")==0) return 4;
    else if(strcmp(d,"五")==0) return 5;
    else if(strcmp(d,"六")==0) return 6;
    else if(strcmp(d,"七")==0) return 7;
    else if(strcmp(d,"八")==0) return 8;
    else if(strcmp(d,"九")==0) return 9;
    else if(strcmp(d,"十")==0) return 10;
    else return -1;
}
int calculate(int wallet,char d[]){
      if(strcmp(d,"零")==0) return 0;
      else if(strcmp(d,"一")==0) return 1;
      else if(strcmp(d,"二")==0) return 2;
      else if(strcmp(d,"三")==0) return 3;
      else if(strcmp(d,"四")==0) return 4;
      else if(strcmp(d,"五")==0) return 5;
      else if(strcmp(d,"六")==0) return 6;
      else if(strcmp(d,"七")==0) return 7;
      else if(strcmp(d,"八")==0) return 8;
      else if(strcmp(d,"九")==0) return 9;
      else if(strcmp(d,"十")==0) return 10;
      else return -1;
}

作业一中之所以,将其分为两个函数是因为,第一个beginning函数其作用在于为变量“钱包”作初始化的作用,而第二个 calculate函数,是执行钱包总额增减的功能。但是,这两个函数在本质上起的是相同的作用,初始化函数也可以等同于对钱包的总额进行增减,故此我将这两个函数进行合并,并更名为change,其作用为对钱包总额的变化,代码如下:

int change(int wallet,char d[]){
      if(strcmp(d,"零")==0) return 0;
      else if(strcmp(d,"一")==0) return 1;
      else if(strcmp(d,"二")==0) return 2;
      else if(strcmp(d,"三")==0) return 3;
      else if(strcmp(d,"四")==0) return 4;
      else if(strcmp(d,"五")==0) return 5;
      else if(strcmp(d,"六")==0) return 6;
      else if(strcmp(d,"七")==0) return 7;
      else if(strcmp(d,"八")==0) return 8;
      else if(strcmp(d,"九")==0) return 9;
      else if(strcmp(d,"十")==0) return 10;
      else return -1;
}

当然,相应的在主函数中,调用函数部分也会有相应的变化(代码见后)。
②然后,我在想,对于输出钱包总额时,我原先采用了三分支判断结构,是否可以进行修改使代码更简洁呢?
原如下代码:

void num(int i){
    if(i==0) printf("零");
    else if(i==1) printf("一");
    else if(i==2) printf("二");
    else if(i==3) printf("三");
    else if(i==4) printf("四");
    else if(i==5) printf("五");
    else if(i==6) printf("六");
    else if(i==7) printf("七");
    else if(i==8) printf("八");
    else if(i==9) printf("九");
    else if(i==10) printf("十");
}
void sum(int wallet){
    int a,b;
    if(wallet<=10){num(wallet);}
    else if(wallet<20){
        a=wallet%10;
        printf("十");
        num(a);
    }
    else{
        a=wallet/10;
        b=wallet%10;
        num(a);
        printf("十");
       if(b!=0) num(b);
    }
}

然后我尝试把后两个分支合并,代码如下:

void num(int i){
    if(i==0) printf("零");
    else if(i==1) printf("一");
    else if(i==2) printf("二");
    else if(i==3) printf("三");
    else if(i==4) printf("四");
    else if(i==5) printf("五");
    else if(i==6) printf("六");
    else if(i==7) printf("七");
    else if(i==8) printf("八");
    else if(i==9) printf("九");
    else if(i==10) printf("十");
}
void sum(int wallet){
    int a,b;
    if(wallet<=10){num(wallet);}
    else{
        a=wallet/10;
        b=wallet%10;
        if(a!=0)num(a);//注意修改前的这一步
        printf("十");
       if(b!=0) num(b);
    }
}

我按照我修改后的代码尝试了三种情况,如下:



前两种按照中文习惯是不存在任何问题的,但是第三种出现六问题,因为按照中文习惯,当钱包总额为17时,应该输出十七,而不是一十七。注意到,我在上一段代码作出的标记:

if(a!=0)num(a);

所以我改变了,这个判断语句a的条件,目的是为了当a=1时,其没有输出,故代码为:

void num(int i){
    if(i==0) printf("零");
    else if(i==1) printf("一");
    else if(i==2) printf("二");
    else if(i==3) printf("三");
    else if(i==4) printf("四");
    else if(i==5) printf("五");
    else if(i==6) printf("六");
    else if(i==7) printf("七");
    else if(i==8) printf("八");
    else if(i==9) printf("九");
    else if(i==10) printf("十");
}
void sum(int wallet){
    int a,b;
    if(wallet<=10){num(wallet);}
    else{
        a=wallet/10;
        b=wallet%10;
        if(a!=1)num(a);//注意修改后的这一步
        printf("十");
       if(b!=0) num(b);
    }
}

验证结果(如下),发现答案正确:

③然后,我开始解决主函数的一些判断问题:
原代码如下:

int main() {
    char a[100],b[100],c[100],d[100];
    int wallet=0,i,flag=0;
    scanf("%s %s %s %s",a,b,c,d);
    if(strcmp(a,"整数")!=0||strcmp(c,"等于")!=0) flag=1;
    for(i=1;flag==0;i++){
        if(i==1) wallet=change(wallet,d);
        else {
            scanf("%s",a);
            if(strcmp(a,b)!=0&&strcmp(a,"看看")!=0) break;
            scanf("%s",c);
            if(strcmp(a,"看看")==0){
                sum(wallet);
                break;}
            scanf("%s",d);
         if(strcmp(c,"增加")==0) wallet+=change(wallet,d);
         if(strcmp(c,"减少")==0) wallet-=change(wallet,d);
        }
    }
   return 0;
}

当初,由于时间关系,我忽略了一个问题就是,如果我在第一次输入变量名为钱包后,在进行钱包总额的增减时,如果我输入的是其他变量名,那其总额仍会进行变化吗,于是我进行了测试:发现程序会结束,原来之前已经考虑过了这种情况,好吧,有点白费功夫了
④最后,优化规范,我对一些不规范对命名的调整,总代码如下:

#include <stdio.h>
#include <string.h>
int change(int wallet,char d[]){
      if(strcmp(d,"零")==0) return 0;
      else if(strcmp(d,"一")==0) return 1;
      else if(strcmp(d,"二")==0) return 2;
      else if(strcmp(d,"三")==0) return 3;
      else if(strcmp(d,"四")==0) return 4;
      else if(strcmp(d,"五")==0) return 5;
      else if(strcmp(d,"六")==0) return 6;
      else if(strcmp(d,"七")==0) return 7;
      else if(strcmp(d,"八")==0) return 8;
      else if(strcmp(d,"九")==0) return 9;
      else if(strcmp(d,"十")==0) return 10;
      else return -1;
}
void num(int i){
    if(i==0) printf("零");
    else if(i==1) printf("一");
    else if(i==2) printf("二");
    else if(i==3) printf("三");
    else if(i==4) printf("四");
    else if(i==5) printf("五");
    else if(i==6) printf("六");
    else if(i==7) printf("七");
    else if(i==8) printf("八");
    else if(i==9) printf("九");
    else if(i==10) printf("十");
}
void printf_sum(int wallet){
    int a,b;
    if(wallet<=10) num(wallet);
    else{
        a=wallet/10;
        b=wallet%10;
        if(a!=1) num(a);
        printf("十");
        if(b!=0) num(b);
    }
}
int main() {
    char a[100],b[100],c[100],d[100];
    int wallet=0,i,flag=0;
    scanf("%s %s %s %s",a,b,c,d);
    if(strcmp(a,"整数")!=0||strcmp(c,"等于")!=0) flag=1;
    for(i=1;flag==0;i++){
        if(i==1) wallet=change(wallet,d);
        else {
            scanf("%s",a);
            if(strcmp(a,b)!=0&&strcmp(a,"看看")!=0) break;
            scanf("%s",c);
            if(strcmp(a,"看看")==0){
                printf_sum(wallet);//这里重新命名函数,使代码更加易读
                break;}
            scanf("%s",d);
         if(strcmp(c,"增加")==0) wallet+=change(wallet,d);
         if(strcmp(c,"减少")==0) wallet-=change(wallet,d);
        }
    }
   return 0;
}

待解诀问题:仍然只能进行零至十的赋值,将在下一阶段进行思考和改进。
由于个人的力量是有限的,所以希望大家,可以对我的代码提出进一步对改进建议,或者你的看法。

(2)制作一个编译脚本,运行该脚本编译代码(学习笔记已在链接标出):

shell代码如下:

#!/bin/bash

 echo -n "请输入需要编译的文件名:"
read compile_file
 gcc $compile_file -o test1.out
 ./test1.out

结果如下:

之后,为了使一运行脚本便可编译代码,作出了修改,代码如下:

#!/bin/bash

 gcc main.c -o test1.out
 ./test1.out

结果如下:

然后,我又参考了沈欢同学的作业,进行进一步完善了脚本,增加了一个判断,用于辨别是否成功编译。代码如下:

#!/bin/bash

 gcc main.c -o test1.out
 if [ $? == 0 ]  # $?显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
 then
     echo "编译成功"
     ./test1.out
     if [ $? == 0 ]
     then
         echo "运行结束"
     else
         echo "运行失败"
     fi
 else
     echo "编译失败"
 fi

结果如下:

需要注意的是,当我们在使用脚本编译代码的时候,需要将代码文件与脚本放在一个文件夹中,否则会出现以下情况:

(3)进行单元测试,并制作一个测试脚本,运行并显示结果:

这个地方,理解了半天,后面参考了提交的同学的博客和询问了同学,我才明白什么意思(非常感谢)
注意到我的代码中总共有三个函数,而后面两个num函数与printf_sum函数皆为输出函数,负责直接输出结果,因此这两个函数的测试我们可以在结果中看到,因此这里只需测试chang函数:

//main.h
#include <stdio.h>
#include <string.h>
int change(char d[]){
      if(strcmp(d,"零")==0) return 0;
      else if(strcmp(d,"一")==0) return 1;
      else if(strcmp(d,"二")==0) return 2;
      else if(strcmp(d,"三")==0) return 3;
      else if(strcmp(d,"四")==0) return 4;
      else if(strcmp(d,"五")==0) return 5;
      else if(strcmp(d,"六")==0) return 6;
      else if(strcmp(d,"七")==0) return 7;
      else if(strcmp(d,"八")==0) return 8;
      else if(strcmp(d,"九")==0) return 9;
      else if(strcmp(d,"十")==0) return 10;
      else return -1;
}

测试部分代码:

#include "main.h"
void judge_change(int number_actual,int number_example){
    if(number_actual==number_example) printf("Pass\n");
    else printf("Fail\n");
}
void test_change(){
     printf("test_change begins\n");
    judge_change(change("零"),0);
    judge_change(change("一"),1);
    judge_change(change("二"),2);
    judge_change(change("三"),3);
    judge_change(change("四"),4);
    judge_change(change("五"),5);
    judge_change(change("六"),6);
    judge_change(change("七"),7);
    judge_change(change("八"),8);
    judge_change(change("九"),9);
    judge_change(change("十"),10);
    judge_change(change("二十"),-1);
    printf("test_change is over\n");
}

int main() {
    test_change();
   return 0;
}

按照(2)的步骤,我们建立相应的脚本文件,脚本代码如下:

#!/bin/bash

 gcc main.c -o test2.out
 if [ $? == 0 ]
 then
     echo "编译成功"
     ./test2.out
     if [ $? == 0 ]
     then
         echo "运行结束"
     else
         echo "运行失败"
     fi
 else
     echo "编译失败"
 fi

打开终端进行测试,结果如下:

Change 函数测试过后,我们来通过结果查看其他两个函数的正误:


以上就是测试部分的内容,感谢沈欢同学的帮助。

(4)添加功能:过命令行读取一个文件,然后运行这个文件

一看到题目疑惑不解,当学完shell后还以为就是Shell 文件包含重定向,后面发现并不是,这样,查了资料(链接已贴出)发现原来在我们c语言课本最后一章中有提到过对文件对操作(当初老师没教,而且考试也不考,就没看细看这一章,可是这次放假书放学校了,等回学校的时候再好好看看书)。以下是我的代码:

//main.h
#include <stdio.h>
#include <string.h>
int change(int wallet,char d[]){
      if(strcmp(d,"零")==0) return 0;
      else if(strcmp(d,"一")==0) return 1;
      else if(strcmp(d,"二")==0) return 2;
      else if(strcmp(d,"三")==0) return 3;
      else if(strcmp(d,"四")==0) return 4;
      else if(strcmp(d,"五")==0) return 5;
      else if(strcmp(d,"六")==0) return 6;
      else if(strcmp(d,"七")==0) return 7;
      else if(strcmp(d,"八")==0) return 8;
      else if(strcmp(d,"九")==0) return 9;
      else if(strcmp(d,"十")==0) return 10;
      else return -1;
}
void num(int i){
    if(i==0) printf("零");
    else if(i==1) printf("一");
    else if(i==2) printf("二");
    else if(i==3) printf("三");
    else if(i==4) printf("四");
    else if(i==5) printf("五");
    else if(i==6) printf("六");
    else if(i==7) printf("七");
    else if(i==8) printf("八");
    else if(i==9) printf("九");
    else if(i==10) printf("十");
}
void printf_sum(int wallet){
    int a,b;
    if(wallet<=10){num(wallet);}
    else{
        a=wallet/10;
        b=wallet%10;
        if(a!=1)num(a);
        printf("十");
       if(b!=0) num(b);
    }
}
void test(){  //注意把原代码的main函数改名,便于后续引用。
    char a[100],b[100],c[100],d[100];
    int  wallet=0,i,flag=0;
    scanf("%s %s %s %s",a,b,c,d);
    if(strcmp(a,"整数")!=0||strcmp(c,"等于")!=0) flag=1;
    for(i=1;flag==0;i++){
        if(i==1) wallet=change(wallet,d);
        else {
            scanf("%s",a);
            if(strcmp(a,b)!=0&&strcmp(a,"看看")!=0) break;
            scanf("%s",c);
            if(strcmp(a,"看看")==0){
                printf_sum(wallet);
                break;}
            scanf("%s",d);
         if(strcmp(c,"增加")==0) wallet+=change(wallet,d);
         if(strcmp(c,"减少")==0) wallet-=change(wallet,d);
        }
    }
    printf("\n");
}

//main.c
#include "main.h"
//argc:命令行传入参数的总个数
//argv:*argv[]是一个指针数组,里面存放的指针指向所有的命令行参数,argv[0]指向程序的全局路径,argv[1]指向在DOS命令行中执行程序名后的第一个字符串,argv[2]指向第二个。
int main(int argc,char * argv[]) {
    if(argc>1){
    //当argc = 1的时候,表示只有一个程序名称;当argc>1时,说明文本的内容已经输入其中。
    freopen(argv[1],"r",stdin);
    //FILE *freopen(文件名,文件打开的模式,一个文件,通常使用标准流文件);
    //"r"代表"只读"
  //准流文件具体是指stdin、stdout和stderr。其中stdin是标准输入流,默认为键盘;stdout是标准输出流,默认为屏幕;stderr是标准错误流,一般把屏幕设为默认。
    test();
    }
    //把缓冲区内最后剩余的数据输出到内核缓冲区,并释放文件指针和有关的缓冲区
    return 0;
}

然后通过终端将其编译为test,然后执行文本(注意在执行文本时需把文本与编译后的程序放在一个文件夹中):

对应文本内容为:


输出答案正确,添加功能成功。

3.疑惑及解决

* 本次作业将代码进行了进一步的优化,但仍存在一个问题待解决:对于钱包总额的变化仍然只能在*零至十*中进行,在下一阶段中将着重解决输入如“二十二”、“三十”的功能等实现 * 本次作业还学习了如何进行函数测试,了解了如何写脚本。对于单元测试,看到沈欢同学的博客中提到了*单元测试工具CUnit*,准备下一阶段中,进行学习。 * 本次作业还学习了github仓库的使用,将在下一阶段中借助作业EX进行深度学习。 * 本次作业还学习了如何通过c语言进行对文件的操作,以后也可将其进一步语言应用。有一个疑问:如果这一题我采用shell脚本中的文件包含重定向功能解决,应该也可以起到相似的功能,那么这两者有什么区别吗? * 将在下一阶段中学习c++,进一步了解课程。
posted @ 2020-02-03 10:46  平和Kenn  阅读(735)  评论(4编辑  收藏  举报