您的位置:首页 > 移动开发 > 微信开发

学习之路——用callback增强链表模块来实现命令行菜单小程序V2.8

2017-10-23 18:31 751 查看
【zhanghughsw + 《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006

本文为网易云课堂课程《软件工程(C编码实践)》的实验报告,本次实验为在前几次实验(命令行菜单小程序)的基础上,将使用可重用链表模块来实现内部模块化。

附上一实验的链接:用可重用的链表模块来实现命令行菜单小程序V2.5

一.实验思路

本次实验的目的是在前些实验的基础上使用callback增强链表模块,实验任务主要有以下3点:

1.找出视频中quit指令无法退出的原因,并修改

2.使用callback增强链表模块

3.隐藏结构体定义

首先解决任务1,出现quit指令失败的直接原因是由于查找失败造成了,为什么会查找失败,从下面截图中可以看到


用于遍历的循环——while的退出条件是 当前结点 != 尾结点,这样就导致了存在尾结点内的指令quit不能被访问,自然就无法实现quit功能,改写函数为



运行结果:



任务2、3在下面的报告中体现!

附小程序功能列表:

- time:获取当前的日期与时间

- calculation:进行加减乘除四则运算

- notepad :在当前文件夹创建并使用vim打开一个文本文档*.txt

- version:打印程序的版本号

- mac : 打开文件管理器nautilus

- explore :打开浏览器

- help :列出所有指令及解释

- help :列出所有指令及解释

二、代码实现

程序代码三个文件来进行代码编写,分别为menu.c linktable.c linktable.h

menu.c

在本文件中实现主函数的编写,主要功能是输入的cmd字符获取与匹配

void main()
{
InitMenuData(&head);
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;
}
if (strcmp(p->cmd, "help") != 0)
{
printf("%s - %s\n", p->cmd, p->desc);
}
if(p->handler != NULL)
{
p->handler();
}
}
}


本次实验menu.c文件中的主函数基本没有变化,变化的是在文件中修改了查找函数,以及添加了callback函数SearchCondition()

int SearchCondition(tLinkTableNode * pLinkTableNode, void * args)
{
char * cmd = (char*)args;
tDataNode * pNode = (tDataNode *)pLinkTableNode;
if(strcmp(pNode->cmd, cmd) == 0)
{
return SUCCESS;
}
return FAILURE;
}

tDataNode* FindCmd(tLinkTable * head,char * cmd)
{
return (tDataNode*)SearchLinkTableNode(head,SearchCondition,(void *)cmd);
}


自定义功能的存储方式如下:

int InitMenuData(tLinkTable ** ppLinktable)
{
*ppLinktable = CreateLinkTable();
tDataNode* pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "help";
pNode->desc = "Menu List:";
pNode->handler = Help;
AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "time";
pNode->desc = "You can use this cmd to get the localtime!";
pNode->handler = Time;
AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "caculation";
pNode->desc = "You can use this cmd to have a simple calculate";
pNode->handler = Calculation;
AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "notepad";
pNode->desc = "You can use this cmd to open a note file by vim";
pNode->handler = Notepad;
AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "version";
pNode->desc = "menu line v1.2 bu yiyu";
pNode->handler = NULL;
AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "mgc";
pNode->desc = "You can use this cmd to open the File System";
pNode->handler = Mgc;
AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "explore";
pNode->desc = "You can use this cmd to open the explore";
pNode->handler = Explore;
AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "quit";
pNode->desc = "Quit the menu";
pNode->handler = Quit;
AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

return 0;
};


linktable.h

本文件用于编写链表以及链表节点的数据结构以及声明在其上的一系列操作,本次实验在其中添加了新方法的声明:SearchLinkTableNode(),同时对结构体的内部结构进行了隐藏

SearchCondition()

#ifndef _LINK_TABLE_H_
#define _LINK_TABLE_H_

#include <pthread.h>

#define SUCESS 0
#define FAILURE (-1)

typedef struct LinkTableNode
{
struct LinkTableNOde * pNext;
}tLinkTableNode;

typedef struct LinkTable tLinkTable;

tLinkTable * CreateLinkTable();

int DeleteLinkTable(tLinkTable *pLinkTable);

int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);

int DelLinkTable(tLinkTable *pLinkTable,tLinkTableNode * pNode);

tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable);

tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);

tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable,int Condition(tLinkTableNode * pNode,void * args), void * args);
#endif


linktable.c

本文件具体定义了链表的各种操作以及指令所对应的操作,本次实验在其中加入了结构体的定义,以及优化修改了部分方法,添加了SearchLinkTableNode()的具体实现

定义结构体

typedef struct LinkTable
{
tLinkTableNode *pHead;
tLinkTableNode *pTail;
int SumOfNode;
pthread_mutex_t mutex;
};


CreateTable()——创建链表

