#include<stdio.h> #define false 0 #define ok 1 //定義節(jié)點(diǎn)的結(jié)構(gòu) typedef struct node{ int data; struct node *next; }node; typedef struct node *linklist; //初始化鏈表,創(chuàng)建一個(gè)鏈表并賦值 void creatlist(linklist *l,int n) { linklist p; (*l) = (linklist)malloc(sizeof(node)); (*l)->next = NULL; int i; for (i = 0; i < n; i++) { p= (linklist)malloc(sizeof(node)); p->data = i; p->next = (*l)->next; (*l)->next = p; } } //鏈表查詢 int getelem(linklist l, int i, int *e) { int k = 1; linklist p=NULL; p = l->next; while (p&&k<i) { p = p->next; k++; } if (!p || k>i) return false; *e = p->data; return ok; } //鏈表特定位置插入元素 int listinsert(linklist *l, int i, int e) { int k = 1; linklist s=NULL, p=NULL; p = *l; int j = 1; while (p&&j<i) { p = p->next; j++; } if (!p || k>i) return false; s = (linklist)malloc(sizeof(node)); s->data = e; s->next = p->next; p->next = s; return ok; } //鏈表特定位置刪除元素 int listdelete(linklist *l, int i, int *e) { int j = 1; linklist p=NULL, q=NULL; p = *l; while (p&&j<i) { p = p->next; j++; } if (!p->next || j>i) return false; q = p->next; p->next = q->next; *e = q->data; free(q); return ok; } //打印鏈表 int seelist(linklist l) { linklist p=NULL; p = l->next; int k = 0; while (p) { printf("%4d", p->data); p = p->next; k++; } if (k == 0) { printf("鏈表為空"); return false; } return ok; } //刪除整個(gè)鏈表 int clearlist(linklist *l) { linklist p = NULL,q=NULL; p = (*l)->next; while (p) { q = p->next; free(p); p = q; } (*l)->next = NULL; return ok; } int main(void) { int a; linklist lb; creatlist(&lb, 5); seelist(lb); listinsert(&lb, 2, 0); seelist(lb); listdelete(&lb, 2, &a); seelist(lb); clearlist(&lb); return 0; }
1、剛申請(qǐng)指針就要指向NULL;給指針初始化時(shí),如果不是規(guī)定它指向某個(gè)地址就要malloc申請(qǐng)空間;不用的指針要free。
2、typedef struct node linklist;這語(yǔ)句的含義是以后linklist就代表struct node 。這里的好處是編程更美觀簡(jiǎn)潔。畢竟要用到指向指針的指針,不用這個(gè)typedef等下就要出現(xiàn)**。
3、以上代碼頭指針指向了頭結(jié)點(diǎn),這個(gè)鏈表?yè)碛蓄^結(jié)點(diǎn),但是其實(shí)這種指向頭結(jié)點(diǎn)的頭指針可以不需要指向指針的指針
下面說明為什么可以不要使用指向指針的指針
頭指針是鏈表必須的元素,linklist p,這里定義了頭指針,頭指針通常代表該鏈表的名字,如果頭指針p就是頭結(jié)點(diǎn),含有data、next,直接對(duì)調(diào)用p做參數(shù),就可以更改p指向的結(jié)構(gòu)的值,不需要指向指針的指針
先看一段簡(jiǎn)單代碼:
#include<stdio.h> #include<stdlib.h> typedef struct node { int data; struct node *next; }node,*link; //初始化頭結(jié)點(diǎn),此時(shí)頭指針就是頭結(jié)點(diǎn) void init(link p) { p->data = 0; p->next = NULL; } //插入元素 void insrt(link p, int i,int a) { int j = 1; link b= (link)malloc(sizeof(node)); link c = p; while (j < i) { c = c->next; j++; } b->data = a; b->next = c->next; c->next = b; } //顯示鏈表 void seeq(link q) { link b = q->next; while (b != NULL) { printf("%d", b->data); b = b->next; } } void main() { int i; link l1 = (link)malloc(sizeof(node)); init(l1); for (i= 1; i < 5; i++) { insrt(l1, i, i); } seeq(l1); }
對(duì)段長(zhǎng)的代碼進(jìn)行改變也無需指向指針的指針,我們把所有的*l改成l,再把主函數(shù)里的&去掉
#include<stdio.h> #define false 0 #define ok 1 typedef struct node { int data; struct node *next; }node,*linklist; void creatlist(linklist l, int n) { linklist p; //去掉了l = (linklist)malloc(sizeof(node)); l->next = NULL; int i; for (i = 0; i < n; i++) { p = (linklist)malloc(sizeof(node)); p->data = i; p->next = l->next; l->next = p; } } int getelem(linklist l, int i, int *e) { int k = 1; linklist p = NULL; p = l->next; while (p&&k<i) { p = p->next; k++; } if (!p || k>i) return false; *e = p->data; return ok; } int listinsert(linklist l, int i, int e) { int k = 1; linklist s = NULL, p = NULL; p = l; int j = 1; while (p&&j<i) { p = p->next; j++; } if (!p || k>i) return false; s = (linklist)malloc(sizeof(node)); s->data = e; s->next = p->next; p->next = s; return ok; } int listdelete(linklist l, int i, int *e) { int j = 1; linklist p = NULL, q = NULL; p = l; while (p&&j<i) { p = p->next; j++; } if (!p->next || j>i) return false; q = p->next; p->next = q->next; *e = q->data; free(q); return ok; } int seelist(linklist l) { linklist p = NULL; p = l->next; int k = 0; while (p) { printf("%4d", p->data); p = p->next; k++; } if (k == 0) { printf("鏈表為空"); return false; } return ok; } int clearlist(linklist l) { linklist p = NULL, q = NULL; p = l->next; while (p) { q = p->next; free(p); p = q; } l->next = NULL; return ok; } int main(void) { int a; linklist lb = (linklist)malloc(sizeof(node));//這里有變動(dòng)! creatlist(lb, 5); seelist(lb); listinsert(lb, 2, 0); seelist(lb); listdelete(lb, 2, &a); seelist(lb); clearlist(lb); return 0; }
可以看到除了&和,還有兩處變動(dòng),就是把原本init函數(shù)內(nèi)的為指針申請(qǐng)空間改到了主函數(shù)內(nèi)一開始申明頭指針時(shí)就申請(qǐng)空間,否則會(huì)報(bào)錯(cuò):使用了未初始化的局部變量lb。這是因?yàn)椋瑒偵昝髦羔槙r(shí),即linklist lb,編譯器會(huì)為lb分配空間(32位系統(tǒng)4字節(jié),64位系統(tǒng)8字節(jié)),此時(shí)lb的地址是已知的,但是lb的值時(shí)不知道的(malloc時(shí)才會(huì)定下來lb的值)。如果函數(shù)調(diào)用不知道值的lb,是沒辦法調(diào)用的。而如果函數(shù)是調(diào)用lb的地址,因?yàn)閘b的地址是已知的,就可以調(diào)用了,可以在函數(shù)內(nèi)再為lb申請(qǐng)空間。即函數(shù)調(diào)用的參數(shù)一定是初始化值了的參數(shù)*
但是實(shí)際上,如果頭指針linklist p,p的值就是一個(gè)單純的指針,它的值就是個(gè)結(jié)點(diǎn)的地址。按照上面的方法,我們想在鏈表頭插入一個(gè)結(jié)點(diǎn)b,b的地址為xxx,p->next=地址xxx,此時(shí)就改變了個(gè)結(jié)點(diǎn)的next的值,即個(gè)結(jié)點(diǎn)指向地址xxx,即b變成了第二個(gè)結(jié)點(diǎn),沒辦法做到讓b變成個(gè)結(jié)點(diǎn)!所以需要改變p的值,讓p指向b,既然改變指針本身的值,而不是指針指向的對(duì)象的值,就需要用到指向指針的指針了。
想要了解更多的c++應(yīng)用技術(shù)那就加入我們吧!