① C語言中指針引用二維數組元素的問題
下面是本人文庫中的文章,關於二維數組與指針的講解。
1、兩條基本准則:
a、首先要明白,指針運算符的作用,我用一言以概之,你在哪裡使用都不會錯。指針運算符*的作用是求出*後面所指地址里的值。因此只要*後面的變數表示的是一個地址就可以使用*運算符,來求出這個地址中的值,你不用管這個地址的表示形式是怎樣的,只要是地址就可以使用*來求出地址中的值。
b、[ ]這個運算符的的運演算法則是,把左側的地址加上[ ]內的偏移量然後再求指針運算,注意有[ ]運算符的地方就有個隱含的指針,比如x[2]表示的就是將指針x偏移2個單位量後再求指針運算。也就說x[2]與*(x+2)是相等的。
2、對二維數組的講解:
a、對一維數組地址的詳細講解:
比如一維數組a[5],眾所周知,一維數組的數組名a表示的是第一個元素a[0]的地址,也就是說數組名與&a[0]是等價的,因此數組名a的地址,並不是這個一維數組的數組的地址。那麼&a,表示的又是什麼呢?因為,a是一個一維數組,所以&a表示的就是這個一維數組的地址,也就是說&a中的地址是一個包含有4個元素的一維數組的地址。就好比int i中的&i,才表示的是這個變數i的地址一樣。
b、對二維數組地址的講解:
比如二維數組b[3][4],我們首先從一維開始分析,眾所周知b[0],b[1]分別表示的是二維數組中第一行第一個元素和第二行第二個元素的地址,也就是說b[0]是與&b[0][0]等價的,b[1]是與&b[1][0]等介的。因此數組名就與&b[0]等介的,也就是說數組名表示的是二維數組中第一行所包含的一維數組的地址,說簡單一點,就是說二維數組名是二維數組中第一行的行地址。因此二維數組名b所包含的地址中包含有二維數組中第二維中元素的個數的一維數組,也就是b的地址中包含一個含有4個元素的一維數組的地址(也就是所謂的數組的數組了)。
c、對二維數組中地址的相加運算的講解:
同樣以b[3][4]為例來講解,在上面講到b[0]表示的是&b[0][0],因此對b[0]進行相加運算,比如b[0]+1,那麼就將使地址偏移一個單位,也就是地址被偏移到了&b[0][1]處,也就是b[0]+1表示的是b[0][1]的地址。上面也講到數組名b,表示的是一個一維數組的地址,因此對數組名進行偏移,比如b+1,則將使指針偏移一個一維數組的長度,也就是b+1,將是&b[1]的地址,因此b+1的地址,表示的是二維數組中第二行所包含的一維數組的地址,簡單點就是第二行的行地址。
d、對二維數組的指針運算:
*b
在上面講解過,因為b表示的是二維數組中第一行所包含的一維數組的地址,因此*b=*(b+0)=*(&b[0])=b[0],所以*b表示的是二維數組中第一行第一個元素的地址,即*b=&b[0][0],用語言來描術*(b+0)就是,把數組名的地址偏移0個單位,然後再求這個地址所包含的值。在二維數組中,這個值就是指的b[0],因此這個值是與b[0][0]的地址相等的,結果就是*(b+0)與b是相等的,這在多維數組中是個怪現象,至少本人無法理解這是為什麼。因為對同一個地址,進行指針運算得到了不同的結果,比如*b和*b[0],因為b和b[0]都是相同的地址,但對他們進行指針運算卻得到了不同的結果,*b得到了&b[0][0]的地址,而*b[0]得到了b[0][0]的值,這是對同一個地址進行指針運算卻得到了不同的值,對於這個問題,無法理解。
*(b+1)和*(b+0)
對於*(b+1)也和*(b+0)是同樣的道理,*(b+1)=b[1]。我們再來看*b[1],因為*b[1]=*(b[1]+0)=*(&b[1][0])=b[1][0],可以看出,這就是二維數組中第二行第一個元素的地址。
*(*(b+1)+1)
因為*(*(b+1)+1)=*(*(&b[1])+1)=*(b[1]+1)=*(&b[1][0]+1)=*(&b[1][1])=b[1][1],語言描術就是,b+1使地址偏移到了二維數組中第二行所包含的一維數組的地址(或第二行的行地址),然後再對這個行地址求指針(或求值)運算,因此就得到第二行第一個元素的地址,然後再對這個地址偏移一個單位,就得到第二行第二個元素的地址,再對這個地址進行指針運算,就得到了這個元素的值,即b[1][1],其他的內容可以以止類推。
e、對二維數組的指針和[ ]的混合運算
在下面的指針和[ ]的混合計算中,要記住兩點關鍵法則,記住了這兩點在哪裡計算都不會出錯
a、對於像b[1]這樣的地址,最好應表示為&b[1][0]再進行偏移計算,比如對於b[1]+1,這不是直接在對b[1]加1,也就是b[1]+1不等於b[2],因為b[1]表示的是第二行行1個元素的地址,對其加1,應該表示的是第二行第二個元素的地址,也就是&b[1][1],而b[2]則表示的是第二行第一個元素的地址,因此錯誤,所以在計算時應把b[1]轉換為&b[1][0]之後,才能直接進行地址的偏移,也就是說b[1]+1=&b[1][0]+1=&b[1][1],這樣才能得到正確的結果,並且不會出錯。
b、對於有小括弧的地方,一定不要省略小括弧。比如(&b[1])[1]與&b[1][1]將表示的是不同的結果,第二個是顯然的,對於第一個(&b[1])[1]=*((&b[1])+1)=*(&b[1]+1)=*(&b[2])=b[2],可以看到,表示的是第3行第1個元素的地址,因此這兩個的結果是顯然不一樣的。因此對於(b+1)[1]這樣的運算,不能省略小括弧,即(b+1)[1]=(&b[1])[1]=*((&b[1])+1)=*(&b[1]+1)=*(&b[2])=b[2],如果省略了小括弧,則是(b+1)[1]=&b[1][1],這將是不易發現的錯誤。因此這是兩個完完全全不同的符案。
c、總結,指針和[ ]混合運算2點關鍵,
第1:應把是地址的[ ]運算,轉換為地址的形式,比如b[1]應轉換為&b[1][0]。因為只有這樣才能進行直接的地址相加運算,即&b[1][0]+1=&b[1][1],而b[1]+1不等於b[2]。
第2:有小括弧的地方不能省略小括弧,如(b+1)[1]=(&b[1])[1]=*((&b[1])+1)=*(&b[1]+1)=*(&b[2])=b[2],也&b[1][1]是完全不同的。
(*(b+1))[1] ,(*b)[1]
最簡單的理解方法為*(b+1)和語句b[1]等價,即(*(b+1))[1]和語句b[1][1]是相同的,也就是二組數組第2行第2個元素的值b[1][1],理解方法2逐條解釋,如上面的解釋*(b+1)表示的是二維數組b的第二行第一個元素的地址,也就是b[1],然後再與後面的[1]進行運算,就得到b[1][1]。或者(*(b+1))[1]=*((*(b+1))+1)=*(*(b+1)+1)這個語句上面解釋過。同理(*b)[1]=b[0][1]
*(b+1)[1]:
計算方法1把[ ]分解為指針來計算:因為[ ]運算符高於指針,因此應先計算[ ]再計算指針,因為[1]表示的是把左側的地址偏移1個單位,再求指針,因此(b+1)[1]=*((b+1)+1),最後再計算一次指針運算,也就是*(b+1)[1]=**((b+1)+1)=**(b+2)=*(*(b+2))=*b[2]=b[2][0],可以看到,最後表示的是b中第3行第一個元素的值。
計算方法2把指針化為[ ]來計算:*(b+1)[1]=*(&b[1])[1]=*(*(&b[1]+1))=**(&b[2])=*b[2]=b[2][0],注意*((&b[1])[1])表達式中應把(&b[1])括起來,若不括起來,則[ ]運算符的優先順序高於&運算符,因此(&b[1])[1]與&b[1][1]是不一樣的,後一個表示的是第二行第二個元素的地址,而頭一個(&b[1])[1]則表示的是,對b的第二行的行地址偏移1個單位後再求指針的結果,也就是*(&b[1]+1)=*(&b[2])=b[2],所以性質是不一樣的。
(*b+1)[2]
計算方法1化簡[ ]運算符:(*b+1)[2]=*((*b+1)+2)=*(*b+3)=*(&b[0][0]+3)=*(&b[0][3])=b[0][3],這里要注意*b表示的是b[0]=&b[0][0],在計算時最好不要代入b[0]來計算,而應把b[0]轉換為&b[0][0]後再計算,因為b[0]+3,很容易被錯誤的計算為b[3],而實際上b[0]指向的是第一行第一個元素的地址,對其偏移3個單位應該是指向第一行第4個元素的地址,即&b[0][3],而b[3],則指向了第3行第1個元素的地址,這是不同的。
計算方法2化簡*運算符:(*b+1)[2]=(b[0]+1)[2]=(&b[0][0]+1)[2]=(&b[0][1])[2]=*(&b[0][1]+2)=*(&b[0][3])=b[0][3],注意,在計算過程中小括弧最好不要省略,省略了容易出錯,因為[ ]運算符的優先給更高,如果省略了,某些地方將無法計算。比如(&b[0][0]+1)[2]=(&b[0][1])[2],如果省略掉括弧,則成為&b[0][1][2],這對於二維數組來講,是無法計算的。
(*(b+1))[5]
計算方法:(*(b+1))[5]=(*(&b[1]))[5]=(b[1])[5]=*(b[1]+5)=*(&b[1][0]+5)=*(&b[1][5])=b[1][5],結果等於第二行第6個元素的值。
f、注意,在二維或者多維數組中有個怪現象,比如對於多維數組a[n][m][i][j],那麼這些地址是相同的,即數組名a, a[0], a[0][0], a[0][0][0], &a[0][0][0][0],都是相同的地址。而且對數組名依次求指針運算將得到,比如*a=a[0],*a[0]=a[0][0], *a[0][0]=a[0][0][0], *a[0][0][0]=a[0][0][0][0],可以看到,只有對最後這個地址求指針運算才真正得到了數組中的值,因此對數組名求指針運算,要得到第一個元素的值,應該****a,也就是對4維數組需要求4次指針運算。同樣可以看到,對數組名進行的前三次指針運算的值都是相同的,即*a, **a, ***a和a的值都是&a[0][0][0][0]的值,這就是這個怪問題,按理說對地址求指針應該得到一個值,但對多維數組求指針,卻得到的是同一個地址,只是這些地址所包含的內容不一樣。
3、數組指針與二維數組講解:
下面我們將以y[4]={1,2,3,4}這個一維數組為例來層層講解,指針和數組的關系。
1、數組指針:
定義形式為:int (*p)[4];表示定義了一個指向多維數組的指針,即指針p指向的是一個數組,這個數組有4個元素,對這個指針p的賦值必須是有4個int元素的數組的地址,即只要包含有四個元素的數組的地址都能賦給指針p,不管這個數組的行數是多少,但列數必須為4。即int y[4],x[22][4];都可以賦給指針p。賦值方式為p=&y或p=x,對於&y和二維數組數組名前面已講過,&y中的地址是一個包含有4個元素的一維數組的地址,二維數組名x也是一個含有4個元素的一維數組的地址,因此可以這樣賦值。而這樣賦值將是錯誤的p=y,或者p=x[0]; 因為y和x[0]的地址只包含一個元素,他們不包含一個數組,因此出錯。
2.注意()必須有,如果沒有的話則,int *p[4];則是定義了一個指針數組,表示每個數組元素都是一個指針,即p[2]=&i;指向一個int型的地址,而*p[2]則表示p[2]所指向的元素的值。
3.初始化數組指針p:
a、當把int y[4]賦給指針p時p=y將是錯誤的,正確的方式為p=&y因為這時編譯器會檢查賦給指針p的元素是否是含有四個元素的數組,如果是就能正確的賦值,但語句p=y中的y代表的是數組y[4]第一行第一列的元素的地址也就是&y[0]的地址,因此y指向的地址只有一個元素,而指針p要求的是有4個元素的數組的地址,因此語句p=y將出錯。而&y也表示的是一個地址,因為數組名y表示的是&y[0]的地址,因此&y=&(&y[0])。可以把&y理解為是數組y[4]的第一行的行地址,即&y包含了數組y[4]的第一行的所有元素,在這里&y包含有4個元素,因則p=&y才是正確的賦值方法,在這里要注意,數組的某行的行地址是第本行的第一個元素的地址是相同的。
b、把x[22][4]賦給指針p有幾種方法,方法一:p=x;我們這樣來理解該條語句,首先x[0]表示的是二維數組x[22][4]的第1行第一列元素的地址,這個地址包含一個元素,這是顯而易見的,而數組名x也表示一個地址,但這個地址包含的是一個數組(即數組的數組),這個數組是包含4個元素的數組,這4個元素就是數組x第一行的4個元素,也就是說x表示的是數組x[22][4]的第1行的行地址,即數組名x就包含了數組x[22][4]第1行的4個元素,因此這種賦值方式是正確的。這時指針p就相當於是數組名一樣,比如p[2][1]訪問的就是數組x的第3行的第2個元素。
c、方法二:p=x+1或者p=&x[1];注意必須要有地址運算符&,同理語句&x[1]表示的是數組x[22][4]第2行的行地址,因為x[1]表示的是數組x[22][4]第的第2行第1列的元素的地址,因此&x[1]表示的就是數組x的第2行的行地址,因為&x[1]這個地址包含了一個數組,這個數組的起始地址是從x[1]這個地址開始的,這,即數組x[22][4]中x[1]這一行的4個元素。在這一行中包含了4個元素。而x+1本身就是指的x[1]的地址。這時指針p的起始地址是&x[1],所以p[0][1]不再是訪問的x的第一行第二個元素,而是訪問的x的第二行第二個元素。
d、注意,再次提示,數組的某行的行地址是與本行的第一個元素的地址是相同的。
② 指針指向二維數組的幾種方法
二維數組乃至多位數組本質就是順序表,所以用只要指向首元素的指針就可以了。
另外就是使用數組指針,要注意語法聲明。
③ 我想問下關於VC一級指針指向二維數組問題
先解釋一下那個數據類型問題:
定義指針時可以這么寫int*
p此時的int*則可以理解為整形指針類型,
在C#中一維數組的定義都是int[]
p,二維的是int[,]
p以此類推,可以看出
int[]也可以和int*類似的看待,所以也可以叫做整形數組類型。所以說p和A的數據類型不同,因為p為指針類型,A為數據類型。
A是二維數組的首地址,對應於雙重指針,所以你那個p=A賦值應該是錯的,應該把*p改成**p,一維數組對就單指針。
④ C語言指針指向一維數組與二維數組
⑤ 一維數組和二維數組的一級指針
直接舉個例子:
int
p1[10];
int
p2[10][10];
p1
是就相當於&p1[0],*p1就相當於p1[0];
二維數組在c/c++就相當於一維數組的數組
所以
p2
相當於&p2[0],
*p2相當於&p2[0][0],
這時p2與*p2相等,**p2就相當於p2[0][0].
⑥ C++中編程問題,指針訪問二維數組數組
如果是*(*p+j)你就應該循環3*4了;
你那程序應該像三樓那樣寫.
⑦ 怎樣使用指針引用二維數組的元素
對於a[i][j](二維數組的大小為n×m)而言,
首先要搞清楚行指針和列指針
行指針:&a[i]或者a+i指向行,&a[i]=&*(a+i)=a+i
列指針:a[i]或*(a+i)指向列,a[i]等價於*(a+i)
元素的引用方式有如下三種方式
1.通過地址引用二維元素
*(&a[i][j]),
*(a[i]+j),
*(*(a+i)+j),
*(a[0]+m*i+j)
*(&a[0][0]+m*i+j)
(*(a+i))[j]
2.建立一個指針數組引用二維元素
int *p[3],a[3][2],i,j;
for(i=0;i<3;i++)
p[i]=a[i];//p[i]用來存放地址,a[i]為列地址
等價如下
(1) *(p[i]+j) 與*(a[i]+j)對應
(2)*(*(p+i)+j) 與*(*(a+i)+j)對應
(3)(*(p+i))[j] *(p[i]+j) 與*(a[i]+j)對應
(4)p[i][j] 與a[i][j]對應
3.建立一個行指針引用二維數組元素
int a[3][2],(*p)[2];
p=a;
(1) *(p[i]+j) 與*(a[i]+j)對應
(2)*(*(p+i)+j) 與*(*(a+i)+j)對應
(3)(*(p+i))[j] 與(*(a+i))[j]對應
(4)p[i][j] 與a[i][j]對應
例題如下
1.
#include<stdio.h>
main()
{
int score[][4]={{60,70,80,90},{56,89,67,88},{34,78,90,66}};
int i,j;
printf("輸入學生號:0-2");
scanf("%d",&i);
printf("the score of No.%d are:\n",i);
for(j=0;j<4;j++)
printf("%d\t",*(*(score+i)+j));//score+i為列指針,*(score+i)為行指針
printf("\n");
}
2.
#include<stdio.h>
main()
{
int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int *p;
for(p=a[0];p<a[0]+12;p++)//使p依次指向下一個元素,a[i]和*(a+i)是指向列的指針;&a[i]或a+i是指向行的指針
{
if((p-a[0])%4==0)printf("\n");
printf("%4d",*p);//輸出p指向的數組元素的值
}
printf("\n");
}
3
#include<stdio.h>
main()
{
int score[][4]={{60,70,80,90},{56,89,67,88},{34,78,90,66}};
int i,j;
printf("輸入學生號:0-2");
scanf("%d",&i);
printf("the score of No.%d are:\n",i);
for(j=0;j<4;j++)
printf("%d\t",*(score[i]+j));
printf("\n");
}
4
#include<stdio.h>
main()
{
int score[][4]={{60,70,80,90},{56,89,67,88},{34,78,90,66}};
int i,j,*p;
printf("輸入學生號:");
scanf("%d",&i);
printf("the score of No.%d are:\n",i);
for(p=score[i];p<score[i]+4;p++)
printf("%d\t",*p);//p+i指向第i行,*(p+i)指向第i行0列元素*(p+i)+j指向第i行j列元素,是列地址
printf("\n");
}
5.
#include<stdio.h>
main()
{
int score[][4]={{60,70,80,90},{56,89,67,88},{34,78,90,66}};
int i,j,*p;
printf("輸入學生號:");
scanf("%d",&i);
printf("the score of No.%d are:\n",i);
for(p=score[i],j=0;j<4;j++)
printf("%d\t",*(p+j));
printf("\n");
}
6
#include<stdio.h>
main()
{
int score[][4]={{60,70,80,90},{56,89,67,88},{34,78,90,66}};
int i,j,(*p)[4];//指針變數p指向包括4個整型元素的一維數組;
p=score;//p指向二維數組0行元素,p+1所指向的元素是p所指向元素的下一行元素;
printf("輸入學生號:0-2");
scanf("%d",&i);
printf("the score of No.%d are:\n",i);
for(j=0;j<4;j++)
printf("%d\t",*(*(p+i)+j));//p+i指向第i行,p是行指針,*(p+i)指向第i行0列元素,是列指針。*(p+i)+j指向第i行j列元素,是一個元素的地址
printf("\n");
}
⑧ 我想問下關於VC一級指針指向二維數組問題
先解釋一下那個數據類型問題:
定義指針時可以這么寫int* p此時的int*則可以理解為整形指針類型,
在C#中一維數組的定義都是int[] p,二維的是int[,] p以此類推,可以看出
int[]也可以和int*類似的看待,所以也可以叫做整形數組類型。所以說p和A的數據類型不同,因為p為指針類型,A為數據類型。
A是二維數組的首地址,對應於雙重指針,所以你那個p=A賦值應該是錯的,應該把*p改成**p,一維數組對就單指針。
⑨ C語言 怎麼用指針輸出一個二維數組的全部值
C語言的數組(不管多少維)在內存中都是線性儲存的。所以用一級指針加偏移就可以訪問所有元素。
舉個例子,有一個10*10的二維數組a,這樣就可以輸出:
inta[10][10];
int*p=(int*)a;
inti;
for(i=0;i<10*10;i++)
printf("%d",*(p+i));