【實驗報告】高軟實驗4

【Jerryykt1464929958440 + 《軟件工程(C編碼實踐篇)》MOOC課程作業http://mooc.study.163.com/course/USTC-1000002006 】

github地址:https://github.com/JerryLittleBear/experiment.git


【實驗目的】:


1、實現接口的定義(鏈表),提高代碼的可重用性,LinkTable.c文件可以在別的項目中使用。
2、引入鏈表結構,用鏈表數據結構存儲和操作的所有命令。
3、用callin方式調用命令函數。


我學到了】:


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進行版本控制。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章