# pointer 指標 > 2022/10/27、2022/11/10 C語言課程筆記 ```cpp= int a = 100; int *ptr; ptr = &a; ``` (1) ptr是一指標變數(pointer variable) (2) ptr指向某一變數位址上 (3) 經由`*ptr`得到a變數的值 (4) 指標變數只能接收位址(&...) ```cpp= int a = 100; int *ptr = &a; ``` **address(位址)** 1. address以&開頭 2. ptr指向某一變數位址上,因此ptr也是address 將上述程式的每一變數用printf()列出: ```cpp a = 100 &a = 62fe1c &ptr = 62fe10 ptr = 62fe1c *ptr = 100 ``` ## ptr指標改變指向之變數 ```cpp= #include <stdio.h> int main() { int a = 100; int *ptr; ptr = &a; printf("a = %d\n", a); printf("&a = %x\n", &a); printf("&ptr = %x\n", &ptr); printf("ptr = %x\n", ptr); printf("*ptr = %d\n", *ptr); printf("\n\n"); int b = 2000; ptr = &b; printf("b = %d\n", b); printf("&b = %x\n", &b); printf("&ptr = %x\n", &ptr); printf("ptr = %x\n", ptr); printf("*ptr = %d\n", *ptr); return 0; } ``` 會印出: ```cpp a = 100 &a = 62fe1c &ptr = 62fe10 ptr = 62fe1c *ptr = 100 b = 2000 &b = 62fe0c &ptr = 62fe10 ptr = 62fe0c *ptr = 2000 ``` 可以看出ptr的value其指向位址從`&a`改變到`&b`, 並且ptr有自己的位址,不會改變。 ## Call by Value傳值呼叫 ```cpp= void change(int x, int y); int main() { int a=100, b=200; printf("before change:a=%d, b=%d \n", a, b); change(a, b); printf("after change:a=%d, b=%d \n", a, b); return 0; } void change(int x, int y) { int temp; temp = x; x = y; y = temp; } ``` 這個例子裏得到的結果: ```cpp before change:a=100, b=200 after change:a=100, b=200 ``` 可以看出在經過`change()`之後,a和b卻都沒有改變。 這就是call by value造成的結果, 事實上`change()`是有在運作的: 在`change()`裡,`int x, int y`call by value把a, b的值拿過來了,此時x=a, y=b,`change()`也把x,y的value互換了。 但是a,b和x,y並沒有關係,因此a,b經過`change()`沒有改變。 ## Call by Address傳址呼叫 ```cpp= void change(int *x, int *y); int main() { int a=100, b=200; printf("before change:a=%d, b=%d \n", a, b); change(&a, &b); printf("after change:a=%d, b=%d \n", a, b); return 0; } void change(int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; } ``` 用`int*`(int型的指標)來接a, b的位址,在`change()`裡交換a, b的位址,如此一來,a, b就能真正地交換。 ## Array與address ```cpp= int main() { int data[] = {0, 1, 2, 3, 4}; int i; for(i=0; i<5; i++) { printf("data[%d] = %d \n",i , data[i]); } for(i=0; i<5; i++) { printf("&data[%d] = %x \n",i , &data[i]); } for(i=0; i<5; i++) { printf("data+%d = %x \n",i , data+i); } } ``` 這個程式的執行結果: ```cpp data[0] = 0 data[1] = 1 data[2] = 2 data[3] = 3 data[4] = 4 &data[0] = 62fe00 &data[1] = 62fe04 &data[2] = 62fe08 &data[3] = 62fe0c &data[4] = 62fe10 data+0 = 62fe00 data+1 = 62fe04 data+2 = 62fe08 data+3 = 62fe0c data+4 = 62fe10 ``` 從第二個迴圈可以看見array裡的每一個數相差4,就是因為一個`int`用4個bytes存。(`double`為8個bytes) 並且我們發現第二、三個迴圈的結果一模一樣,因為`data == &data[0]`, 然後在位址上的「+1」就等於「+一個單位」,所以第二、三個迴圈得到的結果才會一模一樣。 **data == &data[0]** ```cpp= int *ptr = data; for(i=0; i<5; i++) { printf("*(ptr+%d) = %d \n",i , *(ptr+i)); } ``` 會得到: ```cpp *(ptr+0) = 0 *(ptr+1) = 1 *(ptr+2) = 2 *(ptr+3) = 3 *(ptr+4) = 4 ``` 因此可知`ptr`指向`data[0]`的位址, 而`*ptr`會是`data[0]`的value, `*(ptr+1)`會是`data[1]`的value,以此類推。 ## Example I ```cpp= #include <stdio.h> int main() { int k[] = {10,20,30,40,50}; int *ptr = k; printf("k = %x\n", k);//用%x印出address printf("&k[0] = %x\n", &k[0]); printf("ptr = %x\n", ptr); printf("k[0] = %d\n", k[0]); printf("*ptr = %d\n", *ptr); return 0; } ``` 得到的結果會是: ```cpp k = 62fe00 &k[0] = 62fe00 ptr = 62fe00 k[0] = 10 *ptr = 10 ``` 假設再加上這段程式: ```cpp= ptr = k+1; printf("k+1 = %x\n", k+1); printf("&k[1] = %x\n", &k[1]); printf("ptr = %x\n", ptr); printf("k[1] = %d\n", k[1]); printf("*ptr = %d\n", *ptr); ``` 會得到: ```cpp k+1 = 62fe04 &k[1] = 62fe04 ptr = 62fe04 k[1] = 20 *ptr = 20 ``` 所以可以整理出以下幾點: (1)用`%x`印出address (2)`*ptr`可以接address -`ptr`會等於接到的adress -`*ptr`可以解鎖那個adress的value (3)`&`代表adress (4)`data` ==` &data[0]` ## Example II ```cpp= int k[] = {10,20,30,40,50}; int *ptr = k; printf("*k = %d\n", *k); printf("ptr[0] = %d\n", ptr[0]); ``` 會得到: ```cpp *k = 10 ptr[0] = 10 ``` (1)`k`是一個指標常數(不能用++、- -變動) (2)`ptr`是一個指標變數 **指標位置會變動** ```cpp= ptr = k+2; printf("ptr = %x\n", ptr); printf("ptr[0] = %d\n", ptr[0]); ptr++; printf("ptr = %x\n", ptr); printf("&k[3] = %x\n", &k[3]); printf("k[3] = %d\n", k[3]); printf("ptr[0] = %d\n", ptr[0]); printf("\n\n"); printf("ptr[1] = %d\n", ptr[1]); printf("ptr[-1] = %d\n", ptr[-1]); ``` 可以得到: ```cpp ptr = 62fe08 ptr[0] = 30 ptr = 62fe0c &k[3] = 62fe0c k[3] = 40 ptr[0] = 40 ptr[1] = 50 ptr[-1] = 30 ``` 再來加上一些程式: ```cpp= ptr+1; printf("ptr[0] = %d\n", ptr[0]); printf("*(ptr)+1 = %d\n", *(ptr)+1); printf("*(ptr+1) = %d\n", *(ptr+1)); printf("*(k+1) = %d\n", *(k+1)); ``` 會得到: ```cpp ptr[0] = 40 *(ptr)+1 = 41 *(ptr+1) = 50 *(k+1) = 20 ``` ※可以注意到第一行的`ptr+1`是無效的,因為沒有正確賦予`ptr`值,所以`ptr`仍然停留在前面+2再++的`k[3]`adress。 **`*(a+i)` == `a[i]` == `*(ptr+i)` == `ptr[i]`** 是為value。 ## 二維指標 ```cpp= int k2[][3]={10,20,30,40,50,60}; ={{10,20,30},{40,50,60}}; ``` **※行數一定要給,列數可以不給。** |k2[][0]|k2[][1]|k2[][2]| | -- | -- | -- | | 10 k2[0][0]| 20 k2[0][1]| 30 k2[0][2]| | 40 k2[1][0]| 50 k2[1][1]| 60 k2[1][2]| (1)`k2` == `&k2[0][0]` (2)`k2+1` == `&k2[1][0]`(加一列) (3)`k2[0]+1` = `&k2[0][1]`(加一行) (4)二維陣列的指標,要有兩個`[]`,兩個`*`,或是一個`[]`一個`*`,才會是value。 以下為範例: ```cpp= int i,j; for(i=0; i<2; i++) { for(j=0; j<3; j++) { printf("&k2[%d][%d] = %x\n",i,j,&k2[i][j]); } } printf("\n\n"); printf("k2 = %x\n",k2); printf("k2[0]=%x\n", k2[0]); printf("\n\n"); printf("k2+1 = %x\n",k2+1); printf("k2[0]+1=%x\n", k2[0]+1); ``` 可以得出: ```cpp &k2[0][0] = 62fdd0 &k2[0][1] = 62fdd4 &k2[0][2] = 62fdd8 &k2[1][0] = 62fddc &k2[1][1] = 62fde0 &k2[1][2] = 62fde4 k2 = 62fdd0 k2[0]=62fdd0 k2+1 = 62fddc k2[0]+1=62fdd4 ``` 最後: ```cpp= printf("*k2 = %x\n", *k2); printf("*k2[0] = %d\n", *k2[0]); printf("**k2 = %d\n", **k2); printf("k2[0][0] = %d\n", k2[0][0]); ``` 會得出: ```cpp *k2 = 62fdd0 *k2[0] = 10 **k2 = 10 k2[0][0] = 10 ``` ## Example III ```cpp= int a = 100; int *p = &a; int **q =&p; ``` `*p`接收了`&a` `*q`先拿到了`&p`,也就是一個address,直 ```cpp= #include <stdio.h> int main() { int a = 100; int *p = &a; int **pp = &p; int ***ppp = &pp; printf("&a = %p \n", &a); printf("a = %d \n", a); printf("&p = %p \n", &p); printf("p = %p \n", p); printf("*p = %d \n", *p); printf("&pp = %p \n", &pp); printf("pp = %p \n", pp); printf("*pp = %p \n", *pp); printf("**pp = %d \n", **pp); printf("&ppp = %p \n", &ppp); printf("ppp = %p \n", ppp); printf("*ppp = %p \n", *ppp); printf("**ppp = %p \n", **ppp); printf("***ppp = %d \n", ***ppp); return 0; } ``` ```cpp &a = 000000000062FE1C a = 100 &p = 000000000062FE10 p = 000000000062FE1C *p = 100 &pp = 000000000062FE08 pp = 000000000062FE10 *pp = 000000000062FE1C **pp = 100 &ppp = 000000000062FE00 ppp = 000000000062FE08 *ppp = 000000000062FE10 **ppp = 000000000062FE1C ***ppp = 100 ``` ## 在二維陣列裡抓出value的辦法 ```cpp= int arr[][4] ={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int *p[3] = {arr[0],arr[1],arr[2]}; int **pp = p; printf("arr[2][1] = %d \n", arr[2][1]); printf("*(p[2]+1) = %d \n", *(p[2]+1)); printf("*(*(p+2)+1) = %d \n", *(*(p+2)+1)); printf("*(*(pp+1)+2) = %d \n", *(*(pp+1)+2)); ``` ```cpp arr[2][1] = 10 *(p[2]+1) = 10 *(*(p+2)+1) = 10 *(*(pp+1)+2) = 7 ``` ```cpp= int a[] = {10,20,30,40,50}; int *p[] = {a,a+1,a+2,a+3,a+4}; int **pp = p; printf("*(a+2) = %d\n", *(a+2)); printf("*p[2] = %d\n", *p[2]); printf("*(*(p+2)) = %d\n", *(*(p+2))); ``` ```cpp *(a+2) = 30 *p[2] = 30 *(*(p+2)) = 30 ``` ## Example IV ```cpp= char *arr[4] = {"department", "of", "information", "management"}; printf("arr[2][5] = %c \n", arr[2][5]); printf("*(arr[2]+5) = %c \n", *(arr[2]+5)); printf("*(*(arr+2)+5) = %c \n", *(*(arr+2)+5)); printf("str[2]+7 = %s \n", arr[2]+7); printf("*(str+2)+7 = %s \n", *(arr+2)+7); int i; for(i=2; i<6; i++) { printf("%c", *(*arr+i)); } ``` ```cpp arr[2][5] = m *(arr[2]+5) = m *(*(arr+2)+5) = m str[2]+7 = tion *(str+2)+7 = tion part ``` 有bug ```cpp= int a = {10,20,30,40,50}; int *p[] = {a, a+1, a+2, a+3, a+4}; printf("%d",a[3]); printf("%d",*(a+3)); printf("%d",*(p[3])); printf("%d",**(p+3)); ```