您的位置:首页 > 其它

实验七:将menu设计为可重用的子系统

2017-11-09 21:16 411 查看
“软件工程(C编码实践篇)”实验报告

实验七:将menu设计为可重用的子系统

网易云课堂昵称:Arjen0130

《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006

依照学术诚信条款,我保证此回答为本人原创,所有回答中引用的外部材料已经做了出处标记。

GitHub仓库:https://github.com/Arjen0130/AdvancedSoftwareEngineering.git

实验报告原链接地址:http://note.youdao.com/noteshare?id=c18689570e3e66ecc2d226d2603e1beb&sub=ADEC9A84FF5C4FEBB80D28D2A701F643

1. 实验内容和要求

1.1 实验内容

在实验5的代码的基础上,将menu设计为可重用的子系统

1.2 实验要求

为menu子系统设计接口,并写用户范例代码来实现原来的功能;

使用make和make clean来编译程序和清理自动生成的文件;

使menu子系统支持带参数的复杂命令,并在用户范例代码中自定义一个带参数的复杂命令;

可以使用getopt函数获取命令行参数。

注:本实验在实验5的代码基础上进行。

2. 实验的思路和具体过程

2.1 实验的思路

看完实验七的相关学习视频以后,学习到了将一个menu系统设计为可重用子系统的方法,特别是相关接口的定义方法。

依照视频讲解,并参照实验要求,从而完成本次实验。

2.2 实验的具体过程

1)使用实验1中创建好的本地仓库,添加lab7文件夹,把实验5的需要用到的文件复制到lab7文件夹中;

2)添加接口文件,并对已有的相关文件进行修改,使其能够作为可重用的子系统被调用;

3)添加测试文件,测试步骤2)中完成的可重用的子系统的相关功能是否正确;

4)编译、调试通过后,添加到git本地仓库,并上传到git远端仓库。

3. 关键代码

3.1 增加的接口文件menu.h
... ...
/*
* Add cmd to menu.
* @cmd: Name of the cmd to be added.
* @desc: Description of the cmd to be added.
* @handler: A function handler which executes the cmd.
* @return: Number reflects function status.
*/
int MenuConfig(char * cmd, char * desc, int (*handler)(int argc, char * argv[]));

/*
* Menu Engine Execute.
* @return: Number reflects function status.
*/
int ExecuteMenu();


3.2 对menu.c文件做出的修改
... ...
#include "menu.h"

int Help(int argc, char * argv[]);

#define CMD_MAX_LEN 128
#define CMD_MAX_ARGV_NUM 10
#define DESC_LEN 1024
#define CMD_NUM 10

//char cmd[CMD_MAX_LEN];

/* data struct and its operations */

typedef struct DataNode
{
tLinkTableNode * pNext;
char* cmd;
char* desc;
int (*handler)(int argc, char * argv[]);
} tDataNode;
... ...
/*
* Add cmd to menu.
* @cmd: Name of the cmd to be added.
* @desc: Description of the cmd to be added.
* @handler: A function handler which executes the cmd.
* @return: Number reflects function status.
*/
int MenuConfig(char * cmd, char * desc, int (*handler)(int argc, char * argv[]))
{
tDataNode * pNode = NULL;
if(NULL == head)
{
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;
}

/*
* Menu Engine Execute.
* @return: Number reflects function status.
*/
int ExecuteMenu()
{
/* cmd line begins */
while(1)
{
int argc = 0;
char *argv[CMD_MAX_ARGV_NUM];
char cmd[CMD_MAX_LEN];
char * pcmd = NULL;
printf("Input a cmd > ");
/* scanf("%s", cmd); */
pcmd = fgets(cmd, CMD_MAX_LEN, stdin);
if(NULL == pcmd)
{
continue;
}
/* convert cmd to argc/argv */
pcmd = strtok(pcmd, " ");
while((NULL != pcmd) && (CMD_MAX_ARGV_NUM > argc))
{
argv[argc++] = pcmd;
pcmd = strtok(NULL, " ");
}
if(1 == argc)
{
int len = strlen(argv[0]);
*(argv[0] + len - 1) = '\0';
}
tDataNode *p = FindCmd(head, argv[0]);
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);
}
}
}

int Help(int argc, char * argv[])
{
ShowAllCmd(head);
return 0;
}

