目錄
一.相關指針知識點
二.鏈表
1.為什么學了順序表還要學鏈表
2.優點
三.實現
1.鏈表的打印 —— 理解鏈表結構
(2) 物理結構圖
2.鏈表的尾插 —— 入門
錯誤寫法:tail != NULL
總結:
正確代碼物理圖解:
(2) 尾插整體代碼?(思考對嗎?)
Bug
3.頭插
4.尾刪
Bug
5.頭刪
6.查找
7. Find 查找的功能
(1)pos 之前插入
(2)pos 位置刪除
(3)pos 之后插入
(4)pos位置后面刪除
?8.銷毀
?四.思維提升
五.總結
1.傳什么?
2.要不要斷言?
(1)打印、查找
(2)pphead
(3)*pphead
六.整體代碼
SList.h
SList.c
一.相關指針知識點
調用一個函數,就會建立一個空間,這個空間叫棧幀。局部變量是存放在棧幀里的(除了static修飾的局部變量)。函數結束,棧幀空間就銷毀,局部變量也銷毀
函數傳參,不管是傳值,還是傳地址,其實都是拷貝。就看拷貝值還是地址。
代碼1:y 的改變,不會改變 x 的值
void Func(int y)
{y = 1;
}
int main()
{int x = 0;Func(x);return 0;
}
這是兩個棧幀,Func 里面是 y,main 里面是 x。x 傳給 y 是拷貝給 y,y 的改變不會影響 x,并且 Func 會銷毀
代碼2:解決上面問題,傳地址。改變的是 int ,使用的是 int 的指針
void Func(int* p)
{*p = 1;
}
int main()
{int x = 0;Func(&x);return 0;
}
這里的 p 是 x 地址的拷貝。在傳參里面,我們要改變什么,就要用它的指針。然后 * 解引用可以改變
代碼3:
void Func(int* ptr)
{ptr = (int*)malloc(sizeof(int));
}
int main()
{int* px = NULL;Func(px);free(px); // 加上也沒用return 0;
}
這也是拷貝值,把 px 的值拷貝給 ptr,ptr 是空。但是我 malloc 了一塊空間,讓 ptr 指向這塊空間。
px 拷貝給 ptr,ptr 的改變不會影響 px 。并且出了作用域 Func 銷毀,malloc 的內存塊還找不到了(內存泄漏),就算 free 也 free 不到
這里我們要改變的是 int* ,不是 int 。傳 int* 不起作用。應該傳 int**(二級指針)
代碼4:改變 int* ,使用 int* 的地址,int**(二級指針)
void Func(int** pptr)
{*pptr = (int*)malloc(sizeof(int));
}
int main()
{int* px = NULL;Func(&px);free(px);return 0;
}
這里把 px 的地址傳過去,pptr 指向 px 。malloc了一塊空間,是讓 *pptr 即 px 指向這塊空間
Func 結束,棧幀銷毀。但 px 還指向這塊空間,free 可以 free 到。這里內存釋放,值也拿回來了
二.鏈表
1.為什么學了順序表還要學鏈表
順序表是有很多缺陷的:
(1)中間,頭部 插入,刪除數據,需要挪動數據,效率低下。你也不可能說在中間插入一塊空間,沒有這種概念,這本來就是一塊連續的空間。
(2)空間不夠需要擴容,拷貝數據,釋放舊空間。會有不小的消耗
擴容有一定的效率消耗。原地擴還好,異地擴呢?
還可能會有一定的空間浪費。一次擴太少,會頻繁擴;一次擴太多,浪費
能不能說,我用一點給一點呢?存一塊數據,開一塊空間
可以,但怎么管理呢?
順序表里,開了整片空間,由于存放的數據是連續的,只需要記錄這塊空間最開始的地址。
現在要一塊空間,去 malloc 。多次 malloc ,他們之間的地址不能保證相鄰。
這時候,鏈表會用一個指針指向第一個內存塊(節點 Node)。
為了通過第一個能找到第二個怎么辦?上一個會存下一個的地址,上一個指向下一個。
什么時候結束?順序表是 size 。鏈表里最后一個節點的指針存?NULL 即可
2.優點
不需要擴容。存一塊,開一塊。
可以從中間插入,不需要挪動數據。
順序表,鏈表是互補,相輔相成的。很多情況是配合起來使用的
三.實現
上面的理解,鏈表是一個個的內存塊,再由指針鏈接起來
先來定義它的結構:從語言的角度來說,凡是有多個數據,都要存到結構體里面
為方便替換成其他類型的數據,我們將類型統一重命名為 SLTDataType
1.鏈表的打印 —— 理解鏈表結構
SList.h
上一個節點要存下一個節點的地址,每個節點都是結構體類型,所以存結構體指針 next
鏈表要有個頭指針 phead 指向第一個節點,判斷結束只需要走到空 NULL 即可。
不能斷言 phead 為空,空鏈表也可以打印
typedef int SLTDataType;typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SLTNode;//打印鏈表
void SLTPrint(SLTNode* phead);
SList.c
void SLTPrint(SLTNode* phead)
{SLTNode* cur = phead;//while (cur->next != NULL) 錯誤寫法!!!//while(cur != NULL)while (cur){printf("%d->", cur->data);cur = cur->next; // 指向下一個位置// 不能寫成 ++cur;}printf("NULL\n");
}
問:為什么不能寫成 ++cur ?
答:鏈表地址不連續,++cur 不能保證它指向下一個位置。如果強行把地址弄成連續,不就成順序表了嗎?
怎么理解 cur = cur->next;
cur 是結構體指針,cur-> 就是訪問結構體成員。next 是結構體成員,是下一個節點的地址
賦值操作是把下一個節點的地址給 cur?
為什么循環判斷條件 cur->next != NULL 為錯?
cur->next 是下一節點地址。走到尾就結束了,沒有打印最后的數據
(2) 物理結構圖
上面畫的是邏輯結構圖,是為方便理解,形象畫出來的
物理結構圖:實實在在數據在內存中的變化
2.鏈表的尾插 —— 入門
依然不能斷言 phead 為空。為空(沒有數據)依然可以尾插
順序表尾插,先要判斷空間夠不夠,不夠擴容。? ? ? 鏈表不用,永遠有空間
第一步:搞個節點,并初始化。后面多次用到,分裝成函數
第二步:找尾。? 尾的特征:tail->next == NULL
// 搞節點,并初始化
SLTNode* BuySLTNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail");return NULL;}// 初始化newnode->data = x;newnode->next = NULL;return newnode;
}void SLTPushBack(SLTNode* phead, SLTDataType x) // 思考這里對嗎?
{SLTNode* newnode = BuySLTNode(x);// 找尾SLTNode* tail = phead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;
}
錯誤寫法:tail != NULL
// 找尾
SLTNode* tail = phead;
while (tail != NULL)
{tail = tail->next;
}
tail = newnode;
從邏輯結構圖角度,看似正確:
從物理結構圖理解:
tail ,newnode 都是局部變量,出了作用域銷毀
上一個節點沒有存下一個節點的地址,鏈接失敗
總結:
tail 是個局部變量。不應該賦值給 tail 。應該賦值給 tail 指向的結構體(存放下一個節點地址的)成員
不為空鏈表尾插的本質:原尾節點中要存新的尾節點的地址
正確代碼物理圖解:
// 找尾
SLTNode* tail = phead;
while (tail->next != NULL)
{tail = tail->next;
}
tail->next = newnode;
tail ,newnode 都是局部變量,出了作用域銷毀
上一個節點存儲下一個節點的地址,鏈接成功
(2) 空鏈表尾插
phead == NULL? ? ? tail = phead? ? ? ??讓 phead 指向新節點即可
(2) 尾插整體代碼?(思考對嗎?)
SList.h
typedef int SLTDataType;typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SLTNode;//打印鏈表
void SLTPrint(SLTNode* phead);
//尾插
void SLTPushBack(SLTNode* phead, SLTDataType x); // 思考這里對不對
SList.c?
void SLTPushBack(SLTNode* phead, SLTDataType x) // 對嗎?
{SLTNode* newnode = BuySLTNode(x);if (phead == NULL){phead = newnode;}else{// 找尾SLTNode* tail = phead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}
Test.c
void TestSList1()
{SLTNode* plist = NULL;SLTPushBack(plist, 1);SLTPushBack(plist, 2);SLTPushBack(plist, 3);SLTPushBack(plist, 4);SLTPrint(plist);
}
Bug
我們運行上面的代碼:
看下圖,phead 和 newnode 都是結構體指針類型的指針變量
phead = newnode 是賦值行為,其真正含義是讓 phead 也指向 newnode 指向的新節點
函數結束,棧幀空間銷毀。我們的目標是讓 plist 指向新節點,但最后沒有,造成了內存泄漏
改Bug
我們要改變 SLNode* plist ,傳參里要傳 SLNode* plist 的地址 ,用 SLNode** 接收
SList.h
typedef int SLTDataType;typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SLTNode;//打印鏈表
void SLTPrint(SLTNode* phead);
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
SList.c
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySLTNode(x);if (*pphead == NULL){*pphead = newnode;}else{// 找尾SLTNode* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}
pphead 存的是 plist 的指針。*pphead 就是 plist 。
函數結束,棧幀空間銷毀。plist 指向了新節點
鏈表運行結果:
3.頭插
盲猜頭插要用二級指針,因為一定有一個情況是為空,為空肯定要用
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySLTNode(x);newnode->next = *pphead;*pphead = newnode;
}
如果傳的是 phead ,改變的就是 phead ,無法改變外邊的 plist
這段代碼同樣可以解決空的情況
4.尾刪
SList.c
void SLTPopBack(SLTNode** pphead) // 這么寫對嗎?
{assert(pphead);assert(*pphead);// 找尾SLTNode* tail = *pphead;while (tail->next != NULL){tail = tail->next;}free(tail);tail = NULL;
}
Test.c
void TestSList1()
{SLTNode* plist = NULL;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);
}
Bug
? ? ?碰上這種情況多半是野指針,調試看看
尾就是1這個節點,2這個節點存著他的地址
直接把 tail 指向的尾節點 free 了,前一個節點的 next 就是野指針了。指向已經被釋放的空間的指針是野指針
這里把 tail 置空,不會把前一個節點的 next 置空
前一個節點是結構體,想改變結構體的內容要用結構體指針
修改1
void SLTPopBack(SLTNode** pphead)
{assert(pphead);assert(*pphead);SLTNode* prev = NULL;// 找尾SLTNode* tail = *pphead;while (tail->next != NULL){prev = tail;tail = tail->next;}free(tail);tail = NULL;prev->next = NULL;
}
修改2:找的是倒數第2個
void SLTPopBack(SLTNode** pphead)
{assert(pphead);assert(*pphead);// 找尾SLTNode* tail = *pphead;while (tail->next->next != NULL){tail = tail->next;}free(tail->next);tail->next = NULL;
}
如果鏈表刪到只剩1個元素,還刪。
如果鏈表本身為空
void TestSList1()
{SLTNode* plist = NULL;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);
}
? ? ? ? ? ? ??
下面用紅圈圈起來的是兩組代碼在只剩1個的情況下,分別有誤的地方
修改:只有1個節點,直接 free,plist 置空。不用找尾節點
所以尾刪如果用一級指針接收,phead 是 plist 的拷貝,對 phead 置空的改變不影響 plist,達不到置空 plist 的目的,plist 會變成野指針
void SLTPopBack(SLTNode** pphead)
{//暴力檢查assert(pphead);assert(*pphead);//溫柔檢查/*if (*pphead == NULL)return;*/if ((*pphead)->next == NULL) // 只有1個節點{free(*pphead);*pphead = NULL;}else // 多個節點{/*SLTNode* prev = NULL;// 找尾SLTNode* tail = *pphead;while (tail->next != NULL){prev = tail;tail = tail->next;}free(tail);tail = NULL;prev->next = NULL;*/// 找尾SLTNode* tail = *pphead;while (tail->next->next != NULL){tail = tail->next;}free(tail->next);tail->next = NULL;}
}
5.頭刪
不需要單獨處理只有1個節點的情況
void SLTPopFront(SLTNode** pphead)
{assert(pphead);assert(*pphead);SLTNode* first = *pphead;*pphead = first->next;free(first);first = NULL;
}
6.查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{SLTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}
返回的是對應節點的指針,可以用 Find 實現修改
void TestSList2()
{SLTNode* plist = NULL;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPrint(plist);// 值為2的節點 *2SLTNode* ret = SLTFind(plist, 2);ret->data *= 2;SLTPrint(plist);
}
Find 主要是與下面的功能相配合
7. Find 查找的功能
我們這里不傳下標,傳結構體指針,與 C++ 貼合
(1)pos 之前插入
為啥不是在 pos 位置插入? 是把 pos 及以后的數據往后移,所以邏輯上說是之前插入
單鏈表不適合 pos 之前插入,只適合在后面插入,因為要找到 pos 前一個節點的地址,只能從頭找
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{if (pos == *pphead){SLTPushFront(pphead, x);}else{// 找到 pos 的前一個位置SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}SLTNode* newnode = BuySLTNode(x);newnode->next = pos;prev->next = newnode;}
}
如果 pos 不是鏈表里的指針,while 循環停不下來,最終出現空指針
這種情況怎么辦 (甚至 pos 就是 NULL)?? ?
說明傳錯了,斷言,起碼可以排除 NULL
(2)pos 位置刪除
這里 *pphead 可以不斷言,pos 間接斷言了
pos 不為空,有節點,一定不為空鏈表
pos 位刪除,要找到前一個位置。pos 是頭,就是頭刪,先處理這個特殊情況
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(pos);assert(*pphead);if (*pphead == pos){SLTPopFront(pphead);}else{// 找到 pos 的前一個位置SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);// pos = NULL;}
}
pos = NULL 沒用,形參的修改不改變實參。要不要傳二級指針呢?不。
為保持和其他的一致性,通常由用的人考慮置空
void TestSList4()
{SLTNode* plist = NULL;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPrint(plist);SLTNode* ret = SLTFind(plist, 2);SLTErase(&plist, ret);ret = NULL;SLTPrint(plist);
}
(3)pos 之后插入
錯誤寫法:會造成死循環
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = BuySLTNode(x);pos->next = newnode;newnode->next = pos->next;
}
正確寫法:先改后面
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = BuySLTNode(x);newnode->next = pos->next;pos->next = newnode;
}
(4)pos位置后面刪除
法1:pos->next = pos->next->next;? 這里從右往左賦值? ? ?橙圈的內容丟了,所以要引入del
void SLTEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);SLTNode* del = pos->next;pos->next = pos->next->next;free(del);del = NULL;
}
法2:好理解
void SLTEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}
?8.銷毀
寫法1:一級指針
void SLTDestroy(SLTNode* phead); // SList.hvoid SLTDestroy(SLTNode* phead)
{SLTNode* cur = phead;while (cur){SLTNode* tmp = cur->next;free(cur);cur = tmp;}// phead = NULL;
}
phead?= NULL 沒用,形參的修改不改變實參。讓用的人置空
void TestSList4()
{SLTNode* plist = NULL;......SLTDestroy(plist);plist = NULL;
}
寫法2:二級指針? ? 自己置空
void SLTDestroy(SLTNode** pphead); // SList.hvoid SLTDestroy(SLTNode** pphead)
{assert(pphead);SLTNode* cur = *pphead;while (cur){SLTNode* tmp = cur->next;free(cur);cur = tmp;}*pphead = NULL;
}SLTDestroy(&plist); // Test.c
?四.思維提升
單鏈表給了 pos 沒給頭指針
(1)插入
(2)刪除
沒有前一個位置,就刪后一個。先換值,后刪。但是不能刪尾
五.總結
1.傳什么?
我們剛開始拿到鏈表,plist?是 NULL 。要插入新節點,要讓 plist 指向新節點,會改變 plist ,所以要傳指針的地址。
刪除時,總會刪到空,這時要將 plist 置為 NULL ,也改變 plist ,所以也傳指針的地址
如果不需要修改頭指針的鏈接,就傳一級指針
2.要不要斷言?
斷言可以排出明顯的錯誤,避免調試耗時。一定不能為空,就斷言
(1)打印、查找
問:是否要 assert 指針 phead 為空? (一級指針)
答:不要。空的 (沒有數據) 的鏈表,順序表都可以打印、查找。鏈表為空時,phead == NULL,斷言直接終止程序不合適。
順序表,鏈表結構不一樣,不能一概而論。
phead 是指向第一個存有數據的節點,鏈表為空時,phead == NULL
順序表的打印
void SLPrint(SL* ps)
{assert(ps);for (int i = 0; i < ps->size; ++i){printf("%d ", ps->a[i]);}printf("\n");
}
指針 ps 指向結構體 SL ,順序表的數據不是存儲在結構體上。而是存儲在結構體里的一個指針 a 指向的空間。即使順序表里沒有數據,ps 指向的結構體也是必須要有的。ps->a 是否為空也不重要,到底有沒有數據,取決于 ps->size 是否為 0
所以對順序表而言,指針就不能為空
總結:不要看到指針上來就斷言
(2)pphead
要,pphead 不能為空。為什么?
pphead 是 plist 的地址。plist 是指針變量,值有可能是空,地址一定不為空
(3)*pphead
*pphead 就是 plist ,是看是否為空 (二級指針)
要不要斷言 *pphead 取決于函數是否包容空鏈表的情況
先 assert ( pphead )? ?后 assert ( *pphead )? 如果反了,先 * ,再檢查,有啥用?
空鏈表能插入,不斷言;不能刪,要斷言。
六.整體代碼
SList.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int SLTDataType;typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SLTNode;void SLTPrint(SLTNode* phead); // 打印鏈表
void SLTPushBack(SLTNode** pphead, SLTDataType x); // 尾插
void SLTPushFront(SLTNode** pphead, SLTDataType x); // 頭插void SLTPopBack(SLTNode** pphead); // 尾刪
void SLTPopFront(SLTNode** pphead); // 頭刪SLTNode* SLTFind(SLTNode* phead, SLTDataType x); // 查找void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x); // pos之前插入
void SLTErase(SLTNode** pphead, SLTNode* pos); // pos位置刪除void SLTInsertAfter(SLTNode* pos, SLTDataType x); // pos之后插入
void SLTEraseAfter(SLTNode* pos); // pos位置后面刪除//void SLTDestroy(SLTNode* phead); // 鏈表銷毀
void SLTDestroy(SLTNode** pphead); // 鏈表銷毀
SList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"void SLTPrint(SLTNode* phead)
{SLTNode* cur = phead;//while (cur->next != NULL) 錯誤寫法!!!//while(cur != NULL)while (cur){printf("%d->", cur->data);cur = cur->next;//cur++; 錯誤寫法!!!}printf("NULL\n");
}// 搞新節點,并初始化
SLTNode* BuySLTNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail");return NULL;}// 初始化newnode->data = x;newnode->next = NULL;return newnode;
}void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySLTNode(x);if (*pphead == NULL){*pphead = newnode;}else{// 找尾SLTNode* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySLTNode(x);newnode->next = *pphead;*pphead = newnode;
}void SLTPopBack(SLTNode** pphead)
{//暴力檢查assert(pphead);assert(*pphead);//溫柔檢查/*if (*pphead == NULL)return;*/if ((*pphead)->next == NULL) // 只有1個節點{free(*pphead);*pphead = NULL;}else // 多個節點{/*SLTNode* prev = NULL;// 找尾SLTNode* tail = *pphead;while (tail->next != NULL){prev = tail;tail = tail->next;}free(tail);tail = NULL;prev->next = NULL;*/// 找尾SLTNode* tail = *pphead;while (tail->next->next != NULL){tail = tail->next;}free(tail->next);tail->next = NULL;}
}void SLTPopFront(SLTNode** pphead)
{assert(pphead);assert(*pphead);SLTNode* first = *pphead;*pphead = first->next;free(first);first = NULL;
}SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{SLTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);assert(pos);if (pos == *pphead){SLTPushFront(pphead, x);}else{// 找到 pos 的前一個位置SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}SLTNode* newnode = BuySLTNode(x);newnode->next = pos;prev->next = newnode;}
}void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(pos);assert(*pphead);if (*pphead == pos){SLTPopFront(pphead);}else{// 找到 pos 的前一個位置SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);// pos = NULL;}
}void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = BuySLTNode(x);newnode->next = pos->next;pos->next = newnode;
}void SLTEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);//SLTNode* del = pos->next;//pos->next = pos->next->next;//free(del);//del = NULL;SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}/*
void SLTDestroy(SLTNode* phead)
{SLTNode* cur = phead;while (cur){SLTNode* tmp = cur->next;free(cur);cur = tmp;}
}
*/void SLTDestroy(SLTNode** pphead)
{assert(pphead);SLTNode* cur = *pphead;while (cur){SLTNode* tmp = cur->next;free(cur);cur = tmp;}*pphead = NULL;
}
本篇的分享就到這里了,感謝觀看,如果對你有幫助,別忘了點贊+收藏+關注。
小編會以自己學習過程中遇到的問題為素材,持續為您推送文章