tLinkTable * CreateLinkTable()
{
tLinkTable *pLinkTable = (tLinkTable*)malloc(sizeof(tLinkTable));
if(pLinkTable == NULL)
{
return NULL;
}

pLinkTable->pHead = NULL;
pLinkTable->pTail = NULL;
pLinkTable->SumOfNode = 0;
pthread_mutex_init(&(pLinkTable->mutex), NULL);
return pLinkTable;
}


AddLinkTableNode()——插入结点

int AddLinkTableNode(tLinkTable *pLinkTable, tLinkTableNode * pNode)
{
if(pLinkTable == NULL || pNode == NULL)
{
return FAILURE;
}
pNode->pNext = NULL;
pthread_mutex_lock(&(pLinkTable->mutex));
if (pLinkTable->pHead == NULL)
{
pLinkTable->pHead = pNode;
}
if(pLinkTable->pTail == NULL)
{
pLinkTable->pTail = pNode;
}
else
{
pLinkTable->pTail->pNext = pNode;
pLinkTable->pTail = pNode;
}
pLinkTable->SumOfNode += 1;
pthread_mutex_unlock(&(pLinkTable->mutex));
return SUCCESS;
}


GetLinkTableHead()——返回头结点

tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable)
{
if(pLinkTable == NULL)
{
return NULL;
}
return pLinkTable->pHead;
}


DelLinkTable()——删除链表

int DelLinkTable(tLinkTable *pLinkTable, tLinkTableNode * pNode)
{
if(pLinkTable == NULL || pNode == NULL)
{
return FAILURE;
}
pthread_mutex_lock(&(pLinkTable->mutex));
if(pLinkTable->pHead == pNode)
{
pLinkTable->pHead = pLinkTable->pHead->pNext;
pLinkTable->SumOfNode -= 1;
if(pLinkTable->SumOfNode == 0)
{
pLinkTable->pTail = NULL;
}
pthread_mutex_unlock(&(pLinkTable->mutex));
return SUCCESS;
}
tLinkTableNode * pTempNode = pLinkTable->pHead;
while(pTempNode != NULL)
{
if(pTempNode->pNext == pNode)
{
pTempNode->pNext = pTempNode->pNext->pNext;
pLinkTable->SumOfNode -= 1;
if(pLinkTable->SumOfNode == 0)
{
pLinkTable->pTail = NULL;
}
pthread_mutex_unlock(&(pLinkTable->mutex));
return SUCCESS;
}
pTempNode = pTempNode->pNext;
}
pthread_mutex_unlock(&(pLinkTable->mutex));
return FAILURE;
}


GetNextLinkTableNode()——返回下一节点

tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable, tLinkTableNode * pNode)
{
if(pLinkTable == NULL || pNode == NULL)
{
return NULL;
}
tLinkTableNode * pTempNode = pLinkTable->pHead;
while(pTempNode != NULL)
{
if(pTempNode == pNode)
{
return pTempNode->pNext;
}
pTempNode = pTempNode->pNext;
}
return NULL;
}


以及各项指令的功能函数

int Time()
{
time_t now;
struct tm *tm_now;
time(&now);
tm_now = localtime(&now);
printf("now datetime:%d-%d-%d %d:%d:%d\n", tm_now->tm_year + 1900, tm_now->tm_mon + 1, tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);
}

int Calculation()
{
char ch;
int num1, num2;
printf("which calculations: + - * /:");
scanf("%c", &ch);
while (1)
{
scanf("%c", &ch);
setbuf(stdin, NULL);
if (ch == 'Q')
{
return 1;
}
else if (ch != '+' && ch != '-' && ch != '*' && ch != '/')
{
printf("Input Wrong!please input the one of '+','-','*','/'\n");
}
else
{
printf("You want to have a %c calculate,input the two number,separate by comma!\n", ch);
break;
}
}
scanf("%d,%d", &num1, &num2);
if (ch == '+')
{
printf("%d+%d=%d\n", num1, num2, num1 + num2);
}
else if (ch == '-')
{
printf("%d-%d=%d\n", num1, num2, num1 - num2);
}
else if (ch == '*')
{
printf("%d*%d=%d\n", num1, num2, num1 * num2);
}
else if (ch == '/')
{
printf("%d/%d=%f\n", num1, num2, (float)num1 / num2);
}
else
{
printf("Input Wrong!");
return -1;
}
return 0;
}

int Quit()
{
exit(0);
}

int Notepad()
{
system("touch ./*.txt");
system("vim ./*.txt");
return 0;
}

int Mgc()
{
system("nautilus");
return 0;
}

int Explore()
{
system("firefox");
return 0;
}


运行结果:



三、实验总结

本次实验是收获巨大的,让我了解了使用callback方法来增强链表模块,同时在实验过程中,巩固了链表的相关知识,特别是链表的插入、遍历等方面的知识。

复审代码

通过如下命令可以从Git版本库中拉取代码并编译运行

git clone https://github.com/zhanghughsw/zswlab.git cd zswlab
cd lab5
gcc menu.c linktable.c -o menu
./menu


github:

https://github.com/zhanghughsw/zswlab
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