久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

簡析指針與多維數(shù)組 | Tony Bai

 unix89 2014-04-05

簡析指針與多維數(shù)組

三 28

bigwhite技術(shù)志 , , , , , , , , , , , , , , , , , 4 Comments

上一篇文章中對多級指針做了簡要分析,,其實(shí)只有當(dāng)指針與多維數(shù)組以及函數(shù)聯(lián)合在一起使用時,麻煩才算真正到來,。

零,、數(shù)組與數(shù)組名

C語言中的數(shù)組的一般聲明形式如下:

T arr_name[n]; /* T為類型,n為數(shù)組元素個數(shù) */

內(nèi)存布局角度來說,,數(shù)組T arr_name[n]就是內(nèi)存中連續(xù)的內(nèi)存單元,,每個內(nèi)存單元的長度為sizeof(T),數(shù)組的起始內(nèi)存單元地址為arr_name所在的內(nèi)存地址,, 同時也是數(shù)組第一個元素arr_name[0]的內(nèi)存地址,。

C語言數(shù)組的數(shù)組名(arr_name)有這樣的特點(diǎn):arr_name = &arr_name = *arr_name = 數(shù)組起始地址。見下面例子:

char a[5];

printf("a = %p\n", a);
printf("&a = %p\n", &a);
printf("*a = %p\n", *a);

輸出結(jié)果:

a = 0xbfb146c0
&a = 0xbfb146c0
*a = 0xbfb146c0

C語言數(shù)組與指針有著緊密的聯(lián)系,。數(shù)組名本身的值就是數(shù)組的起始地址,,有了地址,就有了指針存在的理由了,。

1) 數(shù)組名可以被當(dāng)作指針來用

    char a[5] = {1, 2, 3, 4, 5};
    printf("%d, %d, %d\n", *a, *(a+1), *(a+2)); // 輸出1, 2, 3

   
    這種用法下,,數(shù)組名相當(dāng)于指向數(shù)組首地址的char*指針變量。

2) 數(shù)組名可以作為地址被賦值給兼容類型的指針變量
   
    char a[5] = {1, 2, 3, 4, 5};
    char *p = a;
    printf("%d, %d, %d\n", *p, *(p+1), *(p+2)); //輸出1, 2, 3

3) 數(shù)組名不可以被當(dāng)作指針變量來賦值

    char a[5] = {1, 2, 3, 4, 5};
    char b[5] = {6, 7, 8, 9, 0};

    a = b; //編譯器提示錯誤:將‘char *’賦值給‘char[5]’時類型不兼容

    數(shù)組名與指針變量不同:指針變量有單獨(dú)的存儲空間,,其存儲空間內(nèi)存儲的是指向的內(nèi)存單元的地址,,但數(shù)組名只是個"代號"而已,其沒有單獨(dú)的存儲空間,,其所 在內(nèi)存地址中存儲的是數(shù)組第一個元素的元素值,,而不是一個地址?;蛘哒f數(shù)組名代表的是一個值類型,,char a[5]中的a可理解為是一個char[5]的值類型變量。將一個數(shù)組指針變量值賦值給一個值變量顯然是不合邏輯的,,也是非法的,。

4) 考慮到效率,數(shù)組無法被按值傳遞給函數(shù)
   
    雖然數(shù)組名可以理解為一個值類型變量,,但將數(shù)組名傳遞給函數(shù)時,,傳遞的不是數(shù)組的全部,而只是數(shù)組的首地址,,這顯然是有效率方面考慮的,。如果是傳遞數(shù)組的 全部,那碰到大數(shù)組時,,這個mem copy的效率顯然是不可接受的,。但通過這個首地址,函數(shù)內(nèi)部也是可以訪問和修改數(shù)組中的所有元素的,。
   
5) 函數(shù)形參中的數(shù)組變量將被轉(zhuǎn)化為兼容類型指針變量對待

正如4)中所言,,數(shù)組是以傳址方式傳入函數(shù)的,。對于以數(shù)組變量作為形參的函數(shù)來說,在函數(shù)內(nèi)部引用該參數(shù)時,,會自動將該參數(shù)視為數(shù)組類型兼容的指 針變量,,比如:
    char a[5] = {1, 2, 3, 4, 5};

    void foo(char a[5]) {
        printf("sizeof(a) = %d\n", sizeof(a));
    }

    這是一個經(jīng)典的C語言“陷阱”。foo形參中變量a已經(jīng)轉(zhuǎn)化為一個char*類型指針了,。對該指針變量進(jìn)行sizeof操作,,所得的 size僅是一個指針的長度(在32bit編譯下是4),而不是a數(shù)組的長度(4 * 5),。

