基本介紹
指標宣告
1 2 3 4 5 6
| // countPtr 型態為 int* // 表示指向 int 的指標 int *countPtr;
// 以下宣告只有 a 是指標 b 不是 int *a,b;
|
指標表示如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| /* count addr = 0060FF08 countPtr addr = 00000000 */ int count = 7; int *countPtr = NULL;
// countPtr addr = 0060FF08 countPtr = &count;
/* 值 0060FF08 7 名稱 countPtr count 位址 0060FF0C 0060FF08 */
|
宣告指標時最好就要給初始值或設為 NULL
NULL
定義在 stdio.h 中
指標運算子
& 為其中一種運算子,稱為位址運算子
目的就是將後面的變數位址取出,注意 & 只能用在變數
不能用在常數、運算式或宣告為 register 的變數
他會取出指標所指變數位址的值,也就是對指標求值
- 和 & 是互補的,也就是
*&valPtr = &$valPtr
Call Func by Ref
有兩種方法傳參數給 func,傳值和傳址
傳值的好處是可以減少一些負擔
如果你要傳一個物件很大,而使用傳值時
會複製這一個物件而造成空間負擔
const 在 pointer 上使用
const 告訴編譯器,某變數的值不能修改
在函式參數使用 const 有 6 種情況
傳值 2 種、傳址 4 種
不同種類是依照你要給函式多大權力來決定
另外傳值只能改變主函式的一個值(利用 reutrn)
要改兩個值就只能用傳址
傳址給函式有 4 種方法
1 2 3 4
| 1.指向 "非常數 data" 的 "非常數 pointer"(什麼都能做) 2.指向 "常數 data" 的 "非常數 pointer"(保護資料) 3.指向 "非常數 data" 的 "常數 pointer"(陣列) 4.指向 "常數 data" 的 "常數 pointer"(什麼都不能做)
|
4 種代表不同權限,最高的是第 1 種
以下為傳入一字串,將小寫改大寫的函式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| void covToUp(char *strPtr) { while( *strPtr != '\0' ) { if( (int)(*strPtr)>= 97 && (int)(*strPtr)<= 122) { *strPtr = (int)(*strPtr)-32; } /* 也可以用內建函式轉 if( islower(*strPtr) ) { *strPtr = toupper(*strPtr); } */ strPtr++; } }
int main() { /* a = 97 z=122 A = 65 a -> A = -32 */ char str[] = "characters and $32"; printf("1. str = %s\n",str); covToUp(str); printf("2. str = %s\n",str); return 0; }
|
第 2 種為指向 “常數 data” 的 “非常數 pointer”
也就是說,pointer 可以指向其他變數,但變數本身的值不能改
此指標宣告為 const char *ptr
要由右往左念!
ptr 是一個指標(*),他指向的變數是常數字元(const char)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| void printChar(const char *strPtr) { while( *strPtr != '\0' ) { printf("char = %c\n",*strPtr); /* 加入以下會編譯錯誤 *strPtr = toupper(*strPtr); */ strPtr++; } /* 就算在這裡將傳入的指標設為 NULL 回到 main str 的位址還是不變 代表 strPtr 只是一個副本而已 */ strPtr = NULL; }
int main() { char str[] = "characters and $32"; printf("1.str addr = %p\n",&str); printChar(str); printf("2.str addr = %p\n",&str); return 0; }
|
結構傳給 func 時都是傳值,但這樣很浪費空間
所以你可以改用此種方法傳給 func
再來第 3 種方法指向”非常數 data” 的 “常數 pointer”
此種 pointer 永遠指向同一個位址
就像陣列變數一樣,陣列變數永遠指向陣列第一個位址
但是我們又可以藉由此指標更改裡面儲存的值
宣告此種指標為 char *const ptr
,一樣由右往左念
ptr 是一個常數指標(*const),他指向字元類型
最後一種存取全縣最低,宣告為const char *const ptr
氣泡排序
氣泡排序可以由小排到大或由大排到小,邏輯上是一樣的
以小到大來說,每一回合就是兩兩比較
每一回合都會把最大的搬到最後面,總共會進行 N-1 回合
舉例來說,有個陣列是 6,3,9,2 (共 4 個數字)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 第 1 回合 (6) 3 9 2 -> 3,6,9,2 3 (6) 9 2 -> 3,6,9,2 3 6 (9) 2 -> 3,6,2,9 第 1 回合結束 9 最大放在最後面 第 2 回合 (3) 6 2 -> 3,6,2 3 (6) 2 -> 3,2,6 第 2 回合結束 6 最大放在最後面
第 3 回合 (3) 2 -> 2,3 第 3 回合結束 3 最大放在最後面
最後為 2,3,6,9
|
程式碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void bubbleSort(int aInt[]) { int aLen = sizeof(aInt); int i = 0; int j = 0; for(i = 0 ; i<aLen-1 ;i++) { for(j = 0 ; j<aLen-1 ;j++) { if( aInt[j] > aInt[j+1] ) { int temp = aInt[j]; aInt[j] = aInt[j+1]; aInt[j+1] = temp; } } } }
|
函式指標
和陣列一樣,函式名稱也就代表函式的起始位址
以下程式示範將函示指標傳入某個函式參數中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| void pArray(int aInt[],int aLen) { int i = 0; for(i = 0 ; i<aLen ;i++) { printf("aInt[%d] = %d\n",i,aInt[i]); } }
int asc (int, int); int desc (int, int); void bubbleSort (int [], int , int (*)(int,int));
int asc(int a, int b) { return b<a; }
int desc(int a, int b) { return b>a; }
void bubbleSort(int aInt[], int aLen, int (*comp)(int,int)) { int i = 0; int j = 0; for(i = 0 ; i<aLen-1 ;i++) { for(j = 0 ; j<aLen-1 ;j++) { //if( aInt[j] > aInt[j+1] ) if( (*comp)(aInt[j],aInt[j+1]) ) { int temp = aInt[j]; aInt[j] = aInt[j+1]; aInt[j+1] = temp; } } } }
int main() { int val[] = {6,21,3,9,2,10}; int aLen = sizeof(val)/sizeof(val[0]); bubbleSort(val, aLen, desc); return 0; }
|