面向对象程序设计2020第一次作业
这个作业属于哪个课程 | 2020面向对象程序设计张栋班 |
---|---|
这个作业要求在哪里 | 寒假作业2 |
这个作业的目标 | 完善代码、新建GitHub仓库并上传代码、制作编译脚本、进行单元测试并制作测试脚本、添加文件读取功能 |
作业正文 | 第二次作业 |
其它参考文献 | git教程 |
shell教程 | |
执行脚本的三种方式 | |
C语言命令行参数的使用 | |
C语言文件操作 | |
git和GitHub教程 |
注: 系统是Mac OS
实践题
-
创建SSH Key
-
新建仓库
-
clone到本地
-
其中仓库地址从这里复制
- 创建.gitignore文件,配置后传到仓库(具体配置到gitignore模版找自己需要的,再复制组合到自己的.gitignore文件中)
- 将代码放到该文件夹后传到仓库
- push时如果出现问题,可参考下图
编程题
一、优化代码
- 能够输入两位数三位数,如“二十”,“三十三”。具体实现在processStringToInt函数。
- 分为几个函数,使含义更清晰,可读性提高
int convertToInt(char str[]);// 中文转为数字
char* convertToString(int n);// 数字转为中文
void error(void);//输出错误
void execute(void);// 执行
int processStringToInt(char number[]);// 在convertToInt函数的基础上,实现处理两位数和三位数中文
void printResult(int n); // 输出结果
- 优化后完整代码
//main.h
#ifndef UNTITLED_MAIN_H
#define UNTITLED_MAIN_H
#include <stdio.h>
#include <string.h>
typedef struct variable
{
char name[1000];
int value;
} var;
int convertToInt(char str[]);// 中文转为数字
char* convertToString(int n);// 数字转为中文
void error(void);//输出错误
void execute(void);// 执行
int processStringToInt(char number[]);// 在convertToInt函数的基础上,实现处理两位数和三位数中文
void printResult(int n); // 输出结果
#endif //UNTITLED_MAIN_H
// main.c
#include "main.h"
int main()
{
char integer[6];
scanf("%s",integer);
if(strcmp(integer,"整数")){ // 判断第一个词是否为“整数”
error();
}
else{
execute();//执行
}
return 0;
}
//error.c
#include "main.h"
void error()
{
printf("格式错误\n");
}
// convertToInt.c
#include "main.h"
int convertToInt(char str[])
{
if(!strcmp(str,"零")) return 0;
else if(!strcmp(str,"一")) return 1;
else if(!strcmp(str,"二")) return 2;
else if(!strcmp(str,"三")) return 3;
else if(!strcmp(str,"四")) return 4;
else if(!strcmp(str,"五")) return 5;
else if(!strcmp(str,"六")) return 6;
else if(!strcmp(str,"七")) return 7;
else if(!strcmp(str,"八")) return 8;
else if(!strcmp(str,"九")) return 9;
else if(!strcmp(str,"十")) return 10;
else return -1;
}
//convertToString.c
char* convertToString(int n)
{
if(n == 0) return "零";
else if(n == 1) return "一";
else if(n == 2) return "二";
else if(n == 3) return "三";
else if(n == 4) return "四";
else if(n == 5) return "五";
else if(n == 6) return "六";
else if(n == 7) return "七";
else if(n == 8) return "八";
else if(n == 9) return "九";
else if(n == 10) return "十";
else return "Error";
}
//execute.c
#include "main.h"
void execute()
{
var a;
char name[1000],operator[6],number[8];
scanf("%s%s%s",a.name,operator,number);
if(strcmp(operator,"等于")){
error();
}
else{
if(processStringToInt(number) == -1) error();
else {
a.value = processStringToInt(number); //赋初始值
scanf("%s", name);
//循环执行到某行首个字符串不是变量名
while (!strcmp(name, a.name)) {
scanf("%s%s", operator, number);
if (!strcmp(operator, "增加")) {
a.value += processStringToInt(number);
} else if (!strcmp(operator, "减少")) {
a.value -= processStringToInt(number);
} else {
error();
break;
}
scanf("%s", name);
}
if (!strcmp(name, "看看")) {
scanf("%s", name);
if (!strcmp(name, a.name))//“看看”后面输入的内容得和前面的变量名称相同
{
printResult(a.value);
} else {
printf("不存在此变量\n");
}
}
}
}
}
//processStringToInt.c
#include "main.h"
int processStringToInt(char number[])
{
char str1[3],str2[3],str3[3];
int sum = 0;
strncpy(str1,number,2);
str1[2] = '\0';
sum = convertToInt(str1);
if(strlen(number) == 4)//输入两位数中文
{
strncpy(str2,number+2,2);//从number字符串的第三个字符number[2]开始复制
str2[2] = '\0'; //结尾要加\0,否则会出错
if(convertToInt(str2) == 10)
sum = convertToInt(str2) * convertToInt(str1);//大于10且为十的整数倍
else if(convertToInt(str2) != -1)
sum = convertToInt(str2) + convertToInt(str1); //十一到十九
else
sum = -1;
}
if(strlen(number) == 6)//输入三位数中文
{
strncpy(str3,number+4,2);
str3[2] = '\0';
sum = convertToInt(str1)*10 + convertToInt(str3); // 二十一~九十九(不包括十的整数倍)
}
return sum;
}
//printResult.c
#include "main.h"
void printResult(int n)
{
if(n <= 10)
{
printf("%s",convertToString(n));
}
else if(n % 10 == 0 && n < 100)
{
printf("%s十",convertToString(n/10));//十的整数倍输出为几十而不是几零
}
else if(n < 20)
{
n %= 10;
printf("十%s",convertToString(n));//输出十几而不是一十几
}
else if(n < 100)
{
printf("%s十%s",convertToString(n/10),convertToString(n%10));
}
else
{
printf("变量数值超出范围");
}
}
二、编译脚本
- 代码如下,所使用脚本语言为shell
#!/bin/bash
fileName=$1 #注意不能有空格 #$0指此文件名 $1指运行此文件时的第一个参数名,也就是要编译的文件名
echo "开始编译......"
gcc $fileName -o result.out # 使用一个定义过的变量,只要在变量名前面加美元符号$即可
if [ $? == 0 ] # $? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
then #注意中括号周围的空格
echo "编译成功......"
echo "开始运行......"
./result.out
if [ $? == 0 ]
then
echo "运行结束......"
else
echo "运行失败......"
fi
else
echo "编译失败......"
fi
- 实现效果
三、 单元测试
- 一开始理解错意思了,花了好长时间学了个单元测试工具CUnit,直到助教在群里说才知道是我想多了, 当场死亡
- 首先测试三个转换函数(test.c作了修改,感谢分享)
//test.c
#include "main.h"
void assert_str_equals(const char *actual, const char *expected)
{
if (!strcmp(actual, expected))
printf("Pass\n");
else
printf("Failed. actual: %s, expected: %s\n", actual, expected);
}
void assert_int_equals(int actual, int expected)
{
if (actual == expected)
printf("Pass\n");
else
printf("Failed. actual: %d, expected: %d\n", actual, expected);
}
void test_convertToString()
{
printf("test_convertToString 开始----------\n");
assert_str_equals(convertToString(0),"零");
assert_str_equals(convertToString(1),"一");
assert_str_equals(convertToString(2),"二");
assert_str_equals(convertToString(3),"三");
assert_str_equals(convertToString(4),"四");
assert_str_equals(convertToString(5),"五");
assert_str_equals(convertToString(6),"六");
assert_str_equals(convertToString(7),"七");
assert_str_equals(convertToString(8),"八");
assert_str_equals(convertToString(9),"九");
assert_str_equals(convertToString(10),"十");
assert_str_equals(convertToString(11),"Error");
assert_str_equals(convertToString(21),"Error");
printf("test_convertToString 结束----------\n");
}
void test_convertToInt()
{
printf("test_convertToInt 开始----------\n");
assert_int_equals(convertToInt("零"), 0);
assert_int_equals(convertToInt("一"), 1);
assert_int_equals(convertToInt("二"), 2);
assert_int_equals(convertToInt("三"), 3);
assert_int_equals(convertToInt("四"), 4);
assert_int_equals(convertToInt("五"), 5);
assert_int_equals(convertToInt("六"), 6);
assert_int_equals(convertToInt("七"), 7);
assert_int_equals(convertToInt("八"), 8);
assert_int_equals(convertToInt("九"), 9);
assert_int_equals(convertToInt("十"), 10);
assert_int_equals(convertToInt("百"), -1);
assert_int_equals(convertToInt("十一"), -1);
printf("test_convertToInt 结束----------\n");
}
void test_pcocessStringToInt()
{
printf("test_pcocessStringToInt开始----------\n");
assert_int_equals(processStringToInt("零"), 0);
assert_int_equals(processStringToInt("六"), 6);
assert_int_equals(processStringToInt("十一"), 11);
assert_int_equals(processStringToInt("二十"), 20);
assert_int_equals(processStringToInt("七十"), 70);
assert_int_equals(processStringToInt("四十二"), 42);
assert_int_equals(processStringToInt("九十九"), 99);
assert_int_equals(processStringToInt("六十六"), 66);
assert_int_equals(processStringToInt("五十三"), 53);
assert_int_equals(processStringToInt("一百"), -1);
assert_int_equals(processStringToInt("三百"), -1);
printf("test_pcocessStringToInt结束----------\n");
}
int main()
{
test_convertToInt();
test_convertToString();
test_pcocessStringToInt();
}
- 测试脚本
#!/bin/bash
echo "开始编译......"
gcc test.c excute.c convertToInt.c convertToString.c error.c printResult.c processStringToInt.c
if [ $? == 0 ]
then
echo "编译成功......"
echo "开始运行......"
./a.out
if [ $? == 0 ]
then
echo "运行成功......"
else
echo "运行失败......"
fi
else
echo "编译失败"
fi
- 运行结果
- 运行方法:在终端cd进入文件夹,然后输入 bash filename.sh(filename指的是脚本的文件名)
- 上面两个函数测试过了以后,其他几个函数由运行结果来验证
四、 添加以下功能
- 通过命令行读取一个文件,然后运行这个文件。
- 完成这题真是坎坷,一直理解错题目的意思。题目改完后才知道是要把1.txt 的内容作为输入
- 首先要知道命令行参数的使用和文件的相关知识,main函数如下
//argc是参数的个数,argv[0]是执行的程序名,argv[1]是第一个参数(参考文章在开头有注明)
int main(int argc,char const* argv[])
{
FILE* fp = fopen(argv[1],"r"); //打开1.txt “r”指的是只读
if(fp) //fopen:如果文件顺利打开,返回指向该流的文件指针。如果文件打开失败则返回NULL
{
char integer[6];
fscanf(fp,"%s", integer); //与scanf的区别只是加了第一个参数,是文件指针 //如果要从文件中输入,就得用该方式,而不是普通的scanf
if (strcmp(integer, "整数"))
{
error();
}
else
{
execute(fp);//该函数还要用到该文件,所以fp得传进该函数
}
fclose(fp);
}
else
{
printf("can't open the file\n");
}
return 0;
}
- 运行
- 首先cd进入文件夹,然后将程序编译成 lang
- 然后如下图
- 上图对应的1.txt是
整数 钱包 等于 零 钱包 增加 四 钱包 减少 三 看看 钱包
- 如果将1.txt改为
整数 钱包 等于 十一 钱包 增加 二十六 钱包 减少 三 钱包 减少 二十 看看 钱包
- 结果还是正确的
写在最后
- 不得不说通过第二次作业学到的东西还是很多的,很多都是之前不会的,只能现学,关键是有时候题目都不知道什么意思,不但要弄懂概念还要学很多新知识(分分钟自闭)
- 顺便记录一下重定向(一开始以为第四部分的功能是这样做)
- 在第一部分代码的情况下,在终端运行方式如下
文件重定向的定义:将原来**从标准输入读取数据**的文件操作重新定向为**从向其他文件读取数据**;将原来要输出到**标准输出**的内容,重新定向输出到**指定的其他文件**
< // 标准输入重定向
> // 标准输出重定向 清空原先的内容后添加新的内容
>> // 标准输出重定向 在原来内容换行下方添加新的内容
来源:oschina
链接:https://my.oschina.net/u/4302665/blog/3313254