【Jerryykt1464929958440 + 《軟件工程(C編碼實踐篇)》MOOC課程作業http://mooc.study.163.com/course/USTC-1000002006 】
github地址:https://github.com/JerryLittleBear/experiment.git
【實驗目的】:
【我學到了】:
1、強制類型轉換的應用
在menuV2.5.c文件(見【關鍵代碼】部分)的54和75行,調用LinkTable.c文件中的getLinkTableHead和 addLinkTableNode函數。而在這兩個函數的定義中,getLinkTableHead的返回值和addLinkTableNode型參中的數據類型都是LinkTableNode*類型,而我們在主函數中調用的,是CmdNode類型,所以此時要強制類型轉換,以便利用CmdNode結構體中的cmd和desc成員,用來儲存命令名和對命令的描述。
值得注意的是,我們不能對結構體變量強制類型轉換(佔用內存大小和格式都不同),但是可以對結構體指針強制類型轉換,在上述的例子中,都是對結構體指針操作的。
參考文獻:http://www.cnblogs.com/jaletech/archive/2013/10/23/3383430.html
2、debug過程中出現segment fault(段錯誤)
在寫代碼過程中,曾經把help函數(menuV2.5.c第126行)設計成viod help(LinkTable* lt);的形式,但是這樣在調用的時候,因爲主函數調用的函數指針(menuV2.5.c第47行,cn->funcPointer();)是沒有型參的,所以當系統執行到help函數體時,實參lt相當於是沒有賦值的指針,對他操作是非法的,所以出現來內存段錯誤。
參考文獻:http://www.cnblogs.com/panfeng412/archive/2011/11/06/2237857.html
3、malloc函數
malloc出來的堆空間不會隨着調用它的函數的結束的而被釋放,必須通過free釋放,即使是其他塊中調用它分配的內存,別的函數調用之後也必須free。
4、互斥鎖
pthread_mutex_t數據類型
參考文獻:http://blog.csdn.net/zmxiangde_88/article/details/7998458
【實驗環境】:
ubuntu16.04、git2.0、gcc4.9
【關鍵代碼】:
代碼分爲3個文件:cmdV2.5.c、linktable.c、linktable.h
1、cmdV2.5.c裏是主函數以及8個功能函數,還有一些諸如initMenuData、findCmd此類的調用鏈表來顯示菜單命令的功能函數。
2、linktable.c裏面主要是對鏈表數據結構及其操作的實現。
3、該頭文件主要提供接口,方便主函數調用linktable.c裏的鏈表
源代碼如下:
cmdV2.5.c
:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"linktable.h"
#define CMD_MAX_LEN 128
#define DESC_LEN 1024
#define CMD_NUM 10
typedef struct CmdNode
{
LinkTableNode* next;
char* cmd;
char* desc;
void (*funcPointer)();
}CmdNode;
void help();
void quit();
void version();
void knowAboutAuthor();
void saySth();
void talkToMe();
void goToToilet();
void minus();
void multiply();
CmdNode* findCmd(LinkTable* lt, char* cmd);
int initMenuData(LinkTable** lt);
void showAllCmd();
LinkTable* lt;//把存儲命令的鏈表定義爲全局變量會比較好
/*-----------------------------主函數-----------------------------*/
int main()
{
initMenuData(<);
CmdNode* cn;
while(1)
{
char cmd[CMD_MAX_LEN];
printf("Input a cmd number >> ");
scanf("%s", cmd);
getchar();
cn = findCmd(lt, cmd);
cn->funcPointer();
}
return 0;
}
/*-----------------------------在鏈表中尋找命令-----------------------------*/
CmdNode* findCmd(LinkTable* lt, char* cmd)
{
CmdNode* cn = (CmdNode*)((CmdNode* )getLinkTableHead(lt))->next;//類型轉換的應用。在這裏,先獲取lt->lHead,轉換爲CmdNode指針類型,再指向下一個結點,
while(cn != NULL)
{
if(!strcmp(cn->cmd, cmd))
{
return cn;
}
cn = (CmdNode* )getNextLinkTableNode(lt, (LinkTableNode* )cn);
}
return NULL;
}
/*-----------------------------將所有命令輸入鏈表-----------------------------*/
int initMenuData(LinkTable** lt)
{
*lt = createLinkTable();
CmdNode* cn = (CmdNode*)malloc(sizeof(CmdNode));
cn->cmd = "help";
cn->desc = "this is help command";
cn->funcPointer = help;
addLinkTableNode(*lt, (LinkTableNode*)cn);//強制類型轉換的應用
cn = (CmdNode*)malloc(sizeof(CmdNode));
cn->cmd = "knowauthor";
cn->desc = "know about author";
cn->funcPointer = knowAboutAuthor;
addLinkTableNode(*lt, (LinkTableNode*)cn);
cn = (CmdNode*)malloc(sizeof(CmdNode));
cn->cmd = "quit";
cn->desc = "quit program";
cn->funcPointer = quit;
addLinkTableNode(*lt, (LinkTableNode*)cn);
cn = (CmdNode*)malloc(sizeof(CmdNode));
cn->cmd = "version";
cn->desc = "show version of the program";
cn->funcPointer = version;
addLinkTableNode(*lt, (LinkTableNode*)cn);
cn = (CmdNode*)malloc(sizeof(CmdNode));
cn->cmd = "toilet";
cn->desc = "how to go to toilet";
cn->funcPointer = goToToilet;
addLinkTableNode(*lt, (LinkTableNode*)cn);
cn = (CmdNode*)malloc(sizeof(CmdNode));
cn->cmd = "minus";
cn->desc = "input two integer, minus them";
cn->funcPointer = minus;
addLinkTableNode(*lt, (LinkTableNode*)cn);
cn = (CmdNode*)malloc(sizeof(CmdNode));
cn->cmd = "multiply";
cn->desc = "input two integer, multiply them";
cn->funcPointer = multiply;
addLinkTableNode(*lt, (LinkTableNode*)cn);
return 0;
}
/*-----------------------------顯示所有命令及其描述-----------------------------*/
void showAllCmd(LinkTable* lt)
{
CmdNode* node = (CmdNode*)(lt->lHead->next);
while(node != NULL)
{
printf(" %s————%s\n", node->cmd, node->desc);
node = (CmdNode* )getNextLinkTableNode(lt, (LinkTableNode* )node);
}
}
/*-----------------------------"help"命令-----------------------------*/
void help()
{
printf("/*-----------------command list-----------------*/\n");
showAllCmd(lt);
printf("/*-----------------command list-----------------*/\n");
}
/*-----------------------------"quit"命令-----------------------------*/
void quit()
{
printf("now, quit the program\n");
exit(0);
}
/*-----------------------------"version"命令-----------------------------*/
void version()
{
printf("menu V2.5\n");
}
/*-----------------------------"knowauthor"命令-----------------------------*/
void knowAboutAuthor()
{
printf("his name is Jerry, he loves helen\n");
}
/*-----------------------------另一些自定義命令-----------------------------*/
void saySth()
{
int i;
char sentenceDuplicate[128];//using the lowCamel style to name a variable
printf("no matter what you say, I will repeat your sentence 3 times, lol!\n");
scanf("%s", sentenceDuplicate);
getchar();//吸收輸入緩衝區裏的回車符
for(i = 0;i < 3;i++)
{
printf("No.%d round repetition: %s\n", i, sentenceDuplicate);
}
}
void talkToMe()
{
char answer[20];
printf("question No.1: if you are a boy or girl?\n");
scanf("%s", answer);
getchar();
printf("this is a pretty %s.\n", answer);
}
void goToToilet()
{
printf("out of the door, turn left, is the toilet\n");
}
void minus()
{
int integer1, integer2;
printf("please input first integer:\\");
scanf("%d", &integer1);
getchar();
printf("please input second integer:\\");
scanf("%d", &integer2);
getchar();
printf("the resule is %d\n", integer1 - integer2);
}
void multiply()
{
int integer1, integer2;
printf("please input first integer:\\");
scanf("%d", &integer1);
getchar();
printf("please input second integer:\\");
scanf("%d", &integer2);
getchar();
printf("the resule is %d\n", integer1 * integer2);
}
linktable.c :
#include <malloc.h>
#include "linktable.h"
/*-----------------------------創建鏈表-----------------------------*/
LinkTable* createLinkTable()
{
LinkTable* ltTemp;
ltTemp = (LinkTable* )malloc(sizeof(LinkTable));
if(ltTemp == NULL)
{
return ;
}
ltTemp->lHead = (LinkTableNode* )malloc(sizeof(LinkTableNode));
if(ltTemp->lHead == NULL)
{
return ;
}
ltTemp->lTail = ltTemp->lHead;
ltTemp->lHead->next = NULL;
ltTemp->nodeNum = 0;
return ltTemp;
}
/*-----------------------------刪除鏈表-----------------------------*/
int deleteLinkTable(LinkTable* lt)
{
LinkTableNode* node, * tempNode;
node = lt->lHead;//node指向頭指針
while(node != NULL)
{
tempNode = node;
free(node);
node = tempNode->next;
}
free(lt);
return 0;
}
/*-----------------------------增加鏈表結點-----------------------------*/
int addLinkTableNode(LinkTable* lt, LinkTableNode* node)
{
lt->lTail->next = node;
lt->lTail = node;
lt->lTail->next = NULL;
(lt->nodeNum)++;
return 0;
}
/*-----------------------------刪除鏈表結點-----------------------------*/
int deleteLinkTableNode(LinkTable* lt, LinkTableNode* node)
{
LinkTableNode* n1, * n2;
n1 = lt->lHead;
n2 = lt->lHead->next;
while(n1->next != node && n1->next->next != NULL)
{
n1 = n1->next;
}
n2 = n1->next;
n1->next = n1->next->next;
free(n2);
return 0;
}
/*-----------------------------獲取鏈表頭指針-----------------------------*/
LinkTableNode* getLinkTableHead(LinkTable* lt)
{
return lt->lHead;
}
LinkTableNode* getNextLinkTableNode(LinkTable* lt, LinkTableNode* node)
{
return node->next;
}
linktable.h :
#ifndef __LINKTABLE_H__
#define __LINKTABLE_H__
#include <pthread.h>
//鏈表節點
typedef struct LinkTableNode
{
struct LinkTableNode* next;
}LinkTableNode;
//鏈表結構,含鏈表頭尾、長度等
typedef struct LinkTable
{
struct LinkTableNode* lHead;
struct LinkTableNode* lTail;
int nodeNum;
pthread_mutex_t mutex;//進程互斥鎖
}LinkTable;
LinkTable* createLinkTable();
int deleteLinkTable(LinkTable* lt);
int addLinkTableNode(LinkTable* lt, LinkTableNode* node);
int deleteLinkTableNode(LinkTable* lt, LinkTableNode* node);
LinkTableNode* getLinkTableHead(LinkTable* lt);
LinkTableNode* getNextLinkTableNode(LinkTable* lt, LinkTableNode* node);
#endif
【實驗流程】:
1、寫linktable.h的代碼,確定接口規範。
2、寫linktable.c的代碼,確定鏈表及其操作
3、寫menuV2.5.c的代碼,運用頭文件中的接口以及鏈表的操作
4、上傳到github進行版本控制。
【實驗截圖】:
1、程序編譯運行,help嵌套調用findCmd顯示命令列表,quit函數退出程序,還有一些功能函數。
2、上傳github進行版本控制。