实验三:内部模块化的命令行菜单小程序V2.0

本文介绍了一个内部模块化的命令行菜单小程序的设计与实现过程。该程序采用C语言开发,实现了菜单数据存储与业务逻辑的分离,支持帮助、退出、版本显示等功能。

实验三:内部模块化的命令行菜单小程序V2.0

【shawn520 + 《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006
【代码仓库】https://github.com/shawn520/SE.git
GitHub代码链接

实验要求

注意代码的业务逻辑和数据存储之间的分离,即将系统抽象为两个层级:
菜单业务逻辑和菜单数据存储

要求:
1)遵守代码风格规范,参考借鉴代码设计规范的一些方法;
2)代码的业务逻辑和数据存储使用不同的源文件实现,即应该有2个.c和一个.h作为接口文件。

实验目的

通过设计简单的命令行菜单细小程序,了解并掌握程序内部模块化设计的思想,实现菜单数据存储与菜单业务逻辑的分离.

实验思路

用一个静态链表来存储可变化的菜单命令及其对应函数,在主函数中实菜单命令逻辑

将数据结构的定义、函数声明放到linklist.h中,声明的函数在linklist.c中实现,在menu.c中定义main函数。共实验help、quit、version、四则运算arithmetic、输出当前系统时间time、判断两个数的大小judge、求一个数的倒数、给一列数排序。

实验过程

在一个头文件中定义链表数据结构及其操作原型,并在相应源文件中实现其操作;然后在主函数源文件中实现菜单命令。

进入实验目录并创建menu.c作为业务逻辑模块
git clone https://github.com/shawn520/SE.git
mkdir lab3
cd lab3
vim menu.c
在menu.c中添加如下代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "linklist.h"

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



/*menu program*/

static tDataNode head[] =
{
    {"help", "this is help cmd!", Help, &head[1]},
    {"version", "menu program v2.0", NULL, &head[2]},
    {"quit", "Quit from menu", Quit, &head[3]},
    {"add", "Addtion", Add, &head[4]},
    {"sub", "Substraction", Sub, &head[5]},
    {"Mul", "Multition", Mul, &head[6]},
    {"Div", "Division", Div, NULL}
};

int Hello()
{
    printf("Hi~My name is Shawn.\nThank you for use my cmd prgram!\n");

}

int main()
{

    /* cmd line begins */
    while(1)
    {
        char cmd[CMD_MAX_LEN];
        printf("Input a cmd number>");
        scanf("%s", cmd);
        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();
        }
    }
}

int Help()
{
    ShowAllCmd(head);
    return 0;
}

编辑linklist.h,作为数据存储模块,增加可重用性

vim linklist.h

/**************************************************************************/
/* Copyright (C) mc2lab.com, SSE@USTC, 2017-2018                          */
/*                                                                        */
/*  FILE NAME                   :   menu.c                                */
/*  PRINCIPAL AUTHOR            :   ShawnLiu                              */
/*  SUBSYSTEM NAME              :   menu                                  */
/*  MODULE NAME                 :   menu                                  */
/*  LANGUAGE                    :   C                                     */
/*  TARGET ENVIRONMENT          :   ANY                                   */
/*  DATE OF FIRST RELEASE       :   2017/10/07                            */
/*  DESCRIPTION                 :   This is a menu program                */
/**************************************************************************/

/*
 * Revision log:
 *
 * Created by ShawnLiu, 2017/10/07
 *
 */

/* data struct and its operations */
typedef struct DataNode
{
    char*   cmd;
    char*   desc;
    int     (*handler)();
    struct  DataNode *next;
}tDataNode;

/* find a cmd in the linklist and return the datanode pointer */
tDataNode* FindCmd(tDataNode * head, char * cmd);

/* show all cmd in listlist*/
int ShowAllCmd(tDataNode * head);

int Help();
int Quit();
int Add();
int Sub();
int Mul();
int Div();
再定义存储所有cmd的linklist数据结构, 并声明其操作方法FindCmd(), 以及遍历输出linklist中所有节点的ShowAllCmd():
vim linklist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linklist.h"

tDataNode *FindCmd(tDataNode *head, char *cmd)
{
    if(head == NULL || cmd == NULL)
    {
        return NULL;
    }
    tDataNode *p = head;
    while(p != NULL)
    {
        if(strcmp(p->cmd, cmd) == 0)
        {
            return p;
        }
        p = p->next;
    }
    return NULL;
}

int ShowAllCmd(tDataNode *head)
{
    printf("Menu List:\n");
    tDataNode *p = head;
    while(p != NULL)
    {
        printf("%s - %s\n", p->cmd, p->desc);
        p = p->next;
    }
    return 0;
}



int Quit()
{
    exit(0);
}

int Add()
{
    double num1, num2;
    double sum;
    printf("Addtion. Please input two numbers:\n");
    scanf("%lf %lf", &num1, &num2 );
    sum = num1 + num2;
    printf("%lf + %lf = %lf\n", num1, num2, sum);
    return 0;
}

int Sub()
{
    double num1, num2;
    double result;
    printf("Subtraction. Please input two numbers:\n");
    scanf("%lf %lf", &num1, &num2 );
    result = num1 - num2;
    printf("%lf - %lf = %lf\n", num1, num2, result);
}

int Mul()
{
    double num1, num2;
    double result;
    printf("Multiplication. Please input two numbers:\n");
    scanf("%lf %lf", &num1, &num2 );
    result = num1 * num2;
    printf("%lf * %lf = %lf\n", num1, num2, result);
}

int Div()
{
    int num1, num2;
    double result;
    printf("Division. Please input two numbers:\n");
    scanf("%d %d", &num1, &num2 );
    if(num2==0)
    {
        printf("Error: divisor can not be zero!\n");
    }
    else
    {
        result = num1 / num2;
        printf("%d / %d = %lf\n", num1, num2, result);
    }
}

编译得到可执行文件
gcc menu.c linklist.c -o menu

并测试menu程序的功能,如图所示
这里写图片描述

完成后提交到git

git add menu.c linklist.h linklist.c
git commit -m 'menu_v2.0'
git push

这里写图片描述
复审实验
本实验的代码可通过如下方式下载并运行

git clone https://github.com/shawn520/SE.git 
cd lab3
gcc menu.c linklist.c -o menu
./menu

实验心得及体会:

软件=程序+软件工程
程序=算法+数据结构

经过基本Modularity (also called separation of concerns)设计的代码
模块化的思想和命令行菜单的实现范例(开源社区中常见的写法)
基本模块化的写法

代码设计中的一些常见方法

  • KISS(keep it simple & stupid)
  • using design to frame the code(matching design with implementation)
  • including pseuducode
  • 不要和陌生人说话原则
  • 合理利用Control Structures、Data Structures来简化代码
  • 一定要有错误处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值