寫鏈表想法的由來:
鏈表---重要的數據結構,工作了這麼長時間,再也沒有寫過鏈表,可能是由於工作中沒有使用的原因,也可能是我太懶了,還可能是因爲玩遊戲玩過頭了吧!總之我知道有鏈表,但是鏈表是什麼好想就天馬行空了,所以決定寫一下,哈哈,雖然我很菜,但是再菜我也要它跑起來,萬一哪天要用那麼一下子呢!好了廢話不多說,來滿足一下自己的小小的一個期望(它跑起來)。
特簡單的:
首先呢!先碼一個特別簡單的,主要是爲了先了解一下嘛!然後在一點點深入嘛!畢竟這麼長時間沒有寫過了,不是嘛?
#include <stdio.h> #include <stdlib.h> struct node { int number; struct node *next; }; typedef struct node Node; int main(void) { Node *head, *b, *c; head = (Node *)malloc(sizeof(Node)); b = (Node *)malloc(sizeof(Node)); c = (Node *)malloc(sizeof(Node)); b->number = 20; c->number = 30; head->next = b; b->next = c; while (head) { printf("---->%d", head->number); head = head->next; } printf("\n"); free(head); free(b); free(c); return 0; }
// 執行結果
[root@yuan misc]# gcc link_list.c
[root@yuan misc]# ./a.out
---->0---->20---->30
鏈表從表面的意思上就是鏈狀的表,就像一根線上繫了很多一樣的結,這些結就是我們定義的結構體,而鏈就是我們定義的結構體中的指針next。next中存放着下一個節點的地址,這樣我們就把所有的節點串聯了起來,就像我們上邊執行的結果一樣。其實就是指針將數據串聯。
稍微有點複雜的:
(我覺得上邊碼的那個並不算是真正意義上的鏈表,我們只是把三個結構體變量串聯了起來)寫一個稍微複雜點的鏈表:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 struct node { 6 char name[16]; 7 char number[16]; 8 // long long number; 9 struct node *next; 10 }; 11 12 typedef struct node Node; 13 14 Node *createList(int num) 15 { 16 Node *head = NULL; 17 Node *tmp = NULL; 18 Node *node = NULL; 19 int i = 0; 20 // int count = 0; 21 // long long tmpNum; 22 23 head = (Node *)malloc(sizeof(Node)); 24 if (!head) { 25 printf("malloc Node(head) error!\n"); 26 goto err; 27 } 28 29 head->next = NULL; 30 31 tmp = head; 32 33 for(i = 1; i <= num; i++) { 34 printf("create [%d] node!\n", i); 35 node = (Node *)malloc(sizeof(Node)); 36 if (!node) { 37 printf("malloc Node(node) error!\n"); 38 } 39 40 printf("Please enter your name :\n"); 41 scanf("%s", &node->name); 42 if (!node->name) { 43 printf("enter the name error! Please enter again!\n"); 44 goto err; 45 } 46 47 printf("Please enter yout number :\n"); 48 // scanf("%d", &node->number); 49 scanf("%s", &node->number); 50 if (strlen(node->number) != 11) { 51 printf("enter the number error! Please enter again!\n"); 52 goto err; 53 } 54 55 // tmpNum = node->number; 56 // while(tmpNum) { 57 // tmpNum /= 10; 58 // count++; 59 // } 60 61 // if (count != 10) { 62 // printf("enter the number error! Please enter again!\n"); 63 // goto err; 64 // } 65 66 tmp->next = node; 67 tmp = node; 68 } 69 node->next = NULL; 70 return head; 71 72 err: 73 return NULL; 74 } 75 76 void printList(Node *node) 77 { 78 Node *tmp = NULL; 79 80 tmp = node->next; 81 82 while(tmp) { 83 printf("name : %s, number : %s\n", tmp->name, tmp->number); 84 tmp = tmp->next; 85 } 86 } 87 88 void freeList(Node *node) 89 { 90 Node *tmp = NULL; 91 int i = 1; 92 93 tmp = node->next; 94 95 while(tmp) { 96 free(tmp); 97 printf("clean up [%d] node!\n", i); 98 tmp = tmp->next; 99 i++; 100 } 101 tmp = NULL; 102 103 free(node); 104 node = NULL; 105 106 printf("clear finish!\n"); 107 } 108 109 int main(void) 110 { 111 Node *node = NULL; 112 int num; 113 114 printf("Please enter the number of nodes int the link_list :\n"); 115 scanf("%d", &num); 116 node = createList(num); 117 printList(node); 118 freeList(node); 119 120 return 0; 121 }
// 執行結果
[root@localhost address_list]# ./a.out
Please enter the number of nodes int the link_list :
2
create [1] node!
Please enter your name :
test
Please enter your number :
12345678901
create [2] node!
Please enter your name :
test2
Please enter your number :
12345678902
name : test, number : 12345678901
name : test2, number : 12345678902
clean up [1] node!
clean up [2] node!
clear finish!
代碼中有部分注掉的,那部分是因爲數字長度的問題,我試了%ll,%l64d, %lld,%ld輸出的結果都不是期望值,所以就改用了字符串,這個問題有時間我在查一下吧!
逐句分析:
首先我們定義了一個結構體Node,結構體成員有三個,用來存儲一個人名和其對應的電話號碼(11位),next指針用來指向下一個節點;
在main函數中,先要輸入一個數字,來確定我們的鏈表的長度,然後創建鏈表,將其存儲的內容打印出來,最後釋放各個節點。
createList函數中:
生成一個頭節點,根據num確定需要生成節點的個數,並對其各個節點進行賦值。
createList函數中我們定義了三個結構體變量,一個是頭節點head,一個是節點node,還有一個臨時結構體變量tmp。我們將頭節點head賦值給中間變量tmp,然後分配一個新的節點node,將node賦值給中間變量tmp結構體成員變量中的next指針變量(也就是頭節點head結構體成員變量中的next指針變量),這樣頭節點就和新分配的節點node串聯起來了。其中有一句tmp = node,這句話表示將新生成的節點node賦值給了中間變量tmp,這樣做是爲了在下一次循環中中間變量tmp表示的是上一次分配的node節點,再次分配新的節點後和現在的中間變量tmp(也就是上一次分配的節點)串聯。描述的有點亂,仔細想一下也不是那麼亂。
當循環結束後,將最後分配的節點node結構體成員中的next指針變量指向NULL。
返回頭節點head。
printList函數中:
剛開始是這樣寫的:
void printList(Node *node) { while(node) { printf("name : %s, number : %s\n", node->name, node->number); node = node->next; } }
// 執行結果
[root@localhost address_list]# ./a.out
Please enter the number of nodes int the link_list :
2
create [1] node!
Please enter your name :
test
Please enter your number :
12345678901
create [2] node!
Please enter your name :
test2
Please enter your number :
12345678902
name : , number :
name : test, number : 12345678901
name : test2, number : 12345678902
clean up [1] node!
clean up [2] node!
clear finish!
從執行結果中可以看出,我們鏈表長度是2,但是在打印的出來的結果中去出現三個,只是因爲其中空的那個是頭節點。
freeList函數:
由於使用了malloc函數動態分配就需要free函數掉,防止內存泄漏,其中有一句tmp = NULL;這句是爲了防止野指針,但是NULL也是一個地址,只不過這個地址是確定的(void *)0;但是這句話加到循環裏就會出現問題,因爲在free掉tmp後這個指針還是存在的,可能就是野指針吧(這裏我不確定),但是這時的tmp確確實實是存在的,所以纔有了下面的操作。而當我們將tmp制空後,它的地址也就不存在了,我們在進行後邊的操作的時候就操作非法地址,就會出現段錯誤。
還需將頭節點free掉。