抱歉,您的瀏覽器無法訪問本站
本頁面需要瀏覽器支持(啟用)JavaScript
了解詳情 >

C語言的重要功能之一:指標,以下簡單紀錄

  • 特色
  1. 傳參考(Call By Reference)
  2. 值是儲存地址(Memory Address)
  • 宣告(declaration)
1
int *ptr;
  • 初始化(initialization)
1
2
3
4
5
6
7
int num=0;

ptr = # //將num所在地址存到變數ptr當中

ptr = NULL; //ptr不會指到任何東西

ptr = 0; //和NULL一樣,但建議使用NULL
  • 反參考(dereference)

取得指標指向的記憶體中那個變數所存的值

1
printf("%d",*ptr);
  • 範例程式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*****************************************
Filename:Pointer1.c
Author:Willy Chen(willychen.org)
Date:2018.01.03
*****************************************/
#include<stdio.h>

int main(void){
int num=0;
int *ptr = &num;
printf("ptr: %p\\n",ptr); //Address of num
printf("\*ptr: %d\\n",\*ptr); //Value of num
printf("&num: %p\\n",&num); //Address of num
printf("&\*ptr: %p\\n",&\*ptr); //Address of num
return 0;
}
1
2
3
4
ptr: 0x7ffc2dc851fc
*ptr: 0
&num: 0x7ffc2dc851fc
&*ptr: 0x7ffc2dc851fc
  • 傳地址(call by reference)
  1. Function的參數都是透過傳值(call by value)
  2. 透過指標,可以「模擬」傳地址(call by reference)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*****************************************
Filename:Pointer2.c
Author:Willy Chen(willychen.org)
Date:2018.01.03
*****************************************/
#include<stdio.h>
void square(int *ptr); //prototype

int main(void){
int num=2;
printf("Origin num: %d\\n",num);
square(&num);
printf("New num: %d\\n",num);
return 0;
}

void square(int *ptr){
\*ptr = \*ptr * *ptr;
}

Origin num: 2
New num: 4
  • 指標與陣列
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:Pointer3.c
Author:Willy Chen(willychen.org)
Date:2018.01.03
*****************************************/
#include<stdio.h>

int main(){
int a\[5\]={0};
int \*ptr = &a\[0\]; //也可以寫成 int \*ptr = a;
int *ptr2 = NULL;

printf("address of a\[0\]:%p\\n",&a\[0\]);
printf("value of ptr:%p\\n",ptr); //value of ptr = the address of a\[0\]

ptr += 2;

printf("address of a\[2\]:%p\\n",&a\[2\]);
printf("value of ptr:%p\\n",ptr); //value of ptr = the address of a\[2\]

ptr2 = &a\[4\];

printf("value of ptr2-ptr:%d\\n",ptr2-ptr); //the number of array elements from ptr to ptr2

return 0;
}
1
2
3
4
5
address of a\[0\]:0x7fff77e371d0
value of ptr:0x7fff77e371d0
address of a\[2\]:0x7fff77e371d8
value of ptr:0x7fff77e371d8
value of ptr2-ptr:2

當 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;
  1. 可以使用void來宣告pointer,此pointer只存地址
  2. 此類pointer不可反參考
  3. 若要反參考,須將此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
      *****************************************/
      #include<stdio.h>

      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
      2
      s: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
      *****************************************/
      #include<stdio.h>

      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
      2
      Origin:A
      Change:B
    • constant pointer,constant data
      pointer恆指向同一地址,那個地址中的資料不可用反參考修改
      基本上只能做讀取的功能

      1
      void read( const char * const ptr)

      如傳一個 array 到 Function 中時,Function中只能對此 array 做讀取的動作

    • 簡單整理一下
      當有 const 在 * 左邊時,代表這個 pointer 指向地址存的資料不可更動,如

      1
      2
      const 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
      *****************************************/
      #include<stdio.h>

      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
      8
      size 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
      *****************************************/
      #include<stdio.h>

      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
      6
      array\[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
      *****************************************/
      #include<stdio.h>

      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
      3
      1:100
      2:100
      3:100

評論




本站使用 Volantis 作為主題