2017 Fall SoftwareEngineering Learning (6)
来源:互联网 发布:windows ant下载 编辑:程序博客网 时间:2024/05/18 00:40
2017 Fall Software Engineering Learning (6)
模块化 命令行菜单
公开发表一篇实验报告,并在实验报告中注明【网易云课堂昵称 + 《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006 】
一、实验需求分析
- 为menu子系统设计接口,并写用户范例代码来实现原来的功能;
- 使用make和make clean来编译程序和清理自动生成的文件;
- 使menu子系统支持带参数的复杂命令,并在用户范例代码中自定义一个带参数的复杂命令;
- 可以使用getopt函数获取命令行参数
二、程序思路分析
我们在上次的lab5代码的基础上进行修改(如果不清楚上次lab5实现了什么可以看看我之前的实验5)。
首先,我们将menu模块化,这就意味着我们将原来的main函数的内容用子函数实现并且定义接口,同时由于原来的menu程序是在menu.c文件里面定义的函数具体操作,所以说修改命令的具体内容就要在menu.c文件里面。但是为了向用户隐藏具体的实习细节,我们希望用户能够不要操作我们提供的源文件。那么我们就还需要一个函数来添加命令,用户能在自己的main函数里面调用这个函数向menu模块添加命令。
实现了上述功能之后就是让我们的命令支持参数输入,就像之前的main函数一样。这里我们只用修改一下menu模块,对于输入的字符串,我们用strtok解析一下,然后传递给相应的函数handler就可以了。
下面是实现上述功能的子函数模块:
int MenuConfig(char *cmd, char *desc, int (*handler)())//为命令链表添加命令int GetOpt(char *pcmd, int *argc, char *argv[])//从pcmd这一输入的字符串中将命令、参数提取出来int ExecuteMenu()//menu主模块,原来的main函数
三、程序具体实现
代码量有点小多,所以我就不贴上来啦。这里就介绍一下主要的几个函数模块,其他内容与实验5 的内容一样
int MenuConfig(char *cmd, char *desc, int (*handler)()){ tDataNode* pNode = NULL; if (head == NULL) { head = CreateLinkTable(); pNode = (tDataNode*)malloc(sizeof(tDataNode)); pNode->cmd = "help"; pNode->desc = "Menu List:"; pNode->handler = Help; AddLinkTableNode(head,(tLinkTableNode *)pNode); } pNode = (tDataNode*)malloc(sizeof(tDataNode)); pNode->cmd = cmd; pNode->desc = desc; pNode->handler = handler; AddLinkTableNode(head,(tLinkTableNode *)pNode); return 0;}
给命令列表添加命令的模块。
nt GetOpt(char *pcmd, int *argc, char *argv[]){ if (pcmd == NULL || argc == NULL || argv == NULL) { printf("Wrong in GetOpt, invalid arguments\n"); return FAILURE; } pcmd = strtok(pcmd," "); while(pcmd != NULL && *argc < CMD_MAX_ARGV_NUM) { argv[*argc]= pcmd; (*argc)++; pcmd = strtok(NULL," "); } if (*argc >= 1) { *(argv[*argc-1]+strlen(argv[*argc-1])-1)='\0'; } return SUCCESS;}
函数从pcmd中提取命令和参数,将参数数目存在argc中,参数具体内容存在字符串数组argv中。注意argc要用指针,不然无法将内容传递出去。
int ExecuteMenu(){ //InitMenuData(&head); /* cmd line begins */ char cmd[CMD_MAX_LEN]; while(1) { int argc = 0; char *argv[CMD_MAX_ARGV_NUM]; char *pcmd = NULL; printf("Input a cmd number > "); //scanf("%s", cmd); pcmd = fgets(cmd, CMD_MAX_LEN, stdin); if(pcmd == NULL) { continue; } if (GetOpt(pcmd, &argc, argv) == FAILURE) { printf("Wrong in ExecuteMenu, GetOpt failure\n"); return FAILURE; } tDataNode *p = FindCmd(head, cmd); if( p == NULL) { printf("This is a wrong cmd!\n "); continue; } printf("%s - %s\n", p->cmd, p->desc); if(p->handler != NULL) { p->handler(argc,argv); } } return SUCCESS;}
就是命令行菜单的主函数,其他的与实验5 区别不大。这里主要就时调用了GetOpt来解析参数,而且将gets换成了fgets,这是因为gets有数组超界的隐患,可能会导致内存泄漏。
接下来就是我的程序了:
/******************************************************************************* * Author : acrididcheng * Email : chenghuaming@aliyun.com * First Created : 2017-11-04 23:32 * Filename : test.c * Description : * *****************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include "menu.h"#include "linktable.h"int Quit(int argc, char *argv[]){ if(argc != 2) { printf("Usage: quit [-h/-t]\n"); return FAILURE; } if (strcmp(argv[1],"-h") == 0) { ; } if (strcmp(argv[1],"-t") == 0) { printf("Bye~~^_^\n"); } exit(0);}int Operate(int argc, char *argv[]){ if (argc != 4) { printf("Usage: operate ['+'/'-'/'*'/'/'] [double1] [double2]\n"); return FAILURE; } if (strcmp(argv[1],"+") == 0) { printf("the output is:%f\n",(atof(argv[2])+atof(argv[3]))); return SUCCESS; } else if (strcmp(argv[1],"-") == 0) { printf("the output is:%f\n",(atof(argv[2])-atof(argv[3]))); return SUCCESS; } else if (strcmp(argv[1],"*") == 0) { printf("the output is:%f\n",(atof(argv[2])*atof(argv[3]))); return SUCCESS; } else if (strcmp(argv[1],"/") == 0) { printf("the output is:%f\n",(atof(argv[2])/atof(argv[3]))); return SUCCESS; } else { printf("wrong operation\n"); return FAILURE; } return FAILURE;}int main(){ MenuConfig("version","menu Independent version 1.0.",NULL); MenuConfig("quit","quit from the menu",Quit); MenuConfig("operate","do some math calculation",Operate); ExecuteMenu(); return 0;}
可以看见我写了一个quit()函数和一个operate()函数。
这里为了测试功能,我将quit变成了加参数才能退出的函数,而且添加了一个具体的功能命令–operate,来实现double的基本运算(+,-,*,/)。
这个程序我就不讲了,超简单。有兴趣就自己看一下代码,很短。
哦,还有最后一个,要写一个Makefile文件,这个我在之前的几个实验里面都有用过,在写实验2的时候有过较详细的介绍。这个Makefile的代码变种特别多,所以这里就不再介绍了。有兴趣的可以去make的wiki看看各种语法。
四、程序效果演示
make一下后就可以运行了,这里可以发现,功能还是没什么大问题的。
运行完后make clean 清理一下就行了:
五、实验总结
这次讲解了参数的处理和整体模块化,让整个程序完整了,符合了尽可能模块化,精简main函数的思想,而且这次用到了makefile,使得整个工程圆满结束。非常有意义!!
- 2017 Fall SoftwareEngineering Learning (6)
- 2017 Fall SoftwareEngineering Learning (2)
- 2017 Fall SoftwareEngineering Learning (3)
- 2017 Fall SoftwareEngineering Learning (4)
- 2017 Fall SoftwareEngineering Learning (5)
- 2017 Fall Software Engineering Learning (1)
- 台大Hungyi Lee Machine-Learning 2017FALL HW0
- 台大Machine Learning 2017Fall HW0字数统计和图片淡化 解答
- 台大Machine Learning 2017Fall 卷积神经网络 Convolutional Neural Network
- 《CS PhD Journey》Chapter 1 Fall 2017
- Fall Regimen
- Fall in Madrid
- 坠入(Fall)赏析
- Data Structures, Fall 2007
- Fall through the cracks
- 2013Fall 申请总结
- break的fall through
- zoj3299 Fall the Brick
- 简单的密码输入三次错误模拟登陆
- 获取网络状态以及Fragment的隐藏和显示使用
- LA3027
- 5、位运算符(7个):实例
- 软设之路-4.1(数据结构及算法)
- 2017 Fall SoftwareEngineering Learning (6)
- LeetCode 476 Number Complement 补数
- Viewgroup(View容器)
- Pat 1016. 部分A+B (15)
- Android开发-认识palette
- SQL SERVER 2008 R2 增删改查之01
- 最小费用最大流
- 用于代码生成的抽象语法网络 (侵图删)
- 115