一.知識回顧
首先在我們宣告結構體的時候,有時候為了方便傳遞結構體,可以採用將結構體的變數進行指標賦值的方式進行
比如
struct student
;struct student stud;
//定義結構體普通變數
struct student *p;
//定義結構體指標變數,表明是同個型別
p=&stud;
那麼在後續的使用中可以採用這種方式
//指標變數名->成員變數名
//如上,p是指標變數名,裡面有id、name、score等成員變數名
p->id=lumxi;
//這樣就完成了這個賦值
//而且對於記憶體的分配是節約的
補充函式:
malloc&free
(1)malloc函式是向系統申請乙個長度為size的連續記憶體空間,函式的返回值是記憶體空間的起始位址,如果未能正常分配到記憶體空間,那麼將會返回null,函式用法
(
int*
)malloc
(xx)
//這裡代表的是(int*)表示的是所代表的資料型別
//xx內表示的是所需要的記憶體的大小
//注意需要多少是可以計算的
//比如int是四個位元組,那麼後面輸入的數字即為xx*4個記憶體大小
free函式
free函式是malloc的配套函式,每當我們申請到了一塊記憶體空間,那麼我們在使用完了這個資料之後,需要對這個申請到的記憶體空間進行釋放,以便我們大程式後續的執行
用法
free
(void
*p)//注意free的是乙個指標變數,用來指標那一塊連續的記憶體空間
(2)calloc&realloc函式
作用是向計算機申請分配n個長度為size的連續記憶體空間,函式的返回值是記憶體空間的起始位址。
void
*calloc
(unsigned
int n,
unsigned
int size)
;//用法與malloc類似的
realloc函式
作用是對malloc或者calloc申請到的空間進行重新分配,通常是為了改變原來申請記憶體空間的大小,引數p指向原來分配的空間,size表示重新分配的記憶體大小
void
*realloc
(void
*p,unsigned
int size)
;
上面四個函式的引數和返回值使用了"void *"指標型別,該指標型別的指標變數只儲存乙個純位址,即只表示記憶體位址的編號,而不表示位址的型別,void型別指標與其他型別指標相互賦值的時候,無需強制型別轉換,編譯器會自動進行轉換,但習慣上,void指標賦值給其他型別指標的時候,要使用對應的型別強制轉化
注:這裡搞清楚 *是取內容運算子,可以把後續的那個指標變數所對應的值拿出來用!同時也用在指明指標型別上.
二.鍊錶及其衍生概念
鍊錶:鍊錶是一種常見的資料結構,可以儲存多個同型別的資料,它是動態地進行儲存分配的一種資料結構,因此鍊錶沒有使用陣列時的限制,它可以隨著元素的變化而改變儲存空間,從而節約空間,而且根據malloc的特點,他所申請的記憶體可以是不連續的。
結點:結點是鍊錶的基本儲存單位,乙個幾點對應鍊錶中的乙個資料元素,所有的結點具有相同的資料結構,每個節點占用一段連續的記憶體空間,而結點之間可以使用指標鏈結在一起,使用指標乙個元素單位指向另外乙個元素單位,所以稱為鍊錶
資料域:存放資料的結點
指標域:用來存放下個結點的位址
一般形式如:
struct node
;
那麼在上面這種鍊錶的建立過程中,需要注意以下問題 :
(1)需要定義乙個指標變數指向第乙個結點,這個結點稱為頭結點,值得注意的是,第乙個指標可以為null,即空指標,亦或者是直接包含有乙個資料域
(2)除最後乙個結點外,其他結點的指標域指向下乙個指點
(3)最後乙個結點的指標域用來存放null,表示結束
(4)結點的資料域可以定義多個資料成員,即可以再次定義乙個結構
這種鍊錶結構稱為單向鍊錶結構,查詢只能按照順序操作.
三.鍊錶的基本操作(建立、插入與刪除、遍歷鍊錶)
(1)定義鍊錶結點的型別
程式中如果使用鍊錶,首先要定義描述鍊錶結點的結構體型別
struct product
;
(2)建立乙個鍊錶
node *
create()
//建立鍊錶
else
tail=p;
//指標的賦值,即tail繼續指向新的結尾點
printf
("請輸入商品的編號和**(如果輸入編號為0,那麼表示結束\n");
scanf
("%d%lf"
,&id,
&price);}
return head;
//返回值是鍊錶的頭指標
}
具體建表如上,在這裡進行註解說明
1.p指向鍊錶建立過程中新增加的結點
2.迴圈中每次建立乙個新結點並鏈結到鏈結尾部後,那麼tali就不再是尾結點,而需要讓tail指向新的尾結點
3.函式create在main中呼叫方法如下
node *head;
head=
create()
;
(3)鍊錶的遍歷
具體過程是指:從鍊錶的第乙個結點開始,依次對鍊錶中的每乙個結點進行一次訪問,直到鍊錶結束為止,遍歷鍊錶使用迴圈結構來實現,首先使指標p指向第乙個結點,通過p對結點進行訪問,訪問完成後,使指標p指向指向下乙個結點,如此不斷迴圈,直到鍊錶結束(p為null)
我們一般會進行如下操作:輸出結點的資料域、修改結點的資料域、對結點進行計數、對結點資料進行判斷.
輸出鍊錶所有結點的函式display
void
display
(node *h)
printf
("---------------------\n");
}
如下為display的實現總結
1.函式的引數h表示的是要輸出的鍊錶的頭指標
2.指標p指向第乙個結點
3.在main中呼叫的方法應該是display(head)
同理,我們可以實現鍊錶結點的統計
}
intcount
(node *h)
return n;
}
同理,在main中呼叫應該是count (head)
(4)在鍊錶中查詢結點
node *
search_for
(node *h,
int id)
return p;
}
使用方法為p=search_for(head,xx)
(5)鍊錶結點的插入
插入的演算法如下:
1.在鍊錶中找到插入點,這個插入點是相鄰結點中前面的結點,尋找插入點通常使用迴圈語句來實現。
在找到插入點後,使得指標p指向該結點,然後準備好插入的新結點c,使指標指向新結點
2.使得新結點c稱為結點b的前驅結點.
q->next=p->next;
3.將c變成a的後續結點
p->next=q;
node *
insert
(node *h,
int n,
int id,
double price)
p=h;
for(j=
0;j>next!=
null
;j++
)//迴圈找第n個結點
//迴圈結束後,如果有第n個結點,則p指向該結點,否則,指向最後乙個結點
//插入新結點s
s->next=p-
>next;
p->next=s;
return h;
}
在main中的呼叫方法:head=insert(head,5,1009,120.99)
(6)鍊錶結點的刪除
基本思路如:
1.在刪除結點之前,需要用迴圈結構找到被刪除的那個節點,找到後,用乙個指標q指向它,進行刪除操作時,不僅需要找到被刪除的是哪個結點,還要需要它的前驅結點是哪乙個結點,
2.把要刪除的結點,下面稱為結點b,把結點b拆解出來,只需要讓結點b的前驅結點a的指標域指向結點b的後續結點c即可。
p->next=q->next
b拆解了之後需要釋放記憶體
node *
del(node *h,
int n)
//下面分兩種不同情況進行結點的刪除
if(p==
null
)//沒有第n個結點,不刪除,直接返回原位址
else
if(p==h)
//要刪除的p指向第乙個結點
else
//要刪除的p指向其他結點,pre指向前驅節點
free
(p);
return h;
}
Lumxi的學習筆記 檔案部分
格式化的輸入和輸出 printf flags width prec hil type scanf flags type 註解 1.flags 其意思為標誌,可以加以下幾種字元 左對齊 在前面放個加號或者減號 space 正數留空 0 用0填充 2.width或prec number 最小字元數 下乙...
C語言程式設計 學習筆記 鍊錶
接可變陣列 但如果我們可以使用block,將其都拼接在一起,並不是用上面的方法複製貼上。每乙個block會有乙個單元指向的是下乙個block的位址,這樣就不會有上述的問題了 所以對於乙個單元,它裡面應該分成兩部分 1.資料 2.下乙個單元的位址 指標 這樣指向的下乙個資料結構也應是如此。直到最後乙個...
C語言學習筆記 鍊錶
鍊錶是一種常見的重要的資料結構。它是動態地進行儲存分配的一種結構。它可以根據需要開闢記憶體單元。鍊錶有乙個 頭指標 變數,以head表示,它存放乙個位址。該位址指向乙個元素。鍊錶中每乙個元素稱為 結點 每個結點都應包括兩個部分 一為使用者需要用的實際資料,二為下乙個結點的位址。因此,head指向第乙...