网易云课堂昵称:sa17225159
《软件工程(C编码实践篇)》MOOC课程作业 http://mooc.study.163.com/course/USTC-1000002006
实验四:用可重用的链表模块来实现命令行菜单小程序V2.5
实验要求
- 用可重用的链表模块来实现命令行菜单小程序,执行某个命令时调用一个特定的函数作为执行动作;
- 链表模块的接口设计要足够通用,命令行菜单小程序的功能保持不变;
- 可以将通用的Linktable模块集成到我们的menu程序中;
接口规范;
实验过程
1.建立远程仓库,并下载到本地,远程仓库地址:https://github.com/libaoquan95/seClass_lab4.git
git clone https://github.com/libaoquan95/seClass_lab4.git
并进入版本库并创建 menu.c linktable.h linktable.c 文件
2 linktable.h
#ifndef _LINK_TABLE_H_
#define _LINK_TABLE_H_
#include <pthread.h>
#define SUCCESS 0
#define FAILURE (-1)
/*
* LinkTableNode Node Type
*/
typedef struct LinkTableNode
{
struct LinkTableNode *pNext;
}tLinkTableNode;
/*
* LinkTableNode Type
*/
typedef struct LinkTable
{
tLinkTableNode * pHead;
tLinkTableNode * pTail;
int SumOfNode;
}tLinkTable;
tLinkTable * CreateLinkTable();
int DelLinkTable(tLinkTable* pLinkTable);
int AddLinkTable(tLinkTable* pLinkTable,tLinkTableNode *pNode);
int AddLinkTableNode(tLinkTable *pLinkTable, tLinkTableNode *pNode);
int DelLinkTableNode(tLinkTable* pLinkTable,tLinkTableNode *pNode);
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable);
tLinkTableNode * GetNextLinkTableNode(tLinkTable* pLinkTable,tLinkTableNode *pNode);
#endif
3 linktable.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linktable.h"
tLinkTable * CreateLinkTable()
{
tLinkTable *pLinkTable=(tLinkTable*)malloc(sizeof(tLinkTable));
if (pLinkTable == NULL)
{
return NULL;
printf("create linktable failure! ");
}
pLinkTable->pHead = NULL;
pLinkTable->pTail = NULL;
pLinkTable->SumOfNode = 0;
return pLinkTable;
}
int DelLinkTable(tLinkTable* pLinkTable)
{
if(pLinkTable == NULL)
{
return FAILURE;
}
while(pLinkTable->pHead != NULL)
{
tLinkTableNode *p = pLinkTable->pHead;
pLinkTable->pHead = p->pNext;
free(p);
}
pLinkTable->pHead = NULL;
pLinkTable->pTail = NULL;
pLinkTable->SumOfNode = 0;
free(pLinkTable);
return SUCCESS;
}
int AddLinkTable(tLinkTable* pLinkTable,tLinkTableNode *pNode)
{
if(pLinkTable == NULL || pNode == NULL)
{
return FAILURE;
}
if(pLinkTable->pHead == NULL && pLinkTable->pTail == NULL)
{
pLinkTable->pHead = pNode;
pLinkTable->pTail = pNode;
pLinkTable->pTail = NULL;
pLinkTable->SumOfNode = 1;
}
else
{
pLinkTable->pTail->pNext = pNode;
pLinkTable->pTail = pNode;
pLinkTable->pTail->pNext = NULL;
pLinkTable->SumOfNode ++;
}
return SUCCESS;
}
int AddLinkTableNode(tLinkTable *pLinkTable, tLinkTableNode *pNode)
{
if (pLinkTable == NULL || pNode == NULL)
return FAILURE;
if (pLinkTable->pHead == NULL)
{
pLinkTable->pHead = pNode;
pLinkTable->pTail = pNode;
pLinkTable->SumOfNode = 1;
}
else
{
pLinkTable->pTail->pNext = pNode;
pLinkTable->pTail = pNode;
pLinkTable->SumOfNode++;
}
return SUCCESS;
}
int DelLinkTableNode(tLinkTable* pLinkTable,tLinkTableNode *pNode)
{
if (pLinkTable == NULL)
{
return FAILURE;
}
tLinkTableNode *pWork = pLinkTable->pHead;
tLinkTableNode *pre = pWork;
if (pLinkTable->pHead == pNode)
{
pLinkTable->pHead = pWork->pNext;
free(pWork);
return SUCCESS;
}
while (pWork != NULL)
{
if(pWork == pNode)
{
pre->pNext = pWork->pNext;
free(pWork);
return SUCCESS;
}
pre = pWork;
pWork = pWork->pNext;
}
return FAILURE;
}
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable)
{
if (pLinkTable->pHead == NULL)
{
printf("LinkTable is empty\n");
return NULL;
}
return pLinkTable->pHead;
}
tLinkTableNode * GetNextLinkTableNode(tLinkTable* pLinkTable,tLinkTableNode *pNode)
{
if (pLinkTable == NULL || pNode == NULL)
{
printf("LinkTable is empty\n");
return NULL;
}
tLinkTableNode *pWork = pLinkTable->pHead;
while(pWork != NULL)
{
if(pWork == pNode)
return pWork->pNext;
pWork = pWork->pNext;
}
return NULL;
}
4 menu.c
/*
* Copyright (C) libaoquan95@github.com, 2017-2018
*
* File name : menu.c
* Principal author : libaoquan95
* Subsystem name : menu
* Module name : menu
* Language : C
* Date of first release : 2017/10/09
* Deacription : This is a menu program
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "linktable.h"
#define CMD_MAX_LEN 128
#define DESC_LEN 1024
#define CMD_NUM 10
int PrintCommand();
int PrintSystemTime();
int PrintCurrentWorkingDirectory();
int Add();
int Sub();
int Mul();
int Div();
int Quit();
typedef struct DataNode
{
tLinkTableNode * pNext;
char* cmd;
char* desc;
int (*handler)();
}tDataNode;
tDataNode * FindCmd(tLinkTable *head, char *cmd)
{
tDataNode *pNode = (tDataNode*)GetLinkTableHead(head);
while(pNode != NULL)
{
if(strcmp(pNode->cmd, cmd) == 0)
{
return pNode;
}
pNode = (tDataNode*)GetNextLinkTableNode(head, (tLinkTableNode*)pNode);
}
return NULL;
}
int ShowAllCmd(tLinkTable *head)
{
tDataNode *pNode = (tDataNode*)GetLinkTableHead(head);
printf("-------------------------------------------------------------------\n");
while(pNode != NULL)
{
printf("\t\t %s: \t\t %s\n", pNode->cmd, pNode->desc);
pNode= (tDataNode*)GetNextLinkTableNode(head, (tLinkTableNode*)pNode);
}
printf("-------------------------------------------------------------------\n");
return 0;
}
/*static tDataNode menu[] =
{
{(tLinkTableNode*)&menu[1], "help", "Print all command of menu", PrintCommand},
{(tLinkTableNode*)&menu[2], "time", "Show system time", PrintSystemTime},
{(tLinkTableNode*)&menu[3], "pwd", "Show current working directory", PrintCurrentWorkingDirectory},
{(tLinkTableNode*)&menu[4], "add", "Calculate the summarize of the two integer numbers", Add},
{(tLinkTableNode*)&menu[5], "sub", "Calculate the subtractions of the two integer numbers", Sub},
{(tLinkTableNode*)&menu[6], "mul", "Calculate the multiplication of the two integer numbers", Mul},
{(tLinkTableNode*)&menu[7], "div", "Calculate the division of the two integer numbers", Div},
{(tLinkTableNode*)NULL, "quit", "Exit menu program", Quit}
};*/
int InitMenuData(tLinkTable **ppLinkTable)
{
/**ppLinkTable = CreateLinkTable();
(*ppLinkTable)->pHead = (tLinkTableNode*)&menu[0];
(*ppLinkTable)->pTail = (tLinkTableNode*)&menu[7];
(*ppLinkTable)->SumOfNode = 8;*/
*ppLinkTable = CreateLinkTable();
tDataNode *pNode0 = (tDataNode*)malloc(sizeof(tDataNode));
pNode0->cmd = "help";
pNode0->desc = "Print all command of menu";
pNode0->handler = PrintCommand;
AddLinkTableNode(*ppLinkTable, (tLinkTableNode*)pNode0);
tDataNode *pNode1 = (tDataNode*)malloc(sizeof(tDataNode));
pNode1->cmd = "time";
pNode1->desc = "Show system time";
pNode1->handler = PrintSystemTime;
AddLinkTableNode(*ppLinkTable, (tLinkTableNode*)pNode1);
tDataNode *pNode2 = (tDataNode*)malloc(sizeof(tDataNode));
pNode2->cmd = "pwd";
pNode2->desc = "Show current working directory";
pNode2->handler = PrintCurrentWorkingDirectory;
AddLinkTableNode(*ppLinkTable, (tLinkTableNode*)pNode2);
tDataNode *pNode3 = (tDataNode*)malloc(sizeof(tDataNode));
pNode3->cmd = "add";
pNode3->desc = "Calculate the summarize of the two integer numbers";
pNode3->handler = Add;
AddLinkTableNode(*ppLinkTable, (tLinkTableNode*)pNode3);
tDataNode *pNode4 = (tDataNode*)malloc(sizeof(tDataNode));
pNode4->cmd = "sub";
pNode4->desc = "Calculate the subtractions of the two integer numbers";
pNode4->handler = Sub;
AddLinkTableNode(*ppLinkTable, (tLinkTableNode*)pNode4);
tDataNode *pNode5 = (tDataNode*)malloc(sizeof(tDataNode));
pNode5->cmd = "mul";
pNode5->desc = "Calculate the multiplication of the two integer numbers";
pNode5->handler = Mul;
AddLinkTableNode(*ppLinkTable, (tLinkTableNode*)pNode5);
tDataNode *pNode6 = (tDataNode*)malloc(sizeof(tDataNode));
pNode6->cmd = "div";
pNode6->desc = "Calculate the division of the two integer numbers";
pNode6->handler = Div;
AddLinkTableNode(*ppLinkTable, (tLinkTableNode*)pNode6);
tDataNode *pNode7 = (tDataNode*)malloc(sizeof(tDataNode));
pNode7->cmd = "quit";
pNode7->desc = "Exit menu program";
pNode7->handler = Quit;
AddLinkTableNode(*ppLinkTable, (tLinkTableNode*)pNode7);
}
tLinkTable *head = NULL;
int main()
{
InitMenuData(&head);
while(1)
{
char cmd[CMD_MAX_LEN];
printf("$menu > ");
scanf("%s", cmd);
tDataNode *p = FindCmd(head, cmd);
if(p == NULL)
{
printf("ERROR: This is not a command, you can input 'help' to find command\n");
continue;
}
if(p->handler != NULL)
{
p->handler();
}
}
}
/**
* print all command and it's information
* @param none
* @return none
*/
int PrintCommand()
{
ShowAllCmd(head);
return 0;
}
/**
* print current time
* @param none
* @return none
*/
int PrintSystemTime()
{
struct tm *ptr;
time_t it;
it = time(NULL);
ptr = localtime(&it);
printf("%4d年%02d月%02d日 %d:%d:%d\n", ptr->tm_year + 1900, ptr->tm_mon + 1, ptr->tm_mday,
ptr->tm_hour, ptr->tm_min,ptr->tm_sec);
return 0;
}
/**
* print current working directory path
* @param none
* @return none
*/
int PrintCurrentWorkingDirectory()
{
char buf[256];
getcwd(buf, sizeof(buf));
printf("当前路径: %s\n", buf);
return 0;
}
/**
* calculate add of two interage numbers
* @param none
* @return calculate result
*/
int Add()
{
int num1 = 0, num2 = 0;
printf("input number1:");
scanf("%d", &num1);
printf("input number2:");
scanf("%d", &num2);
printf("%d + %d = %d\n", num1, num2, num1 + num2);
return 0;
}
/**
* calculate sub of two interage numbers
* @param none
* @return calculate result
*/
int Sub()
{
int num1 = 0, num2 = 0;
printf("input number1:");
scanf("%d", &num1);
printf("input number2:");
scanf("%d", &num2);
printf("%d - %d = %d\n", num1, num2, num1 - num2);
return 0;
}
/**
* calculate mul of two interage numbers
* @param none
* @return calculate result
*/
int Mul()
{
int num1 = 0, num2 = 0;
printf("input number1:");
scanf("%d", &num1);
printf("input number2:");
scanf("%d", &num2);
printf("%d * %d = %d\n", num1, num2, num1 * num2);
return 0;
}
/**
* calculate div of two interage numbers
* @param none
* @return calculate result
*/
int Div()
{
int num1 = 0, num2 = 0;
printf("input number1:");
scanf("%d", &num1);
printf("input number2:");
scanf("%d", &num2);
if(num2 != 0)
{
printf("%d / %d = %d\n", num1, num2, num1 / num2);
}
else
{
printf("ERROR: don't division 0\n");
}
return 0;
}
/**
* quit command
* @param none
* @return none
*/
int Quit()
{
exit(0);
return 0;
}
5.编译程序并运行
5.1 编译
gcc linktable.h linktable.c menu.c -o menu
./menu
5.2 运行
help 命令
time 命令
pwd 命令
add 命令
sub 命令
mul 命令
div 命令
错误的命令
quit 命令
6.上传至远程版本库
实验总结
远程仓库地址:https://github.com/libaoquan95/seClass_lab4.git
通过这次菜单程序模块化设计使我学会了许多的软件工程思想,体会到了模块化的巨大作用
本次实验设计了一个通用的链表模块,在调用时指定了具体的数据类型,体现了高类聚低耦合的思想,接口更加规范,使我们的代码更具有通用性并且更容易管理。
在实验中体会到了函数接口规范对于可重用的重要性,以及代码设计规范的一些方法。在编译的过程中也学习了链接的相关知识,对gcc编译器有了进一步的理解.