08 指標
- 3. 認識指標(2) 8-1 認識指標
程式範例:&(取址運算子)的宣告與使用範例:
CH08_01.c
3
- 4. 8-1 認識指標
執行結果
程式解說
第6~8行分別宣告三種不同型態的變數,第10~12行則
以%p格式來表示16進位的位址,如果要取出變數的位
址只要在變數前加上&運算子即可。 4
- 8. 指標變數的宣告(2) 8-1 認識指標
程式範例:指標變數的宣告與使用範例:
CH08_02.c
8
- 9. 8-1 認識指標
執行結果
程式解說
第9行宣告指標變數指向num1變數的位址。
第11行則利用&運算子取出num1位址。
第13行則是輸出此指標變數的位址。 9
- 10. 指標變數的宣告(3) 8-1 認識指標
程式範例:指標變數與取值運算子的使用範例:
CH08_03.c
10
- 11. 8-1 認識指標
執行結果
程式解說
在第10、12行中分別指向相同資料型態的不同變
數,而在第11、13行中分別輸出指標變數的值與
指向變數的位址間的比較。 11
- 13. 8-1 認識指標
執行結果
程式解說
在第9行中,我們特意使用了input變數來初始化指標的值,
這邊再次要提醒的是,您不能使用未經初始化的指標。
第12,行,由於取址運算子與乘法運算子在符號使用上相同,
您可以使用空白來增加程式的可讀性,此外由於取址運算子
的優先順序大於乘法運算子,所以不必加上括號。
第13行中我們特別把求得立方值的*ptr內容輸出,各位會發
現與它同一位值的input變數值也同步改變了。 13
- 14. 8-1 認識指標
指標與函數傳遞(1)
先來回憶一下傳址方式的函數宣告型式如下所示:
回傳資料型態 函數名稱(資料型態 *參數1, 資料型態 *參數
2, ……….);
或
回傳資料型態 函數名稱(資料型態 *, 資料型態 *, ……….);
此外,傳址呼叫的函數呼叫型式如下所示:
函數名稱(&引數1,&引數2, ……….);
14
- 15. 指標與函數傳遞(2) 8-1 認識指標
程式範例:氣泡排序法的傳址呼叫範例:
CH08_05.c
15
- 18. 8-1 認識指標
執行結果
程式解說
在本程式中由於swap()函數與BubbleSort( )函數是定義
在main( )函數之前,所以不用原型宣告。
第4行利用兩個指標變數傳入函數內。
第24行接收兩個指向陣列元素的位址。
第38行呼叫BubbleSort( )函數,並將num陣列以傳址呼
叫傳送。 18
- 20. 函數與指標回傳值(2) 8-1 認識指標
程式範例:函數與指標回傳值的應用範例:
CH08_06.c
20
- 22. 8-1 認識指標
執行結果
程式解說
第4行是傳回指標值的函數原型宣告,第9行呼叫
get_pointer_value ()函數,並傳值給ptr指標變數。
第11行輸出ptr指標變數的內容。
第19行函數宣告為傳回指標變數。第25行輸入input變
數的值。
第28行傳回值為指標變數。 22
- 23. 函數與指標回傳值(3) 8-1 認識指標
程式範例:指標回傳值與函數傳遞的應用範例:
CH08_07.c
23
- 25. 8-1 認識指標
執行結果
程式解說
第4行宣告傳址呼叫函數min()的原型。
以ptr指標變數接收函數的指標回傳值。
第23、24行則直接傳回指標值。 25
- 26. 8-1 認識指標
指標的運算
對於指標的加法或減法運算,只能針對常數值
(如+1或-1)來進行,不可以做指標變數之間的
相互運算。
因為指標變數內容只是存放位址,而位址間的
運算並沒有任何意義,而且容易讓指標變數指
向不合法位址。
以下程式範例中可以發現,對整數型態的指標
來說每進行一次加法運算,記憶體位址就會向
右移動4位元組,而對於字元型態的指標而言,
加法運算則是每次向右移動1位元組。
26
- 29. 8-1 認識指標
程式解說
第6、7行宣告整數型態指標與字元型態指標變數。
第13行整數指標變數加一,則記憶體位址就會向右
移動4位元組。
第14行字元指標變數加一,則記憶體位址就會向右
移動1位元組。
29
- 30. 8-1 認識指標
多重指標(1)
一個宣告雙重指標的例子如下所示:
int **ptr;
雙重指標變數所存放的就是某個指標變數在記
憶體中的位址,也就是這個ptr就是一個指向指
標的指標變數。例如我們宣告如下:
int num=100,*ptr1,**ptr2;
ptr1=#
ptr2=&ptr1;
30
- 32. 8-1 認識指標
執行結果
程式解說
第11行中各位可以發現&num的位址和ptr是一樣的,而
*ptr的值也和num相同。
第13行中&ptr1和ptr2相同,ptr1與*ptr2一樣,*ptr1與
32
**ptr2相同。
- 33. 8-2 指標與陣列的應用
指標與一維陣列(1)
陣列宣告:
int arr[6]={312,16,35,65,52,111};
這時陣列名稱arr就是一個指標常數,也是這個
陣列的起始位址。
可以利用指標方式與取值運算子「*」來直接
存取陣列內的元素值。使用語法如下:
陣列名稱[索引值]= *陣列名稱(+索引值)
或
陣列名稱[索引值]= *(&陣列名稱[索引值]) 33
- 36. 8-2 指標與陣列的應用
程式解說
第7行輸出指標常數arr的值與指標常數arr的位址相同。
第11行列印陣列與兩種指標常數的替代運算,從執行結
果中您可以看到,對於int資料型態來說,每加1則位址
位移4位元組。
第15行則以兩種指標常數方式來存取陣列內的元素值。
36
- 40. 8-2 指標與陣列的應用
程式解說
使用指標變數ptr指向陣列常數arr。
第15、17行輸出arr+i的值與ptr+I的值,兩者顯
示的位址是相同的。
40
- 41. 指標與二維陣列(1) 8-2 指標與陣列的應用
二維陣列具有兩個索引值,這意味著二維陣列
會有兩個值來控制指定元素相對於第一個元素
的位移量,為了說明方便,我們以下面這個宣
告為例:
int no[2][4];
在這個例子中,*(no+0)將表示陣列中維度1的
第一個元素的記憶體位址。
也就是&no[0][0];而*(no+1)表示陣列中維度2
的第一個元素的記憶體位址,也就是&no[1][0],
而*(no+i)表示陣列中維i+1的第一個元素的記憶
體位址。 41
- 43. 8-2 指標與陣列的應用
執行結果
程式解說
第11行中是輸出使用「&」取址運算子取得二維陣列元素
位址與指標常數來表示二維陣列元素位址,並可發現要取
得元素no[i][j]的記憶體位址,則要使用*(no+i)+j來取得。
43
- 45. 8-2 指標與陣列的應用
執行結果
程式解說
第11行使用*(*(no+i)+j)與no[i][j]來輸出二維陣列的元素值。
依照以上的說明,您也可以推論在三維陣列中,存取元素值
時的三個索引值之真正意義,其實就分別代表了三個記憶體
位移量的控制,而當中必須使用三重指標來計算,這部份的
推論方式與以上的介紹類似。 45
- 46. 8-2 指標與陣列的應用
指標與字串(1)
在C語言中,字串是以字元陣列來實現,指標
既然可以運用於陣列,則當然也可以運用於字
串。以下都是字串宣告的合法方式:
char name[] = { 'J', 'u', 's', 't', '0'};
char name1[] = "Just";
char *ptr = "Just";
使用指標的觀念來處理字串,會比使用陣列來
得方便許多,宣告格式如下:
char *指標變數="字串內容";
46
- 47. 指標與字串(2) 8-2 指標與陣列的應用
程式範例:指標與字串的宣告與使用範例:
CH08_14.c
47
- 50. 8-2 指標與陣列的應用
程式解說
第7行以以指標變數宣告字串方式,第8行則以字元陣列
宣告字串方式。
在第11行輸出的ptr所佔空間大小4位元,是因為ptr所存
放的是整數位址。
至於sizeof(name)則輸出包含‘0’共7位元。
第16行則以指標變數及指標常數輸出字串。
第21行則將指標變數及指標常數以陣列方式及逐一讀值
方式輸出字元。
第26、27行則執行指標運算,並輸出當時的位址。
50
- 51. 指標與字串(3) 8-2 指標與陣列的應用
程式範例:字串傳遞與大小寫字母互相轉換應
用範例:CH08_15.c
51
- 54. 8-2 指標與陣列的應用
執行結果
程式解說
第9行中是以陣列字元宣告字串,第24、40行則利用指標
變數接收參數字串。
第29、46行則將函數中的指標變數逐一計算字元總數。
第34、51行的主要技巧是利用指標變數逐一讀出字元與在
ASCII編碼中,英文小寫字母編碼為97~122,而大寫字母
為65~90,中間的編碼數值差為32,而字元在記憶體中其
實是以整數型態儲存,所以我們只要對字元加32或減32,
就可以直接轉換字母的大小寫。
54
- 59. 8-2 指標與陣列的應用
程式解說
第4行是指標傳回值的字串串接函數。
第8、9行宣告兩個有60字元的字串陣列。
第28行尋找str1的結束字元‘0’位置,並計算i的長度,第
31~32行將小寫字元轉為大寫。第36~37行逐一加上str2
的字元,並將小寫字元轉為大寫。
第41行加上空字元,代表字串結束。
59
- 60. 8-2 指標與陣列的應用
指標陣列(1)
一維指標陣列的宣告格式:
資料型態 *陣列名稱[元素名稱];
例如以下是宣告一個名稱為p的整數指標陣列,
每個元素(p[i])皆可指向一整數值,另外一個則
是宣告一個名稱為ptr的浮點數指標陣列:
int *p[3];
float *ptr[4];
60
- 61. 8-2 指標與陣列的應用
一維指標陣列的應用特別在儲存字串上相當實用。
例如之前介紹使用二維字元陣列,當一個字串陣列
的宣告方式如下所示:
char name[4][11] = { "apple", "watermelon", "Banana",
"orange" };
為了避免記憶體空間的浪費,我們就相當適合使用
「指標陣列」來儲存字串,我們可以將之前的宣告
更改為以下的方式:
char *name[4] = { "apple", "watermelon", "Banana",
"orange" }; 61
- 62. 指標陣列(2) 8-2 指標與陣列的應用
程式範例:一維指標陣列與字串儲存的應用範
例:CH08_17.c
62
- 63. 8-2 指標與陣列的應用
執行結果
程式解說
我們於第06行宣告陣列時加入了一個空字串,這是
為了方便計算指標陣列儲存字串時所佔有的空間。
在第11行列印字串內容及儲存起始位址。
第12行各位可從兩個位址相減會得到位移量來判斷
所佔用儲存空間。 63
- 64. 指標陣列(3) 8-2 指標與陣列的應用
程式範例:一維指標陣列與氣泡排序法的應用
範例:CH08_18.c
64
- 66. 8-2 指標與陣列的應用
執行結果
程式解說
第7行宣告並設定字串陣列內容。
第10行宣告一維指標陣列及字元指標變數。
第17行將一維指標陣列每個元素指向字串陣列的每個位址。
第31行輸出排序後一維指標陣列的內容。
66
- 67. 8-3 動態配置記憶體
動態配置變數(1)
動態配置一般變數的方式如下,如果n=1,即
表示一個變數:
資料型態* 指標名稱=(資料型態*)malloc(sizeof(資料型態)*n);
當執行時期動態配置的一般變數不需要時,可
以將其釋放,釋放動態配置的一般變數的方式
如下:
free(指標名稱);
67
- 68. 動態配置變數(2) 8-3 動態配置記憶體
程式範例:動態配置變數的宣告與應用範例:
CH08_19.c
68
- 70. 8-3 動態配置記憶體
執行結果
程式解說
第6、8行將浮點數與整數指標指向動態配置記憶空間。
第7、9行分別設定浮點數與整數指標變數的起始值。
第15、16行使用free()函數釋放piVal與 piCal指標所指
向的記憶體空間。 70
- 71. 動態配置變數(3) 8-3 動態配置記憶體
程式範例:動態配置字串變數的宣告與應用範
例:CH08_20.c
71
- 73. 8-3 動態配置記憶體
程式解說
第7行動態配置記憶與str1字串相同大小空間,而第
10行將str1字串複製到str2字串。
第13行輸出str2的位址與所指向的內容值。
第15行釋放str2字串記憶空間。
第13行輸出釋放後的str2位址與所指向的內容值。
73
- 74. 8-3 動態配置記憶體
動態配置陣列(1)
動態配置一維陣列的方式如下,n=陣列長度:
資料型態* 指標名稱=(資料型態*)malloc(n*sizeof(資料型態));
當執行時期動態配置的一維陣列不需要時,可
以將其釋放,釋放動態配置的一維陣列的方式
如下:
free(指標名稱);
74
- 75. 動態配置陣列(2) 8-3 動態配置記憶體
程式範例:動態配置一維陣列的宣告與應用範
例:CH08_21.c
75
- 78. 8-3 動態配置記憶體
程式解說
第10行請輸入欲產生的動態一維陣列個數,第11行
將整數指標指向動態配置一維陣列記憶空間。
第13~16行輸入max個數的陣列元素值。
第24行釋放指標指向的記憶空間。
78
- 79. 8-4 上機實習課程
上機實習課程(1)
上機實習範例:CH08_22.c
– 以下程式範例是利用指標常數方式來表示三維
陣列元素位址的方法與直接使用「&」取址運算
子取得三維陣列元素位址的比較。
– arr陣列元素內容如下:
A[4][3][3]={{{1,-2,3},{4,5,-6},{8,9,2}},
{{7,-8,9},{10,11,12},{0.8,3,2}},
{{-13,14,15},{16,17,18},{3,6,7}},
{{19,20,21},{-22,23,24},(6-,9,12)}};
79
- 85. 上機實習課程(3) 8-4 上機實習課程
上機實習範例:CH08_24.c
– 以下程式範例中利用指標變數指向arr陣列,並
將此指標變數傳遞到計算次方值的cubic()函數,
再利用函數中的指標變數加法運算,來將每一
個元素值次方運算及所有新元素的總和。最後
再輸出所有新元素及總和。
85
- 88. 8-4 上機實習課程
上機實習課程(4)
上機實習範例:CH08_25.c
– 現在有三個整數陣列num1、num2、num3,其
中分別存放二位數整數、三位數整數與四位數
整數,如下所示:
int num1[]={ 15,23,31 };
int num2[]={ 114,225,336 };
int num3[]={ 1237,3358,9271 };
– 請設計一程式,利用指標陣列的三個元素值指
向這三個陣列,並透過這個指標陣列來輸出此
三個整數陣列的所有元素值。
88
- 91. 8-4 上機實習課程
上機實習課程(5)
上機實習範例:CH08_26.c
– 以下程式範例只要是說明函數名稱本身也代表
了一個記憶體位址,當您呼叫函數時,其實就
是在告訴程式,執行該函數名稱所指向的記憶
體位址中之程式,這與函數後加上括號的呼叫
方式是有不同。
91
- 93. 8-4 上機實習課程
上機實習課程(6)
上機實習範例:CH08_27.c
– 延續上題的概念,函數名稱其實也是個指標變
數,其本身所儲存的值為函數內容所在的記憶
體起始位址,因此函數也可當成指標來宣告,
稱為「函式指標」。
– 其作用在於使用同一個函式指標名稱,主要作
用在於程式執行期間動態地決定該呼叫的函式。
宣告方式如下:
資料型態 (*ptr)(參數1, 參數2, …)
93
- 96. 上機實習課程(7) 8-4 上機實習課程
上機實習範例:CH08_28.c
– 請將一個整數指標變數指向二維陣列arr,並利
用指標運算將陣列中每一個元素值輸出。
– arr陣列內容如下:
arr[4][3]={312,16,35,65,52,111,66,88,44,55,99,100};
96
- 100. 8-4 上機實習課程
上機實習課程(9)
上機實習範例:CH08_30.c
– 請設計一函數replace(),可在使用者所輸入的
字串中指定位置及打算更換的字元,函數中將
使用字元指標來處理運算及置換過程。
100
- 103. 上機實習課程(10) 8-4 上機實習課程
上機實習範例:CH08_31.c
– 下面這個程式範例則是說明了三重指標的宣告
與使用方法,依據相同的方法也可以宣告更多
重指標。
103
- 105. 8-4 上機實習課程
上機實習課程(11)
上機實習範例:CH08_32.c
– 我們宣告一個指標變數p1並設定它的初值為指向
陣列變數array1的第五個元素的記憶體位址:
int i,array1[5]={100,200,300,400,500};
int *p1=array1;
p1=&array1[4];
– 例如當我們將指標變數p1減1之後,就是將目前指
標變數p1所指向的記憶體位址往前移動1次,也就
是指向陣列變數array1的第四個元素,請看以下
程式碼的實作驗證。
105
- 108. 8-4 上機實習課程
上機實習課程(12)
上機實習範例:CH08_33.c
– 以下程式範例是利用指標常數方式來表示三維
陣列元素位址的方法與直接使用「&」取址運算
子取得三維陣列元素位址的比較。
– arr陣列元素內容如下:
A[4][3][3]={{{1,-2,3},{4,5,-6},{8,9,2}},
{{7,-8,9},{10,11,12},{8,3,2}},
{{-13,14,15},{16,17,18},{3,6,7}},
{{19,20,21},{-22,23,24},(-6,9,12)}};
108
- 112. 上機實習課程(13) 8-4 上機實習課程
上機實習範例:CH08_34.c
– 以下程式範例是說明如果使用指標變數*ptr來存
取二維陣列中第i列的第j行元素可以利用如下公
式來取出該元素值:
*(ptr+i*m+j);
112
- 114. 上機實習課程(14) 8-4 上機實習課程
上機實習範例:CH08_35.c
– 下面的範例程式以兩種不同方式建立字串,並利用
指標讀出其中的各個字元,顯示於螢幕中。
114