C語言的重要功能之一:指標,以下簡單紀錄
- 特色
- 傳參考(Call By Reference)
- 值是儲存地址(Memory Address)
- 宣告(declaration)
1 | int *ptr; |
- 初始化(initialization)
1 | int num=0; |
- 反參考(dereference)
取得指標指向的記憶體中那個變數所存的值
1 | printf("%d",*ptr); |
- 範例程式
1 | /***************************************** |
1 | ptr: 0x7ffc2dc851fc |
- 傳地址(call by reference)
- Function的參數都是透過傳值(call by value)
- 透過指標,可以「模擬」傳地址(call by reference)
1 | /***************************************** |
- 指標與陣列
1 | /***************************************** |
1 | address of a\[0\]:0x7fff77e371d0 |
當 ptr 指向a[0],地址(…1d0)
則 ptr+2 會指向a[2],地址(…1d0) + 2 × 4 ⇐ 乘4是因為1個int佔4個Bytes
所以 ptr+2 指向地址(…1d8),也就是a[2]的地址
而 ptr2-ptr 會回傳地址差÷4
就是 ( (…1e6) - (…1d8) ) ÷ 4 = 2
- void
1
void *ptr;
- 可以使用void來宣告pointer,此pointer只存地址
- 此類pointer不可反參考
- 若要反參考,須將此pointer轉型至int等型別
const with pointer
non-constant pointer,non-constant data
pointer可以改指其他地址,反參考(dereferenced)可以改存的資料non-constant pointer,constant data
pointer可以改指其他地址,但反參考不能改存的資料1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23/*****************************************
Filename:Pointer4.c
Author:Willy Chen(willychen.org)
Date:2018.01.04
*****************************************/
void printChar( const char *Ptr);
// 等同於 void printChar( char const *Ptr);
int main(){
char s\[\]="This is a test.";
printf("s:%s\\n",s);
printChar(s);
printf("\\n");
return 0;
}
void printChar( const char *Ptr){
for(; *Ptr != '\\0';Ptr++){
printf("%c",*Ptr);
}
}1
2s:This is a test.
This is a test.在 printChar 中只有讀取 Ptr 的值,然後修改 Ptr 的指向,並沒有修改 Ptr 所指變數的值
若是在 printChar 的 for 迴圈中加個 *Ptr = ‘x’; 之類的
compiler 會印出 Error,因為加 const 設定成 read-only了constant pointer,non-constant data
pointer永遠指向同一地址,反參考(dereferenced)可以改存的資料
宣告一個array時預設的權限:array的名稱恆指向陣列的開頭1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21/*****************************************
Filename:Pointer5.c
Author:Willy Chen(willychen.org)
Date:2018.01.05
*****************************************/
void change( char * const Ptr);
int main(){
char c = 'A';
char *cptr = &c;
printf("Origin:%c\\n",*cptr); //deference
change(cptr);
printf("Change:%c\\n",*cptr);
return 0;
}
void change( char * const Ptr){
*Ptr = 'B';
}1
2Origin:A
Change:Bconstant pointer,constant data
pointer恆指向同一地址,那個地址中的資料不可用反參考修改
基本上只能做讀取的功能1
void read( const char * const ptr)
如傳一個 array 到 Function 中時,Function中只能對此 array 做讀取的動作
簡單整理一下
當有 const 在 * 左邊時,代表這個 pointer 指向地址存的資料不可更動,如1
2const char * c;
char const * c;當有 const 在 * 右邊時,代表這個 pointer 不可變更指向的地址,如
1
char * const c;
sizeof operator
是一種一元運算子(unary operator)
使用 sizeof 讓程式在編譯時取得變數(陣列等等)的 byte 大小
範例程式
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/*****************************************
Filename:Pointer6.c
Author:Willy Chen(willychen.org)
Date:2018.01.05
*****************************************/
int main(){
int x = 0;
char y = 0;
double z = 0;
char *ptr = &y;
printf("size of x:%d\\n"
"size of int:%d\\n"
"size of y:%d\\n"
"size of char:%d\\n"
"size of z:%d\\n"
"size of double:%d\\n"
"size of ptr:%d\\n"
"size of char*:%d\\n",
sizeof(x),sizeof(int),sizeof(y),sizeof(char),
sizeof(z),sizeof(double),sizeof(ptr),sizeof(char*)
);
return 0;
}1
2
3
4
5
6
7
8size of x:4
size of int:4
size of y:1
size of char:1
size of z:8
size of double:8
size of ptr:8
size of char*:8結果可以看到存 char* (char的指標)使用了 8 bytes
Array of pointer
可以宣告一個指標陣列,其中存一些字串(正確來說是存指標)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/*****************************************
Filename:Pointer7.c
Author:Willy Chen(willychen.org)
Date:2018.01.05
*****************************************/
int main(){
const char * array\[4\] = {"Apple","Banana","Lemon","Orange"};
printf("array\[0\]:%s\\n",array\[0\]);
printf("array\[1\]:%s\\n",array\[1\]);
printf("\*array\[0\]:%c\\n",\*array\[0\]);
printf("\*array\[1\]:%c\\n",\*array\[1\]);
printf("size of array:%d\\n",sizeof(array));
printf("elements of array:%d\\n",sizeof(array)/sizeof(char*));
return 0;
}1
2
3
4
5
6array\[0\]:Apple
array\[1\]:Banana
*array\[0\]:A
*array\[1\]:B
size of array:32
elements of array:4範例程式中array 是一個存有4個指標的陣列
第一個指標 array[0] 指向第一個字串第一個字元的地址,也就是”Apple”的’A’
第二個指標 array[1] 指向第二個字串第一個字元的地址,也就是”Banana”的’B’
所以當反參考 *array[0] 時,會得到 ‘A’
反參考 *array[1] 時,會得到 ‘B’注意字串 “Apple” 實際上是存 ‘A’ ‘p’ ‘p’ ‘l’ ‘e’ ‘\0’,每個字串後面都有 ‘\0’ (null-terminated character string)
sizeof(array)會回傳陣列的大小(Bytes)
使用 sizeof(array)/sizeof(char*) 可以得到 array 的元素個數:4
換句話說,前面有得到 指標的大小sizeof(char*) 是占用 8 bytes,而 array 有4個元素,所以 array的大小就是 8 × 4 = 32 ,也就是 sizeof(array) 得到的數值
pointer to function
- 剛剛是指到字串的地址,現在換成指到 function 的
- 定義: void (*f[3]) (int) = {func1, func2, func3};
- 有三個 function 叫 func1,func2 和 func3,其中他們的回傳值是 void,有一個 int 的參數
- 現在把他們放到一個叫 f[3] 的指標陣列當中,f[0],f[1],f[2] 都是一個指標
- 使用: (*f[element]) (argument);
- (*f[element]) 是對指標進行反參考,所以 f[0] 對應 func1,f[1] 對應 func2,f[2] 對應 func3
- (argument) 就是傳參數進去
- 注意:上面用紅色標註的括號是不能缺少的,一定要寫
- 範例程式
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/*****************************************
Filename:Pointer8.c
Author:Willy Chen(willychen.org)
Date:2018.01.05
*****************************************/
void func1(int x){
printf("1:%d\\n",x);
}
void func2(int y){
printf("2:%d\\n",y);
}
void func3(int z){
printf("3:%d\\n",z);
}
int main(){
void (*f\[3\]) (int) = {func1, func2, func3};
int input = 100;
(*f\[0\])(input);
(*f\[1\])(input);
(*f\[2\])(input);
return 0;
}1
2
31:100
2:100
3:100