二維數組和二級指針(真的沒什麼關係)

剛開始學c語言的時候,老是會認爲,一級指針能夠用來訪問一維數組,那麼二維數組就要用二級指針來訪問啦。。。。html

實際上二級指針和二維數組真的沒什麼關係,並且,切記千萬不要用二級指針訪問二維數組。。。。。小程序

下面是幾個有關的小程序,加深印象。。。。。。。。數組

 

實驗環境:主機CPU酷睿i5,vs2012函數

程序1:spa

int _tmain(int argc, _TCHAR* argv[])
{
    int **p= NULL;
    int a[2][3] = {1,2,3,4};
    p = a;
    return 0;
}

結果:編譯錯誤,錯誤提示:沒法從「int [2][3]」轉換爲「int **設計

可見,二級指針和二維數組名,根本就不是一類東西。3d

程序2:指針

int _tmain(int argc, _TCHAR* argv[])
{
    int **p= NULL;
    int a[2][3] = {1,2,3,4};
    p = (int **)a;
    printf("指針的長度爲:%d\n",sizeof(p));
    printf("值爲:%d\n",(int)(*p));
    p++;
    printf("值爲:%d\n",(int)(*p));
    getchar();
    return 0;
}

輸出結果:code

爲啥能夠輸出結果呢:純屬巧合!!!!!htm

什麼巧合呢:在個人機器上指針的長度和int類型的長度都恰好爲4個字節。

 

把程序放在虛擬機中跑一下,虛擬機的系統是CentOS7,64位的。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int a[2][2]={1,2,3,4};


    int **p =(int **)a;
    printf("值爲:%d\n",(int)(*p));
    p++;
    printf("值爲:%d\n",(int)(*p));


    char *pointer;
    printf("指針的長度爲:%zd\n",sizeof(pointer));
    
    return 0;
}

結果:編譯錯誤,提示:

緣由是,在個人虛擬機中指針佔8個字節嗎,而int佔四個字節。

可是long是佔8個字節,因此改爲long也能夠實現主機中的效果。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    long a[2][2]={1,2,3,4};


    long **p =(long **)a;
    printf("值爲:%ld\n",(long)(*p));
    p++;
    printf("值爲:%ld\n",(long)(*p));


    char *pointer;
    printf("指針的長度爲:%zd\n",sizeof(pointer));
    
    return 0;
}

結果爲:

緣由和第一個程序同樣,純屬巧合:在個人虛擬機中指針和long都佔8個字節。

在寫這個程序的時候還有個小插曲(小錯誤),也設計了兩個知識點,順便分享一下,寫上面程序的時候。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int a[2][2]={1,2,3,4};


    int **p =(int **)a;
    printf("值爲:%d\n",(long)(*p));
    p++;
    printf("值爲:%d\n",(long)(*p));


    char *pointer;
    printf("指針的長度爲:%zd\n",sizeof(pointer));
    
    return 0;
}

輸出結果爲:

在輸出long型數據的時候我不當心用了%d,而不是%ld。

看一下用%ld的效果:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int a[2][2]={1,2,3,4};


    int **p =(int **)a;
    printf("值爲:%ld\n",(long)(*p));
    p++;
    printf("值爲:%ld\n",(long)(*p));


    char *pointer;
    printf("指針的長度爲:%zd\n",sizeof(pointer));
    
    return 0;
}

輸出結果爲:

爲何會這樣?  仍是要從內存角度看:

在個人虛擬機中,指針佔8個字節,而p是個二級指針,*p就是個int類型的指針,佔8個字節,因此其實*p佔據了a[0]和a[1]。

至於爲何結果是8589934593.這還要涉及一個字節序的問題(這裏就不解釋了)

個人cpu是英特爾的,通常x86系列的cpu都是採用低字節序。

因此a[0]和a[1]兩個單元在內存中相似於:

高地址------------------------------------------------------------------------------------低地址

00000000  00000000  00000000 00000010     00000000 00000000 00000000 00000001

把這段內存解釋成long類型的數據就是8589934593

 

------------------------------------------------------------------------------------------------------------------------------

還要注意的是我上面,那兩個巧合之下能運行的程序,都是用*p訪問的,若是用**p會報錯,由於**p就是*p指向的內存空間的值,而*p指向的內存,也就是8589934593地址空間,是未知的。

總之記住,二級指針和二維數據沒啥關係

 

 

問題來了,既然不能用二級指針訪問二維數據,那怎樣用指針訪問二維數組呢?

在我以前的隨筆 由typedef和函數指針引發的危機  中,提到了,要聲明某種類型的指針變量,只需先聲明處該類型的變量,而後加上*便可(注意優先級)

那麼怎樣用指針訪問二維數組呢?

先來回憶一下怎樣用指針訪問一維數組。在訪問一位數組時,咱們實際上聲明的是一個和數組元素類型相同的指針變量指向了數組第一個元素的地址,而後在用這個指針訪問數組。

好比訪問int b[3]= {1,2,3}.

b中的元素爲int類型,因此咱們要聲明一個int類型的指針變量 如int *p ,而後將p指向b的第一個元素的地址,即p = &b[0],數組的首地址和第一個元素的地址是同樣的,因此也能夠用p=b;

這裏須要強調的是,指針類型和數組元素的類型一致,而不是數組類型一致,好比b的類型是有三個int類型元素的數組,而b中元素是int類型,b是數組類型,而元素是int類型,是不同的。上面之因此可以用p=b,不是說p是數組類型的指針,只是數組的首地址,和數組中第一個元素的地址同樣罷了p是個int類型的指針而不是數組類型的指針,這一點必定要記住。。。。

 

回到二維數組來,拿int a[2][3]= {1,2,3,4,5,6}來講, 數組a的元素爲 一個含有三個int類型數據的數據,即a的元素是一個一維數組,這個數組含3個元素。。。。

那麼怎樣聲明指向a數組中元素的指針變量呢? 在 由typedef和函數指針引發的危機  提到,方法及時先聲明一個該類型的變量,而後加上*便可,

a中元素爲含有3個int數據的數組,定義這樣一個普通變量爲: int p[3],而後在變量名前面加上*便可,可是要注意運算符的優先級,由於*的優先級比[]低,因此要加括號,即int (*p)[3]。

這樣再將p指向a的第一個元素的地址:p = &a[0],而後就能夠用p來訪問數組a啦

給出程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int a[2][3] = {1,2,3,4,5,6};
    int (*p)[3] = &a[0];
    printf("值爲:%d\n",(*p)[0]);
    printf("值爲:%d\n",(*p)[1]);
    printf("值爲:%d\n",(*p)[2]);
    p++;
    printf("值爲:%d\n",(*p)[0]);
    printf("值爲:%d\n",(*p)[1]);
    printf("值爲:%d\n",(*p)[2]);
    getchar();
    return 0;
}

 

結果爲:

 

再來一個程序,加深一下理解

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int a[2][3][4] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};
    int (*p)[3][4] = &a[0];
    int i = 0;
    for(;i < 3; i++)
    {
        int j = 0;
        for(; j < 4;j++)
            printf("值爲:%d\n",(*p)[i][j]);

    }
    p++;
    i = 0;
    for(;i < 3; i++)
    {
        int j = 0;
        for(; j < 4;j++)
            printf("值爲:%d\n",(*p)[i][j]);

    }
    return 0;
}

運行結果:

 

 

 最後,貼上一張,來自csdn的圖

但願對你有幫助,有紕漏的地方還請指正,謝謝。。。。

相關文章
相關標籤/搜索