一,、多維數(shù)組的理解

C語言中管數(shù)組的數(shù)組(的數(shù)組的…)稱為多維數(shù)組,雖然高于二維的多維數(shù)組并不經(jīng)常使用和遇見,。

T multi_arr_name[i][j][k];

多維數(shù)組也是數(shù)組,,根據(jù)數(shù)組的理解,多維數(shù)組也是內(nèi)存中連續(xù)分配的內(nèi)存單元,,只是這些物理分配的內(nèi)存單元被從邏輯上看成是“行”,、“列”以及各種 維度罷了?!?a >C專家編程》中有一種理解方法:將數(shù)組看成是一種向量,,也就是某種對象的一維數(shù)組;當(dāng)其元素為其他數(shù)組時,,這個向量也就是我們所說的 多維數(shù)組,。

我們來結(jié)合例子理解一下多維數(shù)組,從低維到高維度逐步理解:

1) 一維數(shù)組

char a[2];
這是一個向量,,擁有兩個元素,,向量中的元素類型為char??梢岳斫鉃椋?/p>

char a[2]; <=> (char) a[2];

2) 二維數(shù)組

char a[2][3];
這是一個向量,,擁有兩個元素,,向量中的元素類型為char[3],。可以理解為:

char a[2][3]; <=> (char[3]) a[2];

3) 三維數(shù)組

char a[2][3][5];
這是一個向量,,擁有兩個元素,,向量中的元素類型為char[3][5]??梢岳斫鉃椋?/p>

char a[2][3][5]; <=> (char[3][5]) a[2];

4) N維數(shù)組

char a[i][j][k]…[z];
這是一個向量,,擁有i個元素,向量中的元素類型為char[j][k]…[z],??梢岳斫鉃椋?/p>

char a[i][j][k]…[z]; <=> (char [j][k]…[z]) a[i];

二,、與數(shù)組類型兼容的指針類型

假設(shè)有下面這樣一個數(shù)組:

char a[2][3];

我要聲明一個可以指向該數(shù)組的指針變量,這個聲明該如何書寫呢,?是 char *p[3]還是char (*p)[3],?按照上面對多維數(shù)組的理解:

char a[2][3]; <=> char[3] a[2];

這樣我們只需構(gòu)造出一個指向char[3]類型的指針即可,顯然這樣的指針聲明是(char[3]) *p,。哦,,不對,這樣的聲明C編譯器是不認(rèn)的,,乾坤大挪移,!把(char[3])從中間劈開 => char *p[3],這樣對么,?這個是指向數(shù)組a的指針么,?怎么越看越像是一個指針數(shù)組阿,char *p[3]<=> (char*) p[3],。哇,,真的弄錯了,改,! 對了,,剛才忘記了(char[3]) *p中還有一對括號呢,給*p穿上,,=> char (*p)[3],。這回沒錯了,就是它了,。

char a[2][3];
char (*p)[3];

p = a; /* 沒有什么比這個還正確的了 */

再來一個三維數(shù)組的例子,,這次簡單直白點(diǎn)。

char a[2][3][5];

變形,!=> (char[3][5]) a[2];
指針有了 => (char[3][5]) *p => char (*p)[3][5];

有了上面的例子分析,,對于更高維度數(shù)組,你還不會聲明其兼容的指針類型嗎,?

理解了多維數(shù)組兼容的指針變量的類型聲明,,那么將多維數(shù)組與函數(shù)結(jié)合在一起使用時,你就會得心應(yīng)手了,,在函數(shù)內(nèi)部你看到的,、能用到的就是多維數(shù)組 對應(yīng)的兼容指針類型變量。

三,、多維數(shù)組中的“隱式數(shù)組名”

在很多C語言書中,,我們會經(jīng)常看到這樣的描述:對于多維數(shù)組char a[m][n][h],其中的某個元素a[i][j][k] <=> *(*(*(a + i) + j) + k),。這種等價形式是如何形成的呢,?

第零小節(jié)的描述告訴我們:數(shù)組名是具有指針屬性的,除了標(biāo)準(zhǔn)的下標(biāo)引用方式外,,還可以以指針的方式做指針運(yùn)算以及訪問元素,,這就是 *(*(*(a + i) + j) + k)是合法的原因。

