指標及一維陣列在不少的書籍,我們都可以看到可以把陣列看成指標,這不完全正確,但在實作上也不能說完全不正確本質上陣列名稱代表的是一個位址, ...
指標及一維陣列在不少的書籍,我們都可以看到可以把陣列看成指標,這不完全正確,但在實作上也不能說完全不正確
本質上陣列名稱代表的是一個位址,而指標代表的是位址的位址,因此在宣告上是不相等的,例如你在某一個地方宣告了inta[10],而在其他地方想extern進來,但如果使用的是extern*a,那會compileerror,因為位址和位址的位址並不一樣再來如果a[10]真的和*a是一樣的,那sizeof(a)就會應該是4
那為什麼我們在實際使用上結果會是一樣的呢呢?下面這個例子都會印出20
inta[]={10,20,30};
printf("%d",a[1]);
printf("%d",*(a+1));
那是因為陣列在compiler階段都會被轉成指標,當看到a[1]的時候就從a的位址加上1個integer的size,如果看到*(a+1)那行為會一樣差別只在如果compiler知道a是陣列那會忽略’*’和’&’也就是不會作dereference,這樣也可以解釋為什麼下面這情況compiler認為是合法的
intb[3]={10,20,30};
b[99]=40;
那在什麼狀況下會完全相等呢?只有在傳陣列參數到函式的時候,以下三種情況compiler編出來會一模一樣,事實上在傳陣列到函式裡面時,真正傳的是指標並不是整份陣列複製過去
func(int*verctor){...};
func(intverctor[]){...};
func(intverctor[10]){...};
試著想一下以下這段程式碼會印出什麼
#include
charga[2]={'a','b'};
voidfunc_in_vec(charca[2])
{
printf("sizeofca:%ld\n",sizeof(ca));
printf("&ca:%p\n",&ca);
printf("&(ca[0]):%p\n",&(ca[0]));
printf("&(ca[1]):%p\n",&(ca[1]));
printf("\n");
}
voidfunc_in_ptr(char*pa)
{
printf("sizeofpa:%ld\n",sizeof(pa));
printf("&pa:%p\n",&pa);
printf("&(pa[0]):%p\n",&(pa[0]));
printf("&(pa[1]):%p\n",&(pa[1]));
printf("\n");
}
intmain(void)
{
printf("sizeofga:%ld\n",sizeof(ga));
printf("&ga:%p\n",&ga);
printf("ga:%p\n",ga);
printf("&(ga[0]):%p\n",&(ga[0]));
printf("&(ga[1]):%p\n",&(ga[1]));
printf("\n");
func_in_vec(ga);
func_in_ptr(ga);
return0;
}
結果如下(有可能在不同平台會有不同結果,這邊是在x64平台的結果,不過概念是一樣的)
sizeofga:2-------------(1)
&ga:0x601048------------(2)
ga:0x601048-------------(3)
&(ga[0]):0x601048-------(4)
&(ga[1]):0x601049-------(5)
sizeofca:8-------------(6)
&ca:0x7fffd7b1c718------(7)
&(ca[0]):0x601048-------(8)
&(ca[1]):0x601049-------(9)
sizeofpa:8-------------(10)
&pa:0x7fffd7b1c718------(11)
&(pa[0]):0x601048-------(12)
&(pa[1]):0x601049-------(13)
由(1)可看出ga的型別為2byte的陣列,代表不直接相等指標(2)(3)可看出&ga=ga,代表雖然compiler會將陣列轉成指標,但會忽略’*’和’&’,(6)(8)可看出若經由funtion傳入參數後皆轉為指標,因此取sizeof為8(64位元平台)
指標及二維陣列(矩陣)在現實生活上我們有二維陣列的概念,用來作運算或儲存各種資料,但是在記憶體裡是如何儲存這些資料?記憶體只是一大塊連續的位址空間,如何實現二維陣列的概念?
事實上在記憶體裡面二維陣列就是陣列的陣列,而三維陣列則是陣列的陣列的陣列,依此類推
舉個例子來說,一個[3][2]的陣列代表的是有一個大小3的陣列裡面有大小2的陣列,共6個,參考下圖即可清楚看出,裡面的數字代表的就是程式取值時需給的二維陣列位址,橘色代表的是第一層陣列,藍色代表第二層陣列(陣列的陣列)
試著想一下以下這段程式碼會印出什麼
intmain(void)
{
inta[3][2]={{10,20},{30,40},{50,60}};
int*b=a[0];
printf("a[0][0]=%d\n",a[0][0]);
printf("a[0][1]=%d\n",a[0][1]);
printf("a[1][1]=%d\n",a[1][1]);
printf("a[2][1]=%d\n",a[2][1]);
printf("*(b+0)=%d\n",*(b+0));
printf("*(b+1)=%d\n",*(b+1));
printf("*(b+3)=%d\n",*(b+3));
printf("*(b+5)=%d\n",*(b+5));
return0;
}
結果如下
a[0][0]=10---(1)
a[0][1]=20---(2)
a[1][1]=40---(3)
a[2][1]=60---(4)
*(b+0)=10---(5)
*(b+1)=20---(6)
*(b+3)=40---(7)
*(b+5)=60---(8)
從下圖可看出此段程式將b指向第一層陣列a[0]的位址,搭配下圖和以上的結果可清楚看出(1)=(5)、(2)=(6)、(3)=(7)、(4)=(8),也可看出記憶體擺放的位址和二維陣列的關係
指標及三維陣列了解指標與陣列關係之後,我們可以來看更為抽象的三維以上的陣列,事實上如果能轉換成記憶體實際擺放的位址來看,也就不會覺得抽象了,假如有一個a[2][3][4]的三維陣列,那在記憶體擺放的情形如下,橘色代表第一維陣列,藍色代表第二維陣列,綠色代表第三維陣列,因此此陣列為一個大小為2的陣列裡面有大小為3的陣列裡面有大小為4的陣列,共24個
試著想一下以下這段程式碼會印出什麼
intmain(void)
{
inta[2][3][4]={0};
int*b=a[0][0];
inti,j,k;
for(i=0;i<2;i++)
for(j=0;j<3;j++)
for(k=0;k<4;k++)
a[i][j][k]=i+j+k;
printf("a[0][0][0]=%d\n",a[0][0][0]);
printf("a[0][0][2]=%d\n",a[0][0][2]);
printf("a[0][1][1]=%d\n",a[0][1][1]);
printf("a[0][2][3]=%d\n",a[0][2][3]);
printf("a[1][0][0]=%d\n",a[1][0][0]);
printf("a[1][2][2]=%d\n",a[1][2][2]);
printf("*(b+0)=%d\n",*(b+0));
printf("*(b+2)=%d\n",*(b+2));
printf("*(b+5)=%d\n",*(b+5));
printf("*(b+11)=%d\n",*(b+11));
printf("*(b+12)=%d\n",*(b+12));
printf("*(b+22)=%d\n",*(b+22));
return0;
}
結果如下
a[0][0][0]=0
a[0][0][2]=2
a[0][1][1]=2
a[0][2][3]=5
a[1][0][0]=1
a[1][2][2]=5
*(b+0)=0
*(b+2)=2
*(b+5)=2
*(b+11)=5
*(b+12)=1
*(b+22)=5
從下圖可看出三維陣列和記憶體的關係,將指標b指到三維陣列的頭,四維以上的陣列和二維三維陣列的原理一樣,可以此類推
接下來我們可以看一下不同type的指標和陣列的關係,首先先看int的指標,試著想一下以下這段程式碼會印出什麼
intmain(void)
{
inta[2][3][4]={0};
int*b=a[0][0];
int*c=a[0][2];
int*d=a[1][1];
inti,j,k;
intcnt=0;
for(i=0;i<2;i++)
for(j=0;j<3;j++)
for(k=0;k<4;k++){
a[i][j][k]=cnt;
cnt++;
}
printf("b=%p,b+1=%p\n",b,b+1);
printf("*(b+0)=%d,*(b+1)=%d\n",*(b+0),*(b+1));
printf("a[0][0][0]=%d,a[0][0][1]=%d\n\n",a[0][0][0],a[0][0][1]);
printf("*(c+0)=%d,*(c+6)=%d\n",*(c+0),*(c+6));
printf("a[0][2][0]=%d,a[1][0][2]=%d\n\n",a[0][2][0],a[1][0][2]);
printf("*(d+0)=%d,*(d+7)=%d\n",*(d+0),*(d+7));
printf("a[1][1][0]=%d,a[1][2][3]=%d\n\n",a[1][1][0],a[1][2][3]);
return0;
}
結果如下
b=0x7fffedac8880,b+1=0x7fffedac8884
*(b+0)=0,*(b+1)=1
a[0][0][0]=0,a[0][0][1]=1
*(c+0)=8,*(c+6)=14
a[0][2][0]=8,a[1][0][2]=14
*(d+0)=16,*(d+7)=23
a[1][1][0]=16,a[1][2][3]=23
b因為指到的是inttype,所以b和b+1的差距為4byte
b,c,d皆為指到int的指標,因此可指到此三維陣列的第三維陣列,大小為4(藍色框住的綠色部份)
b指到a[0][0]的大小為4的陣列,因此*(b+0)=a[0][0][0],*(b+1)會加一個intsize(4byte)之後取值所以*(b+1)=a[0][0][1]
c指到a[0][2]的大小為4的陣列,因此*(c+0)=a[0][2][0],*(c+6)會加六個intsize(4byte)之後取值所以*(c+6)=a[1][0][2]
d指到a[1][1]的大小為4的陣列,因此*(d+0)=a[1][1][0],*(d+7)會加七個intsize(4byte)之後取值所以*(d+7)=a[1][2][3]
再來看int[]的指標,試著想一下以下這段程式碼會印出什麼
intmain(void)
{
inta[2][3][4]={0};
int(*b)[4]=a[0];
int(*c)[4]=a[1];
inti,j,k;
intcnt=0;
for(i=0;i<2;i++)
for(j=0;j<3;j++)
for(k=0;k<4;k++){
a[i][j][k]=cnt;
cnt++;
}
printf("b=%p,b+1=%p\n",b,b+1);
printf("(*(b+0))[0]=%d,(*(b+1))[0]=%d\n",(*(b+0))[0],(*(b+1))[0]);
printf("a[0][0][0]=%d,a[0][0][1]=%d\n\n",a[0][0][0],a[0][1][0]);
printf("(*(b+2))[2]=%d,(*(b+4))[3]=%d\n",(*(b+2))[2],(*(b+4))[3]);
printf("a[0][2][2]=%d,a[1][1][3]=%d\n\n",a[0][2][2],a[1][1][3]);
printf("(*(c+1))[1]=%d,(*(c+2))[2]=%d\n",(*(c+1))[1],(*(c+2))[2]);
printf("a[1][1][1]=%d,a[1][2][2]=%d\n\n",a[1][1][1],a[1][2][2]);
return0;
}
結果如下
b=0x7fff2c1a96c0,b+1=0x7fff2c1a96d0
(*(b+0))[0]=0,(*(b+1))[0]=4
a[0][0][0]=0,a[0][1][0]=4
(*(b+2))[2]=10,(*(b+4))[3]=19
a[0][2][2]=10,a[1][1][3]=19
(*(c+1))[1]=17,(*(c+2))[2]=22
a[1][1][1]=17,a[1][2][2]=22
b因為是指到int[4]的指標因此b和b+1的差距為16byte(4byte(int)*4(size))
b,c,d皆為指到int[4]的指標,因此可指到此三維陣列的第二維陣列,大小為3(橘色框住的藍色部份)
b指到a[0]的大小為3的陣列,因此(*(b+0))[0]=a[0][0][0],*(b+1)會加四個intsize(16byte)之後取值所以(*(b+1))[0]=a[0][1][0],*(b+2)會加八個intsize(32byte)之後取值所以(*(b+2))[2]=a[0][2][2],*(b+4)會加十六個intsize(64byte)之後取值所以(*(b+4))[3]=a[1][1][3]
c指到a[1]的大小為4的陣列,因此(*(c+1))[1]=a[1][1][1],*(c+2)會加八個intsize(32byte)之後取值所以(*(c+2))[2]=a[1][2][2]
再來看int[][]的指標,試著想一下以下這段程式碼會印出什麼
intmain(void)
{
inta[2][3][4]={0};
int(*b)[3][4]=a;
inti,j,k;
intcnt=0;
for(i=0;i<2;i++)
for(j=0;j<3;j++)
for(k=0;k<4;k++){
a[i][j][k]=cnt;
cnt++;
}
printf("b=%p,b+1=%p\n",b,b+1);
printf("(*(b+0))[0][0]=%d,(*(b+0))[0][2]=%d\n",(*(b+0))[0][0],(*(b+0))[0][2]);
printf("a[0][0][0]=%d,a[0][0][2]=%d\n\n",a[0][0][0],a[0][0][2]);
printf("(*(b+0))[2][1]=%d,(*(b+0))[2][3]=%d\n",(*(b+0))[2][1],(*(b+0))[2][3]);
printf("a[0][2][1]=%d,a[0][2][3]=%d\n\n",a[0][2][1],a[0][2][3]);
printf("(*(b+1))[0][1]=%d,(*(b+1))[2][3]=%d\n",(*(b+1))[0][1],(*(b+1))[2][3]);
printf("a[1][0][1]=%d,a[1][2][3]=%d\n\n",a[1][0][1],a[1][2][3]);
return0;
}
結果如下
b=0x7fff1604c440,b+1=0x7fff1604c470
(*(b+0))[0][0]=0,(*(b+0))[0][2]=2
a[0][0][0]=0,a[0][0][2]=2
(*(b+0))[2][1]=9,(*(b+0))[2][3]=11
a[0][2][1]=9,a[0][2][3]=11
(*(b+1))[0][1]=13,(*(b+1))[2][3]=23
a[1][0][1]=13,a[1][2][3]=23
b因為是指到int[3][4]的指標因此b和b+1的差距為48byte(4byte(int)(34)(size))
b,c,d皆為指到int[3][4]的指標,因此可指到此三維陣列的第一維陣列,大小為3*4(橘色部份)
b指到a的大小為34的陣列,因此(\(b+0))[0][0]=a[0][0][0],(*(b+0))[0][2]=a[0][0][2],(*(b+0))[2][1]=a[0][2][1],(*(b+0))[2][3]=a[0][2][3],*(b+1)會加十二個intsize(48byte)之後取值所以(*(b+1))[0][1]=a[1][0][1],(*(b+1))[2][3]=a[1][2][3],
文章目錄
本站概覽
IvanLin
Ivna’sBlog
19
文章
4
標籤
1.指標及一維陣列2.指標及二維陣列(矩陣)3.指標及三維陣列