# 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));
```