指針與數(shù)組


二級指針與二維數(shù)組

char *string[] ={"abc","abcd","acf"};
char string[3][4]={"abc","abcd","acf"};
`
首先一點的是拗小,雖然二維數(shù)組的數(shù)組名可以看做是一個指針本鸣,但是并不能將二維數(shù)組的數(shù)組名賦值給一個二級指針,也就是如下的代碼

int main(void)
{
    int arr[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
    int **p = arr;
    return 0;
}

上面的代碼在執(zhí)行的時候會報錯赎瞎,這是因為兩者數(shù)據(jù)類型是不相同的腹殿,所以不能賦值。
二維數(shù)組的數(shù)組名指向的是一維數(shù)組,也就是指向數(shù)組類型贱鄙,但是二級指針指向的是一級指針缤至,也就是指針類型潮罪,所以兩者不能互相賦值。

下面詳細介紹指針與二維數(shù)組的關(guān)系
聲明一個二維數(shù)組

int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
for (i=0;i<3;i++)
    {   for(j=0;j<4;j++)
        printf("%p ->%d\n",&arr[i][j],arr[i][j]);
    }
000000000062FE10 ->1
000000000062FE14 ->2
000000000062FE18 ->3
000000000062FE1C ->4
000000000062FE20 ->5
000000000062FE24 ->6
000000000062FE28 ->7
000000000062FE2C ->8
000000000062FE30 ->9
000000000062FE34 ->10
000000000062FE38 ->11
000000000062FE3C ->12

二維數(shù)組a可以看成是由a[0],a1,a[2]三個元素組成的一維數(shù)組领斥,a是其數(shù)組名嫉到;a[0],a1,a[2]又都是一維數(shù)組,其數(shù)組名分別是a[0],a1,a[2],a[0],a1,a[2]分別表示各自數(shù)組的首個元素的地址月洛。

arr[0]=000000000062FE00 ->1
arr[1]=000000000062FE10 ->5
arr[2]=000000000062FE20 ->9

由于數(shù)組名就是指針何恶,故a[0],a1,a[2]為一級指針,其類型為int嚼黔。a是由三個一級指針組成的數(shù)組细层。

那么a與a[0],a+1與a[0]+1的區(qū)別是什么?



a+1跨過了二維數(shù)組的一行隔崎,故a,a+1和a+2為行地址今艺。
相對于a[0]而言,a[0]+1只跨過了二維數(shù)組的一個元素爵卒,故為列地址虚缎。
由此可以看出:
(1)a+i是第i行的地址,即*(a+i)=a[i]钓株。因此a[i][j]等價于(*(a+i))[j];
(2)a[i]+j是第i行第j列的地址实牡,因此*(a[i]+j)等價與a[i][j]。

上述等價關(guān)系總結(jié)如下:

a[i][j] ←→ (*(a+i))[j] ←→ *(a[i]+j) ←→ *(*(a+i)+j)

要想理解指針和二維數(shù)組之間的關(guān)系轴合,就要首先弄清楚各種數(shù)組名所代表的元素创坞。
數(shù)組名表示的是該數(shù)組首個元素的地址,即arr=&arr[0][0];

二維數(shù)組在內(nèi)存中也是以一維數(shù)組的形式存儲受葛,只不過每個的一維數(shù)組的元素都是一維數(shù)組,因此二維數(shù)組名题涨,可以將它看做是指向行數(shù)組的指針
對于二維數(shù)組的存儲,是按照先行后列的形式排列的总滩,把每一行看做是一個一位數(shù)組纲堵,那二維數(shù)組就是由多個一位數(shù)組組成的數(shù)組,即二維數(shù)組是數(shù)組的數(shù)組闰渔。

對于二維數(shù)組名席函,可以將它看做是指向行數(shù)組的指針,也就是說二維數(shù)組的元素是行數(shù)組冈涧,所以對于二維數(shù)組加減的變化是以行數(shù)組的大小為單位的茂附,即arr指向arr[0]這個行數(shù)組正蛙,arr+1指向的是arr1這個行數(shù)組。對其進行解引用营曼,得到的是每一行數(shù)組的首地址乒验,即*arr表示的是第0行數(shù)組的首地址,和arr[0]相等,*(arr+1)表示的是第1行數(shù)組的首地址溶推,和arr1是相等的徊件。假如要取第1行第2個元素的地址奸攻,就是arr1+2蒜危,因為此時arr1代表的是一維數(shù)組,所以它的元素就是一個數(shù)字睹耐,在加減的時候移動的就是元素的大小辐赞,例如+1就表示該數(shù)組中第1個元素,+3就表示數(shù)組中的3個元素(以0開始)硝训。因為
*(arr+1)和arr1相等响委,所以第1行第2個元素的地址也可以表示為*(arr+1)+2,對這個地址進行解引用,得到的就是數(shù)組元素的具體值窖梁,也就是((arr+1)+2)赘风。
所以有如下公式,假如一個二維數(shù)組每行有N個元素纵刘,二維數(shù)組名是arr邀窃,那第i行第j個元素的地址是*(arr+i)+j,也可以表示為arr[i]+j假哎。元素的值可以表示為*(*(arr+i)+j)瞬捕,或者可以表示為arr[i][j]。

對上述二維數(shù)組arr舵抹,雖然arr[0]肪虎、arr都是數(shù)組首地址,但二者指向的對象不同惧蛹,arr[0]是一維數(shù)組的名字扇救,它指向的是arr[0]數(shù)組的首元素,其值為arr[0]首個元素的地址香嗓,對其進行“*”運算迅腔,得到的是一個數(shù)組元素值,即arr[0]數(shù)組首元素值(本例arr[0]數(shù)組的首個元素值為1)陶缺,因此钾挟,*arr[0]與arr[0][0]是同一個值。

而arr(可以看作arr+0)是一個二維數(shù)組的名字饱岸,它指向的是它所屬元素的首元素掺出,而二維數(shù)組的每一個元素都是一個維數(shù)組徽千,因此arr指向二維數(shù)組arr的首個元素arr[0],對其進行*運算得到的是arr[0]的地址,而要想得到arr[0][0]的值汤锨,需要再進行一次*運算双抽。

*arr=&arr[0];
**arr=*(&arr[0])=arr[0][0]
printf("arr=%p ->%d\n",arr,**arr); //兩次解應用得到arr[0][0]
printf("*arr=%p->%d\n",*arr,**arr) ;
printf("arr[0]=%p ->%d\n",arr[0],*(arr[0]));   //arr[0][0]地址

printf("%p\n",&arr[0][0]); 
printf("%p\n",&arr[0]);
printf("%p\n",*(arr+2)+3);                     //&arr[2][3]
printf("%p\n",arr[2]+3);               
printf("%p ->%d\n",*(arr+2)+3,*(*(arr+2)+3));
printf("%p ->%d\n",&arr[2][3],arr[2][3]);
arr=000000000062FE00 ->1
*arr=000000000062FE00->1
arr[0]=000000000062FE00 ->1

000000000062FE00
000000000062FE00
000000000062FE2C
000000000062FE2C
000000000062FE2C ->12
000000000062FE2C ->12

因此,數(shù)組名最為指針時移動單位的是“行”闲礼,所以arr+i指向的是第i個行數(shù)組牍汹,即指向arr[i]。對arr進行“*”運算柬泽,得到的是一維數(shù)組arr[0]的首地址慎菲,即\arr與arr[0]是同一個值但指向類型不同通過(arr+1與arr[0]+1即能看出其不同)。當用int*p定義指針p時锨并,p的指向是一個int型數(shù)據(jù)露该,對其進行加減操作,移動的是一個int型大小第煮,而不是一個地址解幼,因此,用arr[0]對p賦值是正確的包警,而用arr對p賦值是錯誤的撵摆。
使用數(shù)組指針對二級指針操作
而int (*ptr)[4],ptr表示一個指向4個int型數(shù)組的指針害晦,對其進行加減操作特铝,該變量為數(shù)組大小乘以數(shù)據(jù)類型大小。即ptr+1=&ptr+4*sizeof(int);
因而篱瞎,int (*ptr)[4]可以使用arr來初始化苟呐,因為ptr是一個指向包含4個int型元素的數(shù)據(jù),而arr指向其首個元素的地址俐筋,其首個元素又是一個包含4個int型數(shù)據(jù)的數(shù)據(jù)牵素。

int (*ptr)[4]=arr;                              //  行地址
printf("arr=%p->%d\n",&arr[0][0],arr[0][0]);    //首元素地址
printf("ptr=%p->%d\n",ptr,**ptr);     
printf("ptr+1=%p->%d\n",ptr+1,**(ptr+1));       //行地址加一移動4個int型大小
printf("*(ptr+1)+1=%p->%d\n",*(ptr+1)+1,*(*(ptr+1)+1));  //
運行結(jié)果:
arr=000000000062FE00->1
ptr=000000000062FE00->1
ptr+1=000000000062FE10->5
*(ptr+1)+1=000000000062FE14->6

完整程序:

#include<stdio.h>

int main()
{
 int i,j=0;
    int arr[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
    //分別使用不同的形式打印第2行,第3個元素的值和地址
    //根據(jù)推到出來的規(guī)律如下
    //該元素的地址
    int  *p;                  // p+1 移動一個int 類型的大小  澄者,列地址
    arr+1 ;                   //移動一個int a[4] 類型的大小笆呆,行地址
   // p=arr;                    // 錯誤,類型不匹配
    p=*arr;                   // 合法粱挡,等同與p=*(a+0)
    p=arr[0];                 // 合法赠幕,arr[0]表示數(shù)組arr[0]的首個元素arr[0][0]地址.p=&arr[0][0]
        for(i=0;i<3;i++)
     printf("arr[%d]=%p ->%d\n",i,arr[i],*(arr[i]));
     
    int (*ptr)[4]=arr;
    printf("arr=%p->%d\n",&arr[0][0],arr[0][0]);
    printf("ptr=%p->%d\n",ptr,**ptr);
    printf("ptr+1=%p->%d\n",ptr+1,**(ptr+1));
     printf("*(ptr+1)+1=%p->%d\n",*(ptr+1)+1,*(*(ptr+1)+1));
    printf("arr=%p ->%d\n",arr,**arr); //兩次解應用得到arr[0][0]
    printf("*arr=%p->%d\n",*arr,**arr) ;
    printf("arr[0]=%p ->%d\n",arr[0],*(arr[0]));   //arr[0][0]地址
    printf("\n");
    printf("%p\n",&arr[0][0]); 
    printf("%p\n",&arr[0]);
    printf("%p\n",*(arr+2)+3);              //&arr[2][3]
    printf("%p\n",arr[2]+3);               

    
    
    
    
    //該元素的值是12
    printf("%p ->%d\n",*(arr+2)+3,*(*(arr+2)+3));
    printf("%p ->%d\n",&arr[2][3],arr[2][3]);
     printf("\n");
   
    for (i=0;i<3;i++)
    {   for(j=0;j<4;j++)
        printf("%p ->%d\n",&arr[i][j],arr[i][j]);
    }
    return 0;
}

執(zhí)行結(jié)果如下:

ptr=000000000062FE00->1
ptr+1=000000000062FE10->5
*(ptr+1)+1=000000000062FE14->6
arr=000000000062FE00 ->1
*arr=000000000062FE00->1
arr[0]=000000000062FE00 ->1

000000000062FE00
000000000062FE00
000000000062FE2C
000000000062FE2C
000000000062FE2C ->12
000000000062FE2C ->12

000000000062FE00 ->1
000000000062FE04 ->2
000000000062FE08 ->3
000000000062FE0C ->4
000000000062FE10 ->5
000000000062FE14 ->6
000000000062FE18 ->7
000000000062FE1C ->8
000000000062FE20 ->9
000000000062FE24 ->10
000000000062FE28 ->11
000000000062FE2C ->12

指針數(shù)組
char *strs[]={"abc","def","acfg"};
指針數(shù)組是一個元素均為指針的數(shù)組,數(shù)組的數(shù)組名表示數(shù)組首個元素的地址询筏,而首個元素又是指針榕堰,因此指針數(shù)組的數(shù)組名就是一個二級指針。
二維數(shù)組名表示的是首個元素的地址,二維數(shù)組又可以理解為一個一維數(shù)組逆屡,而每個一維數(shù)組的元素又是
一個一維數(shù)組圾旨。對其進行加減操作,是以一維數(shù)組的大小為單位進行魏蔗。類似與數(shù)組指針砍的,即指向數(shù)組的指針,對其進行加減操作也是以數(shù)組大小為單位進行莺治。

此處輸入圖片的描述
此處輸入圖片的描述

int douptr(char** a,int size)
{
    char **p=a;
    int c=strlen(*p+2);
    printf("a=%p\n",a);
    printf("p=%p\n",p);
    printf("%s\n",*p);
    printf("%c",**p);
    
}
int main()
{
    int i,j=0;
    char *strs[] = {"abc","def","acfg"};  
    
    int size=sizeof(arr)/sizeof(char *);      //數(shù)組大小
    printf("arr=%p\n",arr);                   //數(shù)組地址廓鞠,數(shù)組名表示首個元素地址
    printf("&arr[0]=%p\n",&arr[0]);           //數(shù)組首個元素地址
    printf("&arr[1]=%p\n",&arr[1]);
    printf("&arr[2]=%p\n",&arr[2]);    
    printf("&arr[0]=%p\n",arr);               //數(shù)組首個元素地址
    printf("arr[0]->%s\n",*arr);              //數(shù)組首個元素指向內(nèi)容
    printf("arr[1][1]=%c\n",*(*(arr+1)+1)) ;  //第二個元素指向數(shù)組的第二個元素
    printf("arr[1][1]=%c\n",arr[1][1]);       //  
    printf("size=%d\n",size);
    douptr(arr,size);

    return 0;
}

結(jié)果:

arr=000000000062FE30
&arr[0]=000000000062FE30
&arr[1]=000000000062FE38
&arr[2]=000000000062FE40
&arr[0]=000000000062FE30
arr[0]->abc
arr[1][1]=e
arr[1][1]=e
size=3
a=000000000062FE30
p=000000000062FE30
abc
a

參考文獻
[1] http://ssspure.blog.51cto.com/8624394/1694224
[2] https://v.qq.com/x/cover/3dwhoro4c9voh54/h14042xdbdp.html
[3] http://ssspure.blog.51cto.com/8624394/1694224
[4] http://c.biancheng.net/cpp/html/478.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谣旁,隨后出現(xiàn)的幾起案子床佳,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,126評論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異趟畏,居然都是意外死亡蕉扮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評論 3 400
  • 文/潘曉璐 我一進店門角溃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拷获,“玉大人,你說我怎么就攤上這事减细〈夜希” “怎么了?”我有些...
    開封第一講書人閱讀 169,941評論 0 366
  • 文/不壞的土叔 我叫張陵未蝌,是天一觀的道長驮吱。 經(jīng)常有香客問我,道長萧吠,這世上最難降的妖魔是什么左冬? 我笑而不...
    開封第一講書人閱讀 60,294評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮纸型,結(jié)果婚禮上拇砰,老公的妹妹穿的比我還像新娘。我一直安慰自己狰腌,他們只是感情好除破,可當我...
    茶點故事閱讀 69,295評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著琼腔,像睡著了一般瑰枫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上丹莲,一...
    開封第一講書人閱讀 52,874評論 1 314
  • 那天光坝,我揣著相機與錄音剖毯,去河邊找鬼。 笑死教馆,一個胖子當著我的面吹牛逊谋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播土铺,決...
    沈念sama閱讀 41,285評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼胶滋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了悲敷?” 一聲冷哼從身側(cè)響起究恤,我...
    開封第一講書人閱讀 40,249評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎后德,沒想到半個月后部宿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,760評論 1 321
  • 正文 獨居荒郊野嶺守林人離奇死亡瓢湃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,840評論 3 343
  • 正文 我和宋清朗相戀三年理张,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绵患。...
    茶點故事閱讀 40,973評論 1 354
  • 序言:一個原本活蹦亂跳的男人離奇死亡雾叭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出落蝙,到底是詐尸還是另有隱情织狐,我是刑警寧澤,帶...
    沈念sama閱讀 36,631評論 5 351
  • 正文 年R本政府宣布筏勒,位于F島的核電站移迫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏管行。R本人自食惡果不足惜厨埋,卻給世界環(huán)境...
    茶點故事閱讀 42,315評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望病瞳。 院中可真熱鬧揽咕,春花似錦、人聲如沸套菜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逗柴。三九已至蛹头,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背渣蜗。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評論 1 275
  • 我被黑心中介騙來泰國打工屠尊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人耕拷。 一個月前我還...
    沈念sama閱讀 49,431評論 3 379
  • 正文 我出身青樓讼昆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親骚烧。 傳聞我的和親對象是個殘疾皇子浸赫,可洞房花燭夜當晚...
    茶點故事閱讀 45,982評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 指針是C語言中廣泛使用的一種數(shù)據(jù)類型。 運用指針編程是C語言最主要的風格之一赃绊。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu)既峡; ...
    朱森閱讀 3,452評論 3 44
  • 1、一維數(shù)組 定義一個指針P 賦值p=&a[0] a+i=&a[i]=p+i *(a+i)=a[i] 僅當p...
    PLW閱讀 1,342評論 0 1
  • C語言中的指針與數(shù)組 @(C語言)[排序算法, 快速排序, C實現(xiàn)] 引言 相信指針與數(shù)組是不少同學在初學C語言時...
    harry502閱讀 470評論 0 2
  • 1滩椤T烁摇!注意:因為簡書的顯示格式緣故忠售,所以“ * ”顯示會出現(xiàn)問題传惠,可能有些星號由于疏忽未改動格式,造成沒有顯示档痪,請...
    Eric_Hunter閱讀 510評論 0 1
  • 你是我心中的歌 吟唱出來是心脈的節(jié)奏 我的心曾滿縛枷鎖 你把它釋放出來橫沖直撞 它也曾嘗試橫流四海 但無論如何行走...
    落日丹楓閱讀 182評論 0 1