这个作业属于哪个课程 | 2020面向对象程序设计张栋班 |
---|---|
这个作业要求在哪里 | 面向对象程序设计寒假作业3 |
这个作业的目标 | 继续完成作业二的编程题、优化架构,思考代码的拓展性 |
作业正文 | 正文 |
其他参考文献 | C语言:函数返回字符串的四种方法 |
我的Github作业仓库 |
思考添加的功能
前两次的作业都完成了对两位数的功能实现,这一次就考虑对负数功能的实现,判断和循环目前是一点思路没有,想着看是否有大佬贡献一下代码来参考参考,因为前两次的主函数都过于复杂,所以这一次考虑着能否把主函数精简一下,代码就重新再打一遍,目标就是添加负数功能以及把主函数拆分成几个函数。在学习python的过程中,也越来越认识到写注释的重要性,特别是面对几百行几十天以前写的代码,没有注释看着就头痛。
首先是添加负数的功能
这里我将前两次作业的代码继续拆分成不同模块,而且现在的函数会在十五行以内完成,还是在这里提一下代码的格式、注释以及适当的空行会使程序更加美观,也更易读懂。
- 对输出这一简单的功能进行改进,在调用函数时首先调用的是
NumToCNJudge
函数,在这里的功能仅仅是对数字的符号进行判断,然后如果是正数的话会调用PositiveNumToCN
函数,这个函数差不多是前两次作业直接copy过来的,如果是负数的话,就调用NegativeNumToCN
,在函数中先输出一个“负”,然后调用PositiveNumToCN
函数对此时的“-num”进行处理代码如下:
//判断为正数的情况
void PositiveNumToCN(int num) {
if(num>=10){
if(num%10==0){
if(num==10){
printf("%s
",CN[10]); // 刚好为十
}
else{
printf("%s%s
",CN[num/10],CN[10]); // 整十情况
}
}
else{
if(num<20){
printf("%s%s
",CN[10],CN[num%10]); // 十几的情况
}
else{
printf("%s%s%s
",CN[num/10],CN[10],CN[num%10]); // 其余情况
}
}
}
else{
printf("%s
",CN[num]); // 一位数情况
}
}
// 判断为负数的情况
void NegativeNumToCN(int num) {
printf("负");
PositiveNumToCN(-num);
}
// 判断正负号
void NumToCNJudge(int num) {
if(num>0) {
PositiveNumToCN(num);
}
else if(num<0) {
NegativeNumToCN(num);
}
else {
printf("%s",CN[0]);
}
}
测试代码和测试结果如下:
#include"main.h"
int main()
{
NumToCNJudge(5);
NumToCNJudge(10);
NumToCNJudge(18);
NumToCNJudge(20);
NumToCNJudge(55);
NumToCNJudge(-5);
NumToCNJudge(-10);
NumToCNJudge(-18);
NumToCNJudge(-20);
NumToCNJudge(-55);
}
- 然后是比较难的对输入的数字进行判断的函数,这里不但要进行拆分,还要增加对负数的判断,所以首先调用的是
CNToNumJudge
函数,目的是为了判断第一位是否为“负”,接着进入CNToNumLen
函数判断长度,继而进行下一步拆分的三个函数CNToNum_2
、CNToNum_4
、CNToNum_6
进行判断不同的情况,其中对数字进行循环判断的函数继续引用自前两次作业的CNJudge
函数,代码如下:
// 汉字对比循环判断
int CNJudge(char* str){
int i;
for(i=0;i<11;i++){
if(strcmp(str,CN[i])==0){
return i;
}
}
return -1;
}
// 第一位是否为负判断
int CNToNumJudge(char str[]) {
char a[3],*p=str;
a[0]=str[0];
a[1]=str[1];
a[2]=0;
if(strcmp(keywords[5],a)==0) {
return -CNToNumLen(p+2);
}
else {
return CNToNumLen(str);
}
}
// 长度为六
int CNToNum_6(char str[]) {
char a[3],b[3];
a[0]=str[0];
a[1]=str[1];
a[2]=0;
b[0]=str[4];
b[1]=str[5];
b[2]=0;
return CNJudge(a)*10+CNJudge(b);
}
// 长度为四
int CNToNum_4(char str[]) {
char a[3],b[3];
a[0]=str[0];
a[1]=str[1];
a[2]=0;
b[0]=str[2];
b[1]=str[3];
b[2]=0;
if(strcmp(a,CN[10])==0) {
return CNJudge(b)+10;
}
else {
return CNJudge(a)*10;
}
}
// 长度为二
int CNToNum_2(char str[]) {
return CNJudge(str);
}
// 长度判断
int CNToNumLen(char str[]) {
int len=strlen(str);
if(len==6) {
return CNToNum_6(str);
}
else if(len==4) {
return CNToNum_4(str);
}
else if(len==2) {
return CNToNum_2(str);
}
}
测试代码和测试结果如下:
#include"main.h"
int main()
{
char num[15][12]={"五","十","十二","二十","三十五","九十一","零","负一","负十","负十五","负二十","负五十六"};
int i;
for(i=0;i<12;i++)
{
printf("%d
",CNToNumJudge(num[i]));
}
}
其次是主函数的划分
在前两次的作业的主函数中我已经划分出了两个模块,一个是变量定义模块,另一个是变量计算和输出变量模块,第二个模块还可以进行拆分,只对比第一个关键词,判断是进行变量计算或者是变量输出,这里考虑一下可以多次进行变量输出的办法,利用第一个关键词的输入可以使用ctrl + Z
结束输入。
- 在输入模块里我定义了
SetVar
函数进行变量的名字确定以及等于数字大小, 其中我把输入拆分为StrInput()
函数,我起初觉得利用函数调用后内存会释放来解决我之前两次作业采用的设置一百条指令的方法,更加人性化,于是我想当然的return一个函数里定义的字符数组名,然后报错了,于是上网搜,看到了这篇博客,于是采用malloc的方法,定义动态内存,代码如下:
// 字符串输入
char* StrInput() {
char* str;
str = (char*)malloc(10);
scanf("%s",str);
return str;
}
// 定义变量
void SetVar() {
char* command;
command=StrInput();
if(strcmp(command,keywords[0])==0) {
scanf("%s",name);
free(command);
command=StrInput();
if(strcmp(command,keywords[1])==0) {
command=StrInput();
target=CNToNumJudge(command);
free(command);
}
}
}
这里直接在本文件里测试,测试代码和结果如下:
int main() {
SetVar();
printf("%d
%s",target,name);
}
- 接着是变量处理,这里我原本以为是最难的一部分,但是代码写着写着就有种轻车熟路的感觉,首先是进入
DealVar
函数判断一下下一步是计算变量还是输出变量,接着分为两个函数,分别负责计算变量和输出变量,借助前两次作业的代码,我很简单就完成了功能,代码如下:
// 处理变量
void DealVar() {
while(1) {
char* command=StrInput();
if(strcmp(command,name)==0) {
CalculateVar();
}
else if(strcmp(command,keywords[4])==0) {
OutPutVar();
}
else if(strcmp(command,keywords[6])==0) {
break;
}
else {
printf("");
continue;
}
free(command);
}
}
// 计算变量
void CalculateVar() {
char* command=StrInput();
if(strcmp(command,keywords[2])==0) {
free(command);
command=StrInput();
target+=CNToNumJudge(command);
}
else if(strcmp(command,keywords[3])==0) {
free(command);
command=StrInput();
target-=CNToNumJudge(command);
}
else {
printf("");
}
free(command);
}
// 输出变量
void OutPutVar() {
char* command=StrInput();
if(strcmp(command,name)==0) {
NumToCNJudge(target);
}
else {
printf("");
}
free(command);
}
printf函数里为空是因为还没处理好报错的提醒格式,我直接贴出总程序的运行结果:
在做报错处理的时候,由于是在子函数中,由于我习惯性写
return 0
,导致编译报错,我上网搜索过后发现了在stdlib这个头文件里包含了一个原型为void exit(int)
的函数,可以直接结束程序,括号内的数值代表在主函数里使用return返回的值,下面是我程序的总代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void PositiveNumToCN(int num);
void NegativeNumToCN(int num);
void NumToCNJudge(int num);
int CNJudge(char* str);
int CNToNumJudge(char str[]);
int CNToNum_6(char str[]);
int CNToNum_4(char str[]);
int CNToNum_2(char str[]);
int CNToNumLen(char str[]);
char* StrInput();
void SetVar();
void DealVar();
void CalculateVar();
void OutPutVar();
const char CN[11][10]={"零","一","二","三","四","五","六","七","八","九","十"}; // 汉字数字
char keywords[7][20]={"整数","等于","增加","减少","看看","负","结束"}; // 关键字
int target; // 将变量对应的变量定义为全局变量
char name[20]; // 将定义变量的中文定义为全局变量
//判断为正数的情况
void PositiveNumToCN(int num) {
if(num>=10){
if(num%10==0){
if(num==10){
printf("%s
",CN[10]); // 刚好为十
}
else{
printf("%s%s
",CN[num/10],CN[10]); // 整十情况
}
}
else{
if(num<20){
printf("%s%s
",CN[10],CN[num%10]); // 十几的情况
}
else{
printf("%s%s%s
",CN[num/10],CN[10],CN[num%10]); // 其余情况
}
}
}
else{
printf("%s
",CN[num]); // 一位数情况
}
}
// 判断为负数的情况
void NegativeNumToCN(int num) {
printf("负");
PositiveNumToCN(-num);
}
// 判断正负号
void NumToCNJudge(int num) {
if(num>0) {
PositiveNumToCN(num);
}
else if(num<0) {
NegativeNumToCN(num);
}
else {
printf("%s",CN[0]);
}
}
// 汉字对比循环判断
int CNJudge(char* str) {
int i;
for(i=0;i<11;i++){
if(strcmp(str,CN[i])==0){
return i;
}
}
return -1;
}
// 第一位是否为负判断
int CNToNumJudge(char str[]) {
char a[3],*p=str;
a[0]=str[0];
a[1]=str[1];
a[2]=0;
if(strcmp(keywords[5],a)==0) {
return -CNToNumLen(p+2);
}
else {
return CNToNumLen(str);
}
}
// 长度为六
int CNToNum_6(char str[]) {
char a[3],b[3];
a[0]=str[0];
a[1]=str[1];
a[2]=0;
b[0]=str[4];
b[1]=str[5];
b[2]=0;
return CNJudge(a)*10+CNJudge(b);
}
// 长度为四
int CNToNum_4(char str[]) {
char a[3],b[3];
a[0]=str[0];
a[1]=str[1];
a[2]=0;
b[0]=str[2];
b[1]=str[3];
b[2]=0;
if(strcmp(a,CN[10])==0) {
return CNJudge(b)+10;
}
else {
return CNJudge(a)*10;
}
}
// 长度为二
int CNToNum_2(char str[]) {
return CNJudge(str);
}
// 长度判断
int CNToNumLen(char str[]) {
int len=strlen(str);
if(len==6) {
return CNToNum_6(str);
}
else if(len==4) {
return CNToNum_4(str);
}
else if(len==2) {
return CNToNum_2(str);
}
}
// 字符串输入
char* StrInput() {
char* str;
str = (char*)malloc(10);
scanf("%s",str);
return str;
}
// 定义变量
void SetVar() {
char* command=StrInput();
if(strcmp(command,keywords[0])==0) {
scanf("%s",name);
free(command);
command=StrInput();
if(strcmp(command,keywords[1])==0) {
command=StrInput();
target=CNToNumJudge(command);
free(command);
}
else {
printf("错误,应输入:等于
");
exit(0);
}
}
else {
printf("错误,应输入:整数
");
exit(0);
}
}
// 处理变量
void DealVar() {
while(1) {
char* command=StrInput();
if(strcmp(command,name)==0) {
CalculateVar();
}
else if(strcmp(command,keywords[4])==0) {
OutPutVar();
}
else if(strcmp(command,keywords[6])==0) {
break;
}
else {
printf("错误,应输入:看看 / %s",name);
exit(0);
}
free(command);
}
}
// 计算变量
void CalculateVar() {
char* command=StrInput();
if(strcmp(command,keywords[2])==0) {
free(command);
command=StrInput();
target+=CNToNumJudge(command);
}
else if(strcmp(command,keywords[3])==0) {
free(command);
command=StrInput();
target-=CNToNumJudge(command);
}
else {
printf("错误,应输入:增加 / 减少");
exit(0);
}
free(command);
}
// 输出变量
void OutPutVar() {
char* command=StrInput();
if(strcmp(command,name)==0) {
NumToCNJudge(target);
}
else {
printf("错误,应输入:%s",name);
}
free(command);
}
int main() {
SetVar();
DealVar();
return 0;
}
小结
在这次作业里又学到了malloc用于函数返回一个字符数组,可以说在将main
函数拆分的过程中,这个StrInput
函数是作了巨大贡献,其次就是exit()
函数的使用,也是帮到大忙,还有注释的添加是的程序明朗。再有就是命名的改进,虽然有些地方翻译过来可能不是很准确,但是还是使程序更加容易读懂。不足之处在于由于添加了负数的功能,导致数字输入错误报错这个功能被我遗弃掉了,想过一些方法,但是过于复杂就没有去实现,最终还是放弃了。有想过python有try和except的语法对于报错有着很好的处理办法,但是目前在C语言里没有学习此类方法。总体看来C语言给人踏踏实实的感觉,那种虽然平平淡淡,但是却十分让人放心的感觉。在学习python的过程中体会过python那些花哨的语法、模块或者是框架,但是一些东西过于高级,总是无法接受,想要深入去研究逻辑性太过去消耗脑力,而C语言始终是那个样子,而且现在学到越来越多,C语言也可以有各种各样的高级用法。怎么说呢,以前觉得哪个语言厉害就一定要会哪种语言,现在体会到了其实无论哪一门语言甚至是框架都有自己独特的魅力,适合自己的,自己兴趣的才是最好的。