---
# System prepended metadata

title: pointer 指標

---

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