... ...


3.3 增加的测试文件test.c
... ...

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include "menu.h"

#define MAX_OPTION_ARGUMENT_SIZE 128

/*
*This function is used to process the "compare" command.
*/
int compare(int argc, char * argv[])
{
int ch;
char argA[MAX_OPTION_ARGUMENT_SIZE];
char argB[MAX_OPTION_ARGUMENT_SIZE];
printf("This is the compare command...\n");
/* for(int i = 0; i < argc; i++) */
/* { */
/* printf("The argv[%d] = %s\n", i, argv[i]); */
/* } */
/* printf("optind: %d\n", optind); */
optind = 1; //这句必不可少,否则,多次执行相同的参数时,会出现结果不一致的情
while((ch = getopt(argc, argv, "a:b:")) != -1)
{
printf("optind: %d\n", optind);
switch(ch)
{
case 'a':
printf("HAVE option: -a\n");
printf("The argument of -a is %s\n", optarg);
argA[0] = '\0';
if(NULL != optarg)
{
memcpy(argA, optarg, strlen(optarg));
}
break;
case 'b':
printf("HAVE option: -b\n");
printf("The argument of -b is %s\n", optarg);
argB[0] = '\0';
if(NULL != optarg)
{
memcpy(argB, optarg, strlen(optarg));
}
break;
case '?':
printf("Unknown option: %c\n", (char)optopt);
break;
}
}
return 0;
}

/*
*This function is used to process the "get" command.
*/
int get(int argc, char * argv[])
{
printf("This is the get command...\n");
return 0;
}

/*
*This function is used to process the "pull" command.
*/
int pull(int argc, char * argv[])
{
printf("This is the pull command...\n");
return 0;
}

/*
*This function is used to process the "push" command.
*/
int push(int argc, char * argv[])
{
printf("This is the push command...\n");
return 0;
}

/*
*This function is used to process the "put" command.
*/
int put(int argc, char * argv[])
{
printf("This is the put command...\n");
return 0;
}

/*
*This function is used to quit the program.
*/
int quit(int argc, char * argv[])
{
printf("This is the quit command...\n");
exit(0);
}

int main(int argc, int * argv[])
{
MenuConfig("compare", "compare cmd:", compare);
MenuConfig("get", "get cmd:", get);
MenuConfig("pull", "pull cmd:", pull);
MenuConfig("push", "push cmd:", push);
MenuConfig("put", "put cmd:", put);
MenuConfig("quit", "quit Cmd:", quit);
return ExecuteMenu();
}


3.4 Makefile文件代码
#
# Makefile for Menu Program
#

CC_PTHREAD_FLAGS = -lpthread
CC_FLAGS = -c
CC_OUTPUT_FLAGS = -o
CC = gcc
RM = rm
RM_FLAGS = -f

TARGET = test
OBJS = test.o menu.o linktable.o

all: $(OBJS)
$(CC) $(CC_OUTPUT_FLAGS) $(TARGET) $(OBJS)

.c.o:
$(CC) $(CC_FLAGS) $<

clean:
$(RM) $(RM_FLAGS) $(OBJS) $(TARGET) *.bak


4. 相关截图

4.1 实验结果截图



4.2 关键代码截图

4.2.1 test.c文件中的关键代码截图







4.2.2 menu.h文件中的关键代码截图



4.2.3 menu.c文件中的关键代码截图









4.2.4 Makefile文件截图



4.3 操作过程截图

4.3.1 本次实验用到的头文件和源文件



4.3.2 执行make命令后的结果





4.3.3 将本地仓库的变化提交到远端仓库





4.4 复现操作截图



5. 实验过程中遇到的疑惑、困难及处理方法

本次实验过程中遇到的最大的问题就是getopt函数的调用问题。对应的menu命令初次执行的之后,一切正常,getopt函数可以正确读出menu命令的选项和参数。但是,当重复执行时,该函数无法正常工作。经过查找相关资料,发现getopt函数的使用了几个全局变量,其中一个optind变量用来记录上一次的处理位置。实际结果表明,为了使同一个命令能够多次重复工作,在调用getopt函数之前,需要重置optind变量的值。

6. 实验总结

通过本次实验,学习到了将一个menu程序修改为可重入子系统的方法。并且,学习使用了getopt函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: