第三十講正確的List指針版_第1頁
第三十講正確的List指針版_第2頁
第三十講正確的List指針版_第3頁
第三十講正確的List指針版_第4頁
第三十講正確的List指針版_第5頁
已閱讀5頁,還剩7頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、第三十講 正確的 List (指針版)昨天我們完成了一個數組版的 List ,但是因為數組的限 制,導致那個實現不能收放自如,為了解決這個問題,我們 引入指針版本的 List ,我們還是先來看看接口:/my_list.h#ifndef _MY_LIST_H_#define _MY_LIST_H_typedef struct TelPhone char Name20;char TelNumber20;iTem;/*typedef struct nodeiTem item; node* next;Node;*/struct listiTem item; list* next;typedef lis

2、t* List;void InitializeList (List * plist); bool ListIsEmpty (const List * plist);bool ListisFull (const List * plist); unsigned int ListItemCount (const List * plist);bool AddItem (iTem item, List *plist); void ShowListItem(const List *plist); void FreetheList (List *plist);#endif大家應該注意到了,接口還是我們熟悉的

3、接口,我 們只是稍微把聲明新類型的時候稍作了下修改,所以對于這 個接口,我們就不多說,如果還有不了解的可以回頭去看看 第二十七講我們關于接口的聲明的那一章,不過雖然說沒啥 好說,有一點還是值得給大家提一提: typedef list* List; 大家可能會覺得奇怪,為什么會是這樣的呢?如果這樣取個外號,那么我們 下面的 List* 想要表達的豈不是 list * 了嗎?是啊,我們要的 就是這種效果,指針的指針,指針的指針很多時候又可以用 來表示二維數組: intanm;/ 二維數組 int *a;/ 指針的指針 上面這兩種聲明方式 在特定的情況下是可以相互表示。如果說大家能夠很好的理 解這個

4、,那么對于我們的 List* 是不是也很好的理解呢? List*plist 等價于 list* plist ,可以這么來理解, plist 是一個指 向 list 指針的指針,既是 *plist 的指針,而 *plist 是指向 list 的指針,就是我們需要的指針,這樣聲明的好處是我們很容讓 *plist 成為一個空殼,也就是好初始化。說到這里,有人 會問,既然是一個指向指針的指針,我們可不可以這么來聲 明呢: typedef struct TelPhonechar Name20;char TelNumber20;iTem;typedef struct nodeiTem item; node

5、* next;Node;struct listNode *head;list* next; 這樣我們同樣可以用下面的方式去初始化:*(plist->head) =NULL; 這看上去似乎是沒錯的,而且還可以瞞天過海,當然瞞的是編譯器, 所以如果這樣寫,編譯不報錯,但是運行時報錯了,這是為 什么呢?這個問題大概只有大家學完C+ 的動態類型識別的時候才會得到答案,不過這可能會是很久以后的事?,F在我 們回到正題上來,既然我們不能這樣寫,那么我們還是規規 矩矩的這樣初始化: *plist =NULL ;那么 *plist 表示什么呢?我們只知道他是一個指向 list 的指針,里面包含了我 們需要

6、iTem和next,但是我們可能有些朋友并不知道他實 際上就我們要實現的 list 的首地址,所以這就是指針的方便 之處,我們得到了一塊內存的指針便得到了這塊內存的起始 處,這個地址對我們來說極為重要,當然不只是我們,是所 有想要使用指針的程序員來說都很重要。該說的理論大概都說了,如果還有不懂還有懵懂的,可以看下我們的 接口的具體實現,如果發現確實還不懂的話可以直接提問, 我想今天這是我們 C 語言的最后一講了, 接下來我們該說說 C+或是Win32編程的知識了。/my_list.c#include#include#include 'my_list.h'/ 全局函數,把元素添加

7、進列表 static void CopyToNode(list *plist,iTem item) plist->item = item;/ 初始化void InitializeList(List *plist)plist = NULL;/確認列表是否為空bool ListIsEmpty(const List* plist)if(*plist = NULL)return true;return false;/確認列表是否已滿bool ListisFull(const List* plist)plist = (List*)malloc(sizeof(List); if(plist = NU

8、LL)return true;elsereturn false;/返回元素個數unsigned int ListItemCount(const List *plist)unsigned int count = 0; list* pNode = *plist; while(pNode != NULL)count+;pNode = pNode->next;return count;/添加元素,由于我們實現的是單向鏈表,所以使用從尾部 添加bool AddItem (iTem item, List* plist)list *pNew;list *pNode = *plist;pNew = (l

9、ist*)malloc(sizeof(list); if(pNew = NULL)return false;CopyToNode(pNew,item); pNew->next = NULL;if(pNode = NULL)*plist = pNew;elsewhile(pNode->next != NULL)pNode = pNode->next;pNode->next = pNew;return true;/ 顯示列表中的元素void ShowListItem(const List *plist)list* pNode = *plist;while(pNode !=

10、NULL)printf('%-10s : %sn',pNode->item.Name,pNode->item.TelNumber);pNode = pNode->next;/ 釋放內存 void FreetheList (List *plist)list* pNode = *plist,*pSave; while(pNode != NULL) pSave = pNode->next;free(pNode);pNode = pSave; 接口的實現 和我們有問題的實現看上去差不多,大家可以嘗試回頭去看 看第二十八講里面的實現,再來對比一下我們今天的實現,

11、看看問題出在那里,我們在二十八講里面是怎么瞞過大家雙 眼的,如果大家能夠把這個地雷挖出來, C 語言也算差不多 了,至少在指針一塊有所理解了。下面我們還是用同一個驅動函數來測試:/ListTest.c#include#include#include 'my_list.h'int main()List BookPhone ;iTem TempPhone;unsigned int count;/使用初始化接口InitializeList(&BookPhone);if(!ListIsEmpty(&BookPhone)exit(1);printf(' 請輸入聯系

12、人的姓名: n');while(gets_s(TempPhone.Name) != NULL&&TempPhone.Name0 != '0')printf(' 請輸入聯系人的電話號碼: n');gets_s(TempPhone.TelNumber);if(ListisFull(&BookPhone)printf(' 內存已滿,請退出! ');exit(1);/使用添加元素接口if(!AddItem(TempPhone,&BookPhone)printf(' 聯系人添加失?。?! '); br

13、eak;while(getchar() != 'n')continue;printf(' 若還要儲存,請輸入下一個聯系 人(空行退出) :n');/接下來我們該顯示我們通信錄里面的聯系人 信息了/使用判斷狀態接口 if(ListIsEmpty(&BookPhone) printf(' 通信錄沒有數據! ! ');elseprintf(' 通信錄: n');ShowListItem(&BookPhone);/使用聯系人數量接口count = ListItemCount(&BookPhone); printf(

14、' 聯系人數目: %dn',count); /釋放內存FreetheList(&BookPhone);return 0; 現在我們來思 考這次實踐的問題, 在這次實踐中, 我們雖然反轉糾結多次, 但是我們卻沒有修改過驅動函數(也就是mian),而且接口我們也沒有修改,我們所動到的知識類型的聲明和接口的實 現,而我們的 mian 函數卻不關心我們的接口是怎么實現的, 他只知道調用就好,至于怎么實現的與他無關,我們可以任 意修改,而不影響 main 的運行,現在是不是發現這種做法 很有用呢?是啊,我們只要實現一類接口,以后當我們想要 實現這些功能的時候就無需在一步步的寫代碼

15、,我們直接把 我們的頭文件添加進去就可以拉出就用,而且通常情況下我 們這類接口是可以通用的,如果我們不想要電話薄,我們想 要其他的,我們只需要把頭文件里面的 iTem 結構修改成我 們想要就好, 而不會影響到我們接口, 大家可以回頭去瞧瞧, 除了顯示元素那個接口會受到影響外其他的毫無問題,當 然,為了通用型,我們可以重新寫個顯示元素的接口: void ShowListiTem (const List * plist, void (* pfun) (iTem item); 這個接口看起來有些復雜(對于初學者來說) ,不過不難理解,后面的 void(*pfun)(iTem item) 是一個函數,

16、以 iTem 類型為參數的函 數, *pfun 是函數指針,也就是代表一個函數名,就好比,我們有個打印函數叫; voidShow(iTem item); 于是 我們就可以這樣調用上面的接口:ShowListiTem (&BookPhone,Show); 所以,這個接口的意思就是讓一個函數作用于我們的 List ,于是這 個接口就變得和類型無關,變得通用。對于這個接口,我們 可以這樣來實現: voidShowListiTem(const List * plist, void (* pfun)(iTem item) list * pnode = *plist;while(pnode != NULL)(* pfun) (pnode->item);pnode = pnode->next; 于是我們在我們的 main 函數后寫個 Show 函數來給這個接口使用: void Show(iTem item)printf('%-10s : %sn', item.Name,item.TelNumber); 這個 Show 函數可以根據我們需要的類型而 修改,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論