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


“软件工程(C编码实践篇)”实验报告
实验七:将menu设计为可重用的子系统
网易云课堂昵称: Arjen0130
《软件工程(C编码实践篇)》MOOC课程作业 http://mooc.study.163.com/course/USTC-1000002006
依照学术诚信条款,我保证此回答为本人原创,所有回答中引用的外部材料已经做了出处标记。
实验报告原链接地址: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函数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值