1 / 36

指標 (Pointer)

Introduction to the C Programming Language. 指標 (Pointer). 指 標 (Pointer). 指標概述 指標的宣告與定義 指標與函數 指標與陣列 指向指標的指標 — 雙 重指標. 為什麼要用指標 ?. 可使函數在傳遞陣列或字串時更有效率。 較複雜的資料結構須要指標才能將資料串在一起。 Ex. Linked list, binary tree. 有些函數必須利用指標來傳達記憶體的訊息。 malloc( ): 記憶體配置函數 fopen( ): 檔案開啟函數.

bunny
Download Presentation

指標 (Pointer)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Introduction to the C Programming Language 指標 (Pointer)

  2. 指 標 (Pointer) • 指標概述 • 指標的宣告與定義 • 指標與函數 • 指標與陣列 • 指向指標的指標—雙重指標

  3. 為什麼要用指標? • 可使函數在傳遞陣列或字串時更有效率。 • 較複雜的資料結構須要指標才能將資料串在一起。 • Ex. Linked list, binary tree. • 有些函數必須利用指標來傳達記憶體的訊息。 • malloc( ):記憶體配置函數 • fopen( ):檔案開啟函數

  4. 指標ptr存放了變數a的位址,也就是指標ptr指向變數a。指標ptr存放了變數a的位址,也就是指標ptr指向變數a。 指標概述 • C語言提供一種存取變數的特殊方式--指標(pointer),透過指標,可以不必用到變數的名稱,卻可以存取到變數的內容. • 指標其實只是一種特殊的變數,用來存放變數在記憶體中的位址. • 利用指標變數,可以把變數在記憶體內的位址存入指標中,可利用指標先找到該變數的位址,再由該位址取出位址內所儲存的變數值.這種依位址來取值的特殊方式,稱之為“間接定址取值法” 變數內容 一般變數 a 指標變數 ptr ( 圖一 : 指標與變數在記憶體中的情形 )

  5. 指標的宣告與定義 • 指標變數宣告格式 (1) 在變數的前面加上指標符號「*」,即是將變數宣告 成指標變數。 (2) 指標變數之前的資料型態,則是代表指標所指向之變 數的型態。 例一: int *ptr ; /* 宣告指向整數的指標變數ptr ,它所存放的 位址必須是一個整數變數的位址。 */ 資料型態 *指標變數 ;

  6. 指標變數ptr 變數num 1400 20 1408 1400 指標變數ptr的位址 變數num的位址 指標的宣告與定義 法1--- int *ptr ; /* 宣告指向整數的指標變數ptr */ int num=20 ; /*宣告整數變數num,並設值為20 */ ptr = &num ; /*把指標ptr設為變數num的位址, 把ptr指向num */ 法2--- int num=20; int *ptr = # ptr指向整數變數num

  7. 指標變數ptr 變數num 1400 20 1408 1400 指標變數ptr的位址 變數num的位址 指標變數的使用 • 指標變數使用方式 • 位址運算子「 &」 : 用來取得變數的記憶體位址 • 位址取值運算子「 *」 : 用來取得指標所指向變數的內容 int num=20 ; 變數num 20 &num可取出變數num的位址,即 1400 1400 變數num的位址 int num=20; int *ptr=# *ptr可取出ptr所指向之變數num的值(num的值為20)

  8. Output: num=20,&num=ffd6 *ptr=20,ptr=ffd6,&ptr=ffd4 指標變數的宣告 • 範例一:指標變數的宣告 #include<stdio.h> #include<stdlib.h> int main(void) { int *ptr,num=20; /*宣告變數num與指標變數ptr */ ptr=&num; /*將num位址設給指標ptr存放 */ printf(“num=%d, &num=%x\n”,num,&num); printf(“*ptr=%d,ptr=%x,&ptr=%x\n”,*ptr,ptr,&ptr); system(“pause”); return 0; }

  9. Output: a=20, *ptr=20, b=20 ptr=ffd6 ,&a=ffd6 指標的宣告與定義 • 範例二: 比較輸出指標的位址與值 #include<stdio.h> void main() { int *ptr; int a,b; a=20; ptr=&a; /* 將 ptr 指向變數 a 的位址 */ b=*ptr; /* 將 b設定為 ptr 所指位址的內容值 */ printf(“a=%d,*ptr=%d , b=%d\n", a,*ptr , b ); printf(“ptr=%x , &a=%x\n", ptr , &a ); }

  10. 指標所佔的空間大小 • #include<stdio.h> • #include<stdlib.h> • int main(void) • { • int *ptri; /*宣告指向整數的變數ptri*/ • char *ptrc; /*宣告指向字元的變數ptrc*/ • printf("size of ptri = %d\n",sizeof(ptri)); • printf("size of ptrc = %d\n",sizeof(ptrc)); • printf("size of *ptri = %d\n",sizeof(*ptri)); • printf("size of *ptrc = %d\n",sizeof(*ptrc)); • system("pause"); • return 0; • }

  11. 指標所佔的空間大小(續) • 在TC中,compile配置給指標變數的空間都是2bytes。 • Output:

  12. 課堂練習 • #include <stdio.h> • #include <stdlib.h> • int main(void) • { • int a=5,b=10; • int *ptr1,*ptr2; • ptr1=&a; /* 將ptr1設為a的位址 */ • ptr2=&b; /* 將ptr2設為b的位址 */ • *ptr1=7; /* 將ptr1指向的內容設為7 */ • *ptr2=32; /* 將ptr2指向的內容設為32 */ • a=17; /* 設定a為17 */ • ptr1=ptr2; /* 設定ptr1=ptr2 */ • *ptr1=9; /* 將ptr1指向的內容設為9 */ • ptr1=&a; /* 將ptr1設為a的位址 */ • a=64; /* 設定a為64 */ • *ptr2=*ptr1+5; /* 將ptr2指向的內容設為*ptr1+5*/ • ptr2=&a; /* 將ptr2設為a的位址 */ • printf("a=%2d, b=%2d, *ptr1=%2d, *ptr2=%2d\n",a,b,*ptr1,*ptr2); • printf("ptr1=%p, ptr2=%p\n",ptr1,ptr2); • system("pause"); • return 0; • }

  13. 課堂練習 • Output: • 請試著寫出以下四個變數記憶體空間之值的變化: • ptr1 ptr2 a b FADA FBDE FFDE FFDG FFDE FFDG 5 10 FFDG FFDE FFDE 7 17 64 32 9 69

  14. 指標與函數 • 在函數中,若是想傳回某個結果給原呼叫函數,可利用return敘述,但當程式需要傳遞兩個以上的值時,就無法利用return敘述,此時可利用“指標”解決函數間傳遞多個回傳值的問題. • 宣告函數原型範例 : int func ( int * , char * ) ; /* 將指標當成參數,傳入函數 */ • 函數定義中接收參數部分,假設接收的變數名稱為 ptr1及 ptr2,記得在變數名稱前要加指標符號 * int func ( int * ptr1 , char * ptr2 ) ;

  15. 傳入pointer值(變數位址即為pointer的值) 指標與函數之範例1 • 範例六:設計一個傳值函式noswap(),及一個傳址函式swap() #include<stdio.h> void noswap(int, int); void swap(int *, int *); main() { int x=2,y=3; printf("The original values are: x=%d , y=%d \n" , x , y ); noswap(x,y); printf(“(call by value: x=%d , y=%d \n", x , y ); swap(&x,&y); printf(“(call by address: x=%d , y=%d \n", x , y ); }

  16. 指標與函數之範例1 • 接上頁(範例六) void noswap ( int a , int b ) /* call by value */ { int t; t=a; a=b; b=t; } void swap ( int *a , int *b) /* call by address* / { int t; t=*a; *a=*b; *b=t; }

  17. 指標與函數之範例2 • #include <stdio.h> • #include <stdlib.h> • void rect(int,int,int *,int *); /* 函數rect()的原型 */ • int main(void) • { • int a=5,b=8; /*矩形的長與寬*/ • int area=0,peri=0; /*矩形的面積與邊長*/ • rect(a, b, &area, &peri); /* 呼叫rect(),計算面積及周長 */ • printf("area=%d,total length=%d\n",area,peri); • system("pause"); • return 0; • } • void rect(int x, int y, int *p1, int *p2) • { • *p1=x*y; • *p2=2*(x+y); • }

  18. 範例2之說明 • 當函數rect(x, y, area, length) 執行完後,變數area可存放矩形面積,而變數peri可存放矩形的周長。 • 指標的好處之一在於它可以更改傳入的引數值,利用此特性,我們便可以設計出很實用的程式。

  19. 指標與陣列 • 陣列事實上也是指標的一種應用,不同的是,陣列是固定長度的記憶體區塊;而指標是一個變數,用來記錄所指變數的位址. • 利用index即可取出陣列的元素值,除了用index外,也可另外利用指標取出陣列的元素值. char a[10]; /*宣告陣列*/ char *pa; /*宣告指標*/ pa=&a[0]; 或 pa=a; /*指標指向陣列的開頭(第0個元素)*/ 以此為基點用索引的方式來取得陣列的每個元素 *(pa)取到的是陣列的第0個元素 a[0] *(pa+1)取到的是陣列的第1個元素 a[1] /*pa+1是將位址值加2(int佔2個bytes)*/ *(pa+i) 取到的是陣列的第i個元素 a[i]

  20. 指 標-指標與一維陣列 • 指標與一維陣列 表示宣告ptr是一個指標變數,ptr本身存的是一個變數的位址。 ptr=a的效果就是將ptr指向a[0]的位址。 printf(“%d”,*ptr); for(i=1;i<5;i++) printf(“%d”,*ptr++); /* 不能寫成*a++ */ int *ptr; int a[5]={3,8,6,2,5}; ptr=a; /* 或 ptr=&a[0]; */ *ptr取出陣列裡的值 陣列名稱本身是一個存放位址的「指標常數」,指向陣列的位址。 因為陣列宣告後,陣列的記憶體位址配置已被固定,所以我們不能再去改變陣列名稱的指向! for(i=0;i<5;i++) printf(“%d”,a[i]);

  21. int a[5]={3,8,6,2,5}; int *ptr; ptr=&a[0]; a ptr fdd2 &a[0] ptr+0 a[0] *(ptr+0) *(ptr+1) a[1] &a[1] fdd4 ptr+1 a[2] *(ptr+2) &a[2] ptr+2 fdd6 a[3] &a[3] ptr+3 *(ptr+3) fdd8 &a[4] ptr+4 a[4] *(ptr+4) fdd10

  22. 課堂練習 • 範例4-2: • #include <stdio.h> • #include <stdlib.h> • int main(void) • { • int a[3]={5,1,9}; • printf(“a[0]=%d, *(a+0)=%d\n”,a[0],*(a+0)); • printf(“a[1]=%d, *(a+1)=%d\n”,a[1],*(a+1)); • printf(“a[2]=%d, *(a+2)=%d\n”,a[2],*(a+2)); • system(“pause”); • return 0; • }

  23. 範例4-2 請說明以下變數的內容 &a[2] &a[1] &a[0] *(a+2) a[2] *(a+1) a[1] *(a+0) a[0] 1408 1406 1404

  24. Pointer指向陣列的開頭 指標與陣列 • 範例四: 用指標取出陣列元素的值與位址 #include<stdio.h> main() { int i; char *pa; char a[4]={'A','B','C','D'}; pa=a; for(i=0;i<4;i++) printf("a[%d] value:%c ; *(pa+%d) value:%c\n",i,a[i],i,*(pa+i)); for(i=0;i<4;i++) printf("&a[%d] address:%x ; *(pa+%d) address:%x\n",i,&a[i],i,pa+i); }

  25. 範例四的結果 • 指標的算術運算多半用在存取陣列元素的操作上。 • 因為compile會配置給陣列一塊連續的記憶體空間,所以陣列元素的位址之間有很高的關聯性。

  26. *(ptr+3*0+2)=5 表示將 a[0][2]的值設為5 指 標-指標與二維陣列 • 指標與二維陣列 • 二維陣列在人們眼中通常用於處理二維的行列表格,但電腦內部的記憶體,是以一維陣列的方式排列,所以雖然是二維的陣列,但在電腦的記憶體中已轉為一維的方式儲存。 • 以指標來處理二維陣列,第一步驟設定第一元素的位址給指標變數: int *ptr; int a[4][3]; ptr=&a[0][0]; 第二步驟以ptr來表示二維陣列的值,必須先將二維排列轉為一為陣列的直線排列: 第0行 第1行 第2行 ptr 第0列 第1列 第i列,第j行 的表示方式*(ptr+3*i+j) 第2列 第3列 3為此陣列行的個數

  27. 若要存取第i列第j行的值: • *(*(a+i)+j)=5; • a[i][j]=5; • *(ptr + 3 *i + j)=5; /*a[i][j]=5;*/ j i

  28. 陣列名稱num是指標常數,是一個指向指標的指標陣列名稱num是指標常數,是一個指向指標的指標 int num[3][4]; num num[0] 1000 1000 第 0列 1000 1000 num[1] 1008 第1列 1008 num[2] 1016 第2列 1016 num[0]~num[2]也是指標常數,分別儲存了每一個一維陣列裡,第一個元素的位址 3*4的二維陣列可以看成是由3個一維陣列所組成 在宣告num陣列時,編譯器會自動配置一個「指標常數」的陣列num[0]、num[1]、num[2]讓他們分別指向每一列的第一個元素。

  29. *(num+0)可取出此值 *(num+2)可取出此值 • 續上頁 num[0] 1000 num+0 1000 num[1] 1008 num+1 1008 num[2] 1016 num+2 1016

  30. 續上頁 *(*(num+1)+2) *(*(num+1)+1) *(*(num+1)+3) *(*(num+1)+0) *(num+1)可取出此值 num[1] 1008 第1列 1008 num+1 *(num+1)+0 *(num+1)+2 *(num+1)+3 *(num+1)+1 這裡列跟行的算法是從第0列第0行起算 *(num+i)+j代表了第i列,第j行的位址 *(*(num+i)+j)代表了取出第i列,第j行的值

  31. 指標與陣列---指標陣列 • 指標也可以宣告成陣列:指標陣列。 • 宣告方式如下: • 資料型態 *陣列名稱[元素個數]; • 例如: • int *ptr[3]; • /*表示宣告了一個可存放3個指向整數的指標,分別是ptr[0] 、ptr[1]、ptr[2]*/ • 二維陣列: • char str[3][10]={“Clare”, ”Jane Wang”, ”Tom Lee”}; • 指標陣列: • char *ptr[3]={“Clare”, ”Jane Wang”, ”Tom Lee”};

  32. Name[0] Name[0] Name[1] Name[1] Name[2] Name[2] 指標陣列 • 指標陣列 如何建立一個儲存字串的陣列?除了用二維的字元陣列處理,另外可用“指標陣列”來解決,用指標陣列來處理,會較節省記憶體空間. char Name[3][10]={“Clare”,”Jane Wang”,”Tom Lee”}; ( 圖 三 : 儲存字串的二維字元陣列儲存方式 ) char *Name[3]={“Clare","Jane Wang","Tom Lee"}; ( 圖 四 : 指標陣列儲存方式 )

  33. 指標陣列 • 範例五: 指標陣列 #include <stdio.h> int main(void) { int i; char *name[3]={"David","Jane Wang","Tom Lee"}; for(i=0;i<3;i++) /* 印出指標陣列的內容 */ printf("name[%d]=%s\n",i,name[i]); /*puts(name[i];)*/ return 0; }

  34. 指標陣列 • 範例五: 指標陣列另一種寫法 • #include <stdio.h> • int main(void) • { • int i; • char *ptr[3]; • ptr[0]="David"; /*設定ptr[0]指向字串”David” */ • ptr[1]="Jane Wang"; /*設定ptr[1]指向字串”Jane Wang” */ • ptr[2]="Tom Lee"; • for(i=0;i<3;i++) /* 印出指標陣列的內容 */ • /*printf("ptr[%d]=%s\n",i,ptr[i]);*/ • puts(ptr[i]); • return 0; • }

  35. 指向整數的指標 變數 一般變數 雙重指標 指標變數 1200 1460 5 位址 1000 1200 1460 位址 整數值 指向指標的指標—雙重指標 • 雙重指標宣告方式 例 : int **ptri; /*宣告一個指向整數的雙重指標ptri */ 資料型態 **指標變數; 雙重指標

  36. a ptr2 ptr1 ffd4 ffd6 10 ffd4 ffd6 ffd2 Output: a=10, &a=ffd6 *ptr1=10, ptr1=ffd6 **ptr2=10 ,*ptr2=ffd6 ptr2=ffd4 , &ptr1=ffd4 指向指標的指標—雙重指標 • 範例三: 雙重指標 , 輸出其內容及位址 #include<stdio.h> void main() { int *ptr1,**ptr2; int a=10; ptr1=&a; /* 指標 ptr1指向 a 的位址 */ ptr2=&ptr1; /* 雙重指標 ptr2 指向 ptr1的位址 */ printf("a=%d , &a=%x\n", a , &a ); printf("*ptr1=%d , ptr1=%x\n", *ptr1 , ptr1 ); printf("**ptr2=%d , *ptr2=%x\n", **ptr2 , *ptr2); printf("ptr2=%x, &ptr1=%x\n", ptr2 , &ptr1); }

More Related