接下來我們來對*(*(*(a + i) + j) + k)做一次分解分析,。鑒于一般形式不易理解和輸出結(jié)果,,我們用一個具體的例子來說明。

    char a[2][3][5] = {
        {
            {1, 2, 3, 4, 5},
            {6, 7, 8, 9, 10},
            {11, 12, 13, 14, 15},
        },

        {
            {21, 22, 23, 24, 25},
            {26, 27, 28, 29, 30},
            {31, 32, 33, 34, 35},
        }
    };

    char (*p)[3][5] = a;
    printf("a[1][2][3] = %d\n”, a[1][2][3]);
    printf("a addr = %p\n", a);
    printf("a + 1 = %p\n", a + 1);
    printf("*(a + 1) = %p\n", *(a + 1));
    printf("*(a + 1) + 2 = %p\n", *(a + 1) + 2);
    printf("*(*(a + 1) + 2) = %p\n", *(*(a + 1) + 2));
    printf("*(*(a + 1) + 2) + 3 = %p\n", *(*(a + 1) + 2) + 3);
    printf("*(*(*(a + 1) + 2) + 3) = %d\n", *(*(*(a + 1) + 2) + 3));

編譯這個程序,,執(zhí)行輸出:

a[1][2][3] = 34
a addr = 0xbfa0893e
a + 1 = 0xbfa0894d
*(a + 1) = 0xbfa0894d
*(a + 1) + 2 = 0xbfa08957
*(*(a + 1) + 2) = 0xbfa08957
*(*(a + 1) + 2) + 3 = 0xbfa0895a
*(*(*(a + 1) + 2) + 3) = 34

我們以*(*(*(a + 1) + 2) + 3)為例,,再根據(jù)上面的輸出結(jié)果,逐步拆解分析,。

1) a + 1

a的等價指針類型是char (*p)[3][5]; 因此a + 1這個指針運(yùn)算的結(jié)果相當(dāng)于在數(shù)組a的起始地址開始向后移動sizeof(char [3][5])個字節(jié),。從輸出結(jié)果來看,a + 1 = 0xbfa0894d = 0xbfa0893e + 15 = a addr +15也印證了這點(diǎn),。

2) *(a + 1)

通常指針的解引用操作會得到指針?biāo)竷?nèi)存地址所在存儲單元中存儲的值,。但上面的輸出結(jié)果讓我們產(chǎn)生疑問:

*(a + 1) = 0xbfa0894d == a + 1

在若干年前我的文章《挖掘一下C語言中的多維數(shù)組》中曾經(jīng)探討過這個問題,當(dāng)時針對這個問題并未給出答案,。這次對此問題我又有了新的認(rèn)識,。還記得我們在開篇中對數(shù)組名做的操作以及輸出結(jié)果么:

char a[5];

a = 0xbfb146c0
&a = 0xbfb146c0
*a = 0xbfb146c0

也是a == *a。而這里同樣是*(a + 1) == a + 1,。通過這個對比我們得到一個大膽的推論:a + 1也可以看作是一個“數(shù)組名”,,這是一個隱式數(shù)組名。只有這個解釋看起來是合理的,。

3) *(a + 1) + 2

a + 1這個隱式數(shù)組名對應(yīng)的指針類型是char (*p)[5],,因此 *(a+1) +2相當(dāng)于從a + 1地址的開始再向后移動10(2 x 5)個字節(jié),也就是0xbfa08957,,輸出結(jié)果也印證了這點(diǎn),。

4) *(*(a + 1) + 2)

我們又遇到了一個隱式數(shù)組名。*(*(a + 1) + 2) = 0xbfa08957 == *(a + 1) + 2,。

5) *(*(a + 1) + 2) + 3

*(a + 1) + 2這個隱式數(shù)組名對應(yīng)的指針類型是char *p,,因此*(*(a + 1) + 2) + 3相當(dāng)于從*(a + 1) + 2開始再向后移動3個字節(jié),也就是0xbfa0895a,,注意這個地址所在單元上存儲的是一個char值,。

6) *(*(*(a + 1) + 2) + 3)

如果將*(*(a + 1) + 2) + 3賦值給char *p,,那么*(*(*(a + 1) + 2) + 3)就相當(dāng)于*p,,這個再簡單不過了,34就是這個單元存儲的char值。

2013, bigwhite. 版權(quán)所有.

Related posts:

  1. 簡析多級指針解引用
  2. 也談指針運(yùn)算
  3. 也談C語言變長參數(shù)
  4. 挖掘一下C語言中的多維數(shù)組
  5. 也談字節(jié)序問題

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多