標籤:傳遞 location length word odi 清空 linux 存在 scanf
下面以一個電子英漢詞典程式(以下簡稱電子詞典)為例,應用雙向迴圈鏈表。分離資料結構,可以使邏輯代碼獨立於資料結構作業碼,程式結構更清晰,代碼更簡潔;電子詞典的增、刪、查、改操作分別對應於鏈表的插入、刪除、尋找、尋找和擷取鏈表元素操作。
在程式初始化時,除了初始化鏈表,還要將儲存在檔案中的詞庫載入到鏈表中:
1 void dict_init() {2 list = linkedlist_new();3 4 dict_load();5 printf("Welcome.");6 }
函數dict_load()實現如下:
1 static void dict_load() { 2 FILE * fp; 3 struct Word word; 4 5 while (!(fp = fopen(PATH, "rb"))) { 6 fp = fopen(PATH, "wb"); 7 fclose(fp); 8 } 9 assert(fp);10 11 fread(&word, sizeof(struct Word), 1, fp);12 while (!feof(fp)) {13 linkedlist_insert(list, TRAVELDIR_BACKWARD, 1, word);14 fread(&word, sizeof(struct Word), 1, fp);15 }16 17 fclose(fp);18 }
函數feof()應先讀後判斷,所以在進入迴圈之前應先讀一次。
當然,在程式結束前,也要將鏈表中的片語儲存到檔案中,函數dict_store()實現如下:
1 static void dict_store() { 2 FILE * fp; 3 const int count = linkedlist_length(list); 4 5 assert(fp = fopen(PATH, "wb")); 6 for (int i = 0; i < count; i++) { 7 fwrite(linkedlist_get(list, TRAVELDIR_FORWARD, i + 1), 8 sizeof(struct Word), 1, fp); 9 }10 11 fclose(fp);12 }
一個英漢片語包含一個英文,一個中文,可以把它定義為一個結構體,並讓它作為鏈表節點資料域的資料類型;修改linkedlist.h中LinkedlistData的相關定義:
1 typedef struct Word {2 string eng;3 string chn;4 } LinkedListData;
C語言中沒有string類型,可以使用定長的字元數組來定義它;再定義一個函數mygets()用來代替scanf()函數,以確保輸入的內容不會超出緩衝區:
1 #define MAX_STR_LEN 8 2 typedef char string[MAX_STR_LEN]; 3 4 void mygets(char * s) 5 { 6 __fpurge(stdin); 7 fgets(s, MAX_STR_LEN, stdin); 8 while (*s++) { 9 *s = *s == ‘\n‘ ? 0 : *s;10 }11 }
在Linux下,使用__fpurge()函數來代替Windows下的fflush()函數清空輸入資料流。
接下來就是電子詞典的增、刪、查、改操作:
1 void dict_add(const char * eng) { 2 struct Word word; 3 strcpy(word.eng, eng); 4 5 printf("The word does not exist, add it?\ny/n>"); 6 if (__fpurge(stdin), getchar() == ‘y‘) { 7 printf("Ok, what does it mean?\n>"); 8 mygets(word.chn); 9 10 linkedlist_insert(list, TRAVELDIR_BACKWARD, 1, word);11 printf("The word is existed now.\n");12 }13 }14 15 void dict_delete() {16 int location;17 struct Word word;18 19 printf("What word do you wanna delete?\n>");20 mygets(word.eng);21 22 if ((location = linkedlist_locate(list, TRAVELDIR_FORWARD, word, dict_cmp))23 != -1) { // found24 struct Word * pWord = linkedlist_get(list, TRAVELDIR_FORWARD, location);25 26 printf("Delete: %s %s\nAre you sure?\ny/n>", pWord->eng, pWord->chn);27 if (__fpurge(stdin), getchar() == ‘y‘) {28 linkedlist_delete(list, TRAVELDIR_FORWARD, location);29 printf("The word is deleted now.\n");30 }31 } else { // not found32 printf("The word does not exist.\n");33 }34 }35 36 void dict_search(const char * eng) {37 int location;38 struct Word word;39 strcpy(word.eng, eng);40 41 if ((location = linkedlist_locate(list, TRAVELDIR_FORWARD, word, dict_cmp))42 == -1) { // not found43 dict_add(eng);44 } else { // found45 printf("%s\n", linkedlist_get(list, TRAVELDIR_FORWARD, location)->chn);46 }47 }48 49 void dict_modify() {50 int location;51 struct Word word;52 53 printf("What word do you wanna modify?\n>");54 mygets(word.eng);55 56 if ((location = linkedlist_locate(list, TRAVELDIR_FORWARD, word, dict_cmp))57 != -1) { // found58 struct Word * pWord = linkedlist_get(list, TRAVELDIR_FORWARD, location);59 60 printf("Ok, what does it mean?\n>");61 mygets(pWord->chn);62 printf("The word is modified now.\n");63 } else { // not found64 printf("The word does not exist.\n");65 }66 }
dict_cmp()函數作為參數傳遞給linkedlist_locate()函數,用以比較片語是否相同,相同則返回0,它的實現如下:
1 int dict_cmp(const void * s1, const void * s2) {2 return strcmp(((LinkedListData *) s1)->eng, ((LinkedListData *) s2)->eng);3 }
還需要一個函數來組織這些子函數的調用:
1 void dict_show() { 2 while (1) { 3 string str; 4 printf("\n>"); 5 mygets(str); 6 7 if (!strcmp(str, "quit;")) { 8 dict_store(); 9 linkedlist_destory(&list);10 printf("Bye.\n");11 return;12 } else if (!strcmp(str, "delete;")) {13 dict_delete();14 } else if (!strcmp(str, "modify;")) {15 dict_modify();16 } else {17 dict_search(str);18 }19 }20 }
最後,編寫主函數,電子詞典就大功告成了!
雙向迴圈鏈表(C語言描述)(四)