




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
1、C語言程序設計指針,林大 經(jīng)管學院 瞿華,指針,指針是啥? 指針基本運算 函數(shù)中的指針 指針與數(shù)組 指針與動態(tài)數(shù)組 指針與結(jié)構(gòu) 函數(shù)指針 指針數(shù)組與多重指針 實驗,一、指針是啥,什么是指針? 假設Z同學是我們班作業(yè)做得最好的同學,大家都喜歡參考他的作業(yè)。 Z=作業(yè)的標準答案 可以把Z看作是一個作業(yè)類型的普通變量 某天A同學找Z:“把作業(yè)借我參考一下?”周X回答:“標準答案在Y同學那里,你找他吧” Z=“標準答案在Y那里” 這時候Z相當于一個指向別人(Y)的鏈接, 他就變成了一個指針!,一、指針是啥,指針(Point)實際上就是一個鏈接! 指針變量中保存的內(nèi)容是一個內(nèi)存地址。 例: int y=
2、10; int *z= 指針z的內(nèi)容就是y所在的內(nèi)存地址。 “z,標準答案是多少?” z說:你去問y吧! y說:標準答案是10!,一、指針是啥,int y=10; int *z=,10,y,內(nèi)存地址1008,1008,z,內(nèi)存地址1004,z指向y,二、指針基本運算,要學好指針,必須熟練掌握指針相關的運算。(接下來會提問!)如: 指針的定義方法:在變量標識符前加* int *p,a,b; /定義了一個整型指針p和一個普通變量a /將30賦給p指向的內(nèi)存中 對于指針p,*p相當于一個普通變量! 見01points.c(使用調(diào)試單步執(zhí)行查看結(jié)果),2.1 ,?,a,內(nèi)存地址1008,?,b,內(nèi)存地
3、址1004,?,p,內(nèi)存地址1000,2.1 a=10;,?,a,內(nèi)存地址1008,?,b,內(nèi)存地址1004,?,p,內(nèi)存地址1000,2.1 a=10;,10,a,內(nèi)存地址1008,?,b,內(nèi)存地址1004,?,p,內(nèi)存地址1000,2.1 a=10; p=,10,a,內(nèi)存地址1008,?,b,內(nèi)存地址1004,?,p,內(nèi)存地址1000,2.1 a=10; p=,10,a,內(nèi)存地址1008,?,b,內(nèi)存地址1004,1000,p,內(nèi)存地址1000,2.1 a=10; p=,10,a,內(nèi)存地址1008,?,b,內(nèi)存地址1004,1000,p,內(nèi)存地址1000,2.1 a=10; p=,10,a
4、,內(nèi)存地址1008,10,b,內(nèi)存地址1004,1000,p,內(nèi)存地址1000,2.1 a=10; p=,10,a,內(nèi)存地址1008,10,b,內(nèi)存地址1004,1000,p,內(nèi)存地址1000,2.1 a=10; p=,20,a,內(nèi)存地址1008,10,b,內(nèi)存地址1004,1000,p,內(nèi)存地址1000,2.1 a=10; p=,20,a,內(nèi)存地址1008,10,b,內(nèi)存地址1004,1000,p,內(nèi)存地址1000,2.1 a=10; p=,21,a,內(nèi)存地址1008,10,b,內(nèi)存地址1004,1000,p,內(nèi)存地址1000,2.1 double *p2; sizeof(p1)和sizeo
5、f(p2)哪個大?為什么? 因為我們使用的是32位的gcc編譯器(dev-cpp自帶),所以每個指針的大小都是32位,即4個字節(jié)。 見04size.c,三、函數(shù)中的指針,折騰指針有啥用呢? 回憶一下函數(shù)的知識: 在函數(shù)中改變形式參數(shù)的值,會影響實際參數(shù)嗎?為什么? 見05swap_1.c 由于: 函數(shù)的形式參數(shù)實質(zhì)上是一個局部變量 函數(shù)執(zhí)行時先將實際參數(shù)的值賦給形式參數(shù) 所以在函數(shù)中改變形式參數(shù),不會影響實際參數(shù),三、函數(shù)中的指針,swap(i,t)就相當于: int a=i; int b=t; int temp=a; a=b; b=temp; 很顯然,i和t的值實際并未改變。,3.1 指針類
6、型參數(shù),可是我確實需要在函數(shù)中改變實參的值,怎么辦? 使用指針類型參數(shù),就可以解決這個問題。 見05swap_2.c 為什么? 在函數(shù)swap(int *p1,int *p2)中,p1和p2是兩個指針類型的形式參數(shù)。 注意,在函數(shù)中,p1和p2各自指向哪里有變化嗎? 變化的是*p1和*p2,即p1和p2指向的內(nèi)存地址中保存的數(shù)據(jù)!,3.1 指針類型參數(shù),swap( 很顯然,這樣是能交換i和t的內(nèi)容的。,3.1 指針類型參數(shù),使用指針參數(shù)的另外一個好處是節(jié)約??臻g。 見06stacksize.c。程序為什么會異常關閉? 由于函數(shù)調(diào)用時會為struct參數(shù)分配很大一塊內(nèi)存(1M字節(jié)),超過了棧的現(xiàn)
7、有空間大小,導致堆棧溢出。 見06stacksize_2.c,改用struct指針作為參數(shù)。 函數(shù)調(diào)用時只需要為指針參數(shù)分配一塊內(nèi)存(還記得一個指針占用多大空間嗎?),所以就不存在堆棧溢出問題了!,3.2 指針類型返回值,函數(shù)也可以返回指針類型的數(shù)據(jù)。 例:07pointreturn.c 思考:可以返回一個指向函數(shù)局部變量的指針嗎?為什么? 見08localpoint.c 因為函數(shù)執(zhí)行完畢后,其局部變量的生命就結(jié)束了!對應的內(nèi)存空間可能會被別的變量使用! Never ever返回指向函數(shù)局部變量的指針!,四、指針與數(shù)組,指針變量中保存的是地址。 也可以理解為,指針就是地址類型的變量。 數(shù)組實質(zhì)
8、上是地址類型的常量。 因此: 可以將數(shù)組地址賦給指針 也可以直接使用下標來訪問指針指向的數(shù)組地址。 同樣,可以使用*運算符來訪問數(shù)組的第一個元素 見09arraypoint.c,4.2數(shù)組元素訪問與指針,如果希望指針p指向a的第4個元素的地址,怎么辦? 方法1:使用 方法2:使用+運算符 p=a+3; 方法2寫起來更簡單,因此更常見。 思考:想得到字符串str從第3個字符開始的字串,怎么辦? 假設str為”12345678”,想得到”45678”。 見10substring.c,4.3 指針地址運算,指針(數(shù)組)可以與整數(shù)做加減運算,得到的是一個新的地址 假設p指向一個數(shù)組,那么: p+1指向
9、數(shù)組中的下一個元素。 p-1指向數(shù)組中的上一個元素。 p+4指向數(shù)組中的后面第4個元素 p-4指向數(shù)組中的前面第4個元素 p+令p指向數(shù)組中的下一個元素 p令p指向數(shù)組中的上一個元素 見11pointmath.c,4.3 指針地址運算,C語言中經(jīng)常利用地址運算來處理字符串 例:模擬實現(xiàn)strcpy函數(shù) 見例12strcpy.c 注意,該程序使用了多個技巧,請認真思考體會: 字符串以0結(jié)尾 C語言中將0作為邏輯假,非0作為邏輯真 指針算數(shù)+; 函數(shù)形參改變不影響實參,4.3 指針地址運算,在C語言中,兩個同類型的指針可以做減法。 要讓兩個指針的減法p2-p1產(chǎn)生有意義的結(jié)果,需要滿足下面兩個條件
10、: p2和p1指向同一個數(shù)組的不同元素 p2指向的元素與p1相同,或者在p1指向的元素之后 則p2-p1表示p2和p1之間差多少個元素,即p2指向的元素與p1指向的元素的下標之差 見13strlen.c,計算字符串長度,4.4 數(shù)組參數(shù)與指針,在函數(shù)定義中,將參數(shù)類型定義為指針或者定義為數(shù)組,效果都是一樣的 實際都是定義了一個指針類型的參數(shù)。 這是C語言的一個語法糖 /syntax sugar 同樣,也可以將數(shù)組作為實參傳遞給指針類型的形參 見例14arrayparam.c,4.5 字符串與指針,使用字符數(shù)組與字符指針,最大的區(qū)別在于C對它們的初始化的處理上。 例如: char str=“He
11、llo world!”; char s*=“Hello world!”; C會為str在棧上分配一塊13字節(jié)大小的內(nèi)存,并將“Hello world!”這13個字符拷貝到這塊內(nèi)存中。 相當于:char str13;strcpy(str,”Hello world!”); 而s只是在棧上分配了4字節(jié)大小的內(nèi)存,然后把“Hello world!”在程序的常量數(shù)據(jù)區(qū)中的地址保存在s中。,4.5 字符串與指針,由于程序的常量區(qū)是不可寫的,所以在程序中可以修改str的內(nèi)容,而修改s的內(nèi)容就會出錯! 見:15strchange.c,4.6 練習,已知: int a=0,1,2,3,4,5,6,7,8,9,1
12、0; int *p1=a,*p2=a+10,*p3; 求下列運算的結(jié)果:,(7)*(p1+3)+*(a+5) 8 (8)p14+a610 (9)p3=p1;p3+;*p31 (10)p3=a+6;p3-p1;6 (11)p1=a 0 (12)p2=p1 1,(1)p2-p1 10 (2)*(p1) 0 (3)p100 (4)*a0 (5)*(a+5)5 (6)*(p2-3)7,五、指針與動態(tài)數(shù)組,除了用作函數(shù)參數(shù)外,指針的另一個重要作用是用來實現(xiàn)動態(tài)內(nèi)存管理。 所謂動態(tài)內(nèi)存,就是指大小、生存期都由你的代碼自己來控制一塊內(nèi)存。 主要涉及兩個函數(shù),即malloc/表示內(nèi)存分配和free。/表示內(nèi)存
13、釋放 malloc:在堆(heap)中分配一塊指定大小的內(nèi)存 free:釋放之前由malloc分配的內(nèi)存。 堆的大小只受到操作系統(tǒng)尋址能力的限制(32位指針最大只能表示4G內(nèi)存) 動態(tài)內(nèi)存最常見的用途之一是實現(xiàn)動態(tài)數(shù)組。,五、指針與動態(tài)數(shù)組,普通數(shù)組主要有兩個缺陷: 數(shù)組的大小是程序編寫時決定的。為了保證數(shù)組的大小夠用,通常需要將數(shù)組定得很大,導致內(nèi)存的浪費。 數(shù)組的大小受到??臻g大小的限制。 使用動態(tài)數(shù)組就可以解決這些問題。 見17dynamicarray.c 注意:使用動態(tài)內(nèi)存分配時,一定要注意及時free不需要的內(nèi)存。否則就會造成內(nèi)存泄漏。,六、指針與結(jié)構(gòu),指針除了可以用于指向基本數(shù)據(jù)類
14、型的地址外,也可以指向結(jié)構(gòu)等自定義類型數(shù)據(jù)的地址。 結(jié)構(gòu)指針在使用上和普通類型指針沒有區(qū)別。 可以先用*取指針對應結(jié)構(gòu)的內(nèi)容,然后用.來訪問其成員,如(*p).name 但也可以直接使用-訪問結(jié)構(gòu)指針成員,這種用法更常見,如:p-name 例:見18structpoints.c,6.1 結(jié)構(gòu)指針與參數(shù),使用結(jié)構(gòu)指針來作為函數(shù)的形參是一種常見的函數(shù)定義方式。 好處: 利用結(jié)構(gòu)的成員,一次可以傳入多項數(shù)據(jù),從而簡化了函數(shù)的定義和調(diào)用 使用結(jié)構(gòu)指針做形參,可以在函數(shù)中修改結(jié)構(gòu)的成員 使用結(jié)構(gòu)指針做形參,可以減少函數(shù)調(diào)用時參數(shù)內(nèi)容復制的開銷。 后面我們會大量使用結(jié)構(gòu)指針來做形參!,6.2 鏈表,利用結(jié)
15、構(gòu)指針,可以實現(xiàn)一種重要的數(shù)據(jù)結(jié)構(gòu)鏈表。 使用動態(tài)數(shù)組,我們可以解決程序編寫時,不知道實際元素的數(shù)量導致的??臻g浪費問題。 但動態(tài)數(shù)組依然需要在為數(shù)組分配空間之前知道元素的數(shù)量! 如果在實際使用中,實際元素的數(shù)量是經(jīng)常動態(tài)變化的,那么動態(tài)數(shù)組依然會有內(nèi)存浪費的問題。,6.2 鏈表,數(shù)組還存在另一個缺點,就是刪除和插入元素的效率問題。 如果要將一個新元素插入到數(shù)組的第3個位置上,那么從3到最后的全部元素都必須向后移動一位 同樣,刪除元素需要將后面的全部元素向前移動一位 鏈表解決了數(shù)組的這些缺點。它也是一種常用的數(shù)據(jù)結(jié)構(gòu)。它的特點是: 能夠動態(tài)增加或減少元素 插入或刪除某個元素,只會影響和它相鄰的
16、兩個元素。 搞明白鏈表及其操作,指針就徹底學會了!,6.2 鏈表,鏈表(Chained List/Linked List)在形式上類似于現(xiàn)實中的鏈條: 由多個結(jié)點(node)組成 每個結(jié)點中除數(shù)據(jù)外,還包含一個指針,指向鏈表中的下一個結(jié)點。 通過指針,各結(jié)點依次連接成一個鏈表 我們利用圖形的形式來看一下鏈表,6.2 鏈表,哨兵,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,NULL,鏈表頭指針head,單向鏈表的基本形式,struct node int data; struct node* next; ;,6.2 鏈表,哨兵,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,NULL,鏈表頭指針head,指針
17、變量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /訪問數(shù)據(jù)p-data p=p-next; ,遍歷鏈表,6.2 鏈表,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,NULL,鏈表頭指針head,指針變量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /訪問數(shù)據(jù)p-data p=p-next; ,遍歷鏈表,哨兵,6.2 鏈表,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,NULL,鏈表頭指針
18、head,指針變量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /訪問數(shù)據(jù)p-data p=p-next; ,遍歷鏈表,哨兵,6.2 鏈表,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,NULL,鏈表頭指針head,指針變量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /訪問數(shù)據(jù)p-data p=p-next; ,遍歷鏈表,哨兵,6.2 鏈表,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,
19、NULL,鏈表頭指針head,指針變量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /訪問數(shù)據(jù)p-data p=p-next; ,遍歷鏈表,哨兵,6.2 鏈表,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,NULL,鏈表頭指針head,遍歷鏈表,指針變量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /訪問數(shù)據(jù)p-data p=p-next; ,NULL,哨兵,6.2 鏈表,哨兵,結(jié)點
20、1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,鏈表頭指針head,新節(jié)點,struct node int data; struct node* next; ;,先使用遍歷操作找到接點2; p2-next=p1-next;,插入新結(jié)點到結(jié)點2、3之間,指針變量p1,指針變量p2,NULL,NULL,6.2 鏈表,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,鏈表頭指針head,新節(jié)點,struct node int data; struct node* next; ;,先使用遍歷操作找到接點2; p2-next=p1-next; p1-next-p2;,插入新結(jié)點到結(jié)點2、3之間,指針變量p1,指針變量p2,N
21、ULL,哨兵,6.2 鏈表,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,鏈表頭指針head,新節(jié)點,struct node int data; struct node* next; ;,先使用遍歷操作找到接點2; p2-next=p1-next; p1-next-p2; 整理一下圖形,插入新結(jié)點到結(jié)點2、3之間,指針變量p1,指針變量p2,NULL,哨兵,6.2 鏈表,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,鏈表頭指針head,新節(jié)點,struct node int data; struct node* next; ;,先使用遍歷操作找到接點2; p2-next=p1-next; p1-next-
22、p2; 整理一下圖形,插入新結(jié)點到結(jié)點2、3之間,NULL,哨兵,6.2 鏈表,哨兵,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,NULL,鏈表頭指針head,指針變量p1,struct node int data; struct node* next; ;,令p1指向結(jié)點1,p2指向結(jié)點2 p1-next=p2-next;,刪除結(jié)點2,指針變量p2,6.2 鏈表,結(jié)點1,結(jié)點2,結(jié)點3,結(jié)點4,結(jié)點5,NULL,鏈表頭指針head,指針變量p1,struct node int data; struct node* next; ;,令p1指向結(jié)點1,p2指向結(jié)點2 p1-next=p2-next;
23、 整理圖形,刪除結(jié)點2,指針變量p2,哨兵,6.2 鏈表,結(jié)點1,結(jié)點3,結(jié)點4,結(jié)點5,NULL,鏈表頭指針head,struct node int data; struct node* next; ;,令p1指向結(jié)點1,p2指向結(jié)點2 p1-next=p2-next;,刪除結(jié)點2,哨兵,6.2 鏈表,在單向鏈表的基礎上,還可以進一步實現(xiàn)雙向鏈表、循環(huán)鏈表等更復雜的數(shù)據(jù)結(jié)構(gòu)。 例:輸入學生信息,學號為0時結(jié)束輸入。保存并輸出按照學號排序的信息。然后用戶每輸入一個名字,從存儲中刪除對應的信息,直到用戶輸入回車或存儲為空為止。 分析: 使用鏈表保存學生信息 每輸入一個學生信息,動態(tài)建立一個結(jié)點,并插入到合適的位置 最后使用遍歷操作來輸出學生信息 例:19studentlink.c,七、函數(shù)指針,指針實質(zhì)上是一個內(nèi)存地址。這個地址不但可以是數(shù)據(jù)的存放地址,也可以是一段代碼的地址。 函數(shù)指針就是一個指向函數(shù)地址的指針,即指向代碼的指針。 函數(shù)指針的定義及使用見20funcpoints.c 利用函數(shù)指針,可以實現(xiàn)很多非常強大的功能。,7.1 函數(shù)指針做參數(shù),使用函數(shù)指針做函數(shù)的參數(shù),可以用一個函數(shù)實現(xiàn)多個功能 例:學生信
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 醫(yī)用設備捐贈管理辦法
- 供暖供水考核管理辦法
- 新質(zhì)生產(chǎn)力對電商創(chuàng)新生態(tài)系統(tǒng)的影響及發(fā)展策略
- 小學描寫人物作文寫作指導
- 綠色教育校本課程開發(fā)與實施
- 施工方案:道路與地坪拆除工程
- 智能預測系統(tǒng)在化纖生產(chǎn)中的應用-洞察及研究
- 培訓機構(gòu)聘用管理辦法
- 探索和完善科研過程中的容錯機制以促進創(chuàng)新活力的策略研究
- 供暖企業(yè)熱源管理辦法
- 2025年天津市中考語文試卷(含標準答案)
- 保險品質(zhì)管理制度
- 2025年遼寧高考地理試卷真題答案詳解講評課件(黑龍江吉林內(nèi)蒙古適用)
- 全國中小學教師職業(yè)道德知識競賽80題及答案
- 2023CSCO食管癌診療指南
- 2024年四川省資中縣事業(yè)單位公開招聘教師崗筆試題帶答案
- 成人女性壓力性尿失禁護理干預護理團標解讀
- 某律師事務所內(nèi)部規(guī)章管理制度大全
- GB 29743.2-2025機動車冷卻液第2部分:電動汽車冷卻液
- 急性右心衰的治療與護理
- 制約理論(TOC)驅(qū)動制造業(yè)突破性增長
評論
0/150
提交評論