<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 多維數(shù)組與指針

          多維數(shù)組與指針

          作者: 時間:2016-12-01 來源:網(wǎng)絡(luò) 收藏
          C語言中數(shù)組和指針之間存在一些千絲萬縷的聯(lián)系,搞不清楚的情況下非常容易出錯,在前一段時間我寫過關(guān)于數(shù)組和指針的分析,但是還是存在很多不清楚的問題,特別是當(dāng)出現(xiàn)一些復(fù)雜的問題時,這種情況更加的復(fù)雜??戳撕芏嗑W(wǎng)友的博客,但是發(fā)現(xiàn)一些問題,做一下簡要的總結(jié)吧。


          多維數(shù)組的數(shù)組名并不是很多網(wǎng)友描述的多級指針,我僅以二維數(shù)組作為研究對象,進行一定的分析。

          二維數(shù)組int A[M][N],可以認為是存在M個元素的數(shù)組,且每一個元素都是長度為N的int型數(shù)組,這樣就能比較清晰的理解了數(shù)組。數(shù)組名在很多情況下轉(zhuǎn)換為指針,且數(shù)組名是數(shù)組首個元素的指針,這是非常重要的概念,搞清楚了這個概念也就能夠分析其他多維的數(shù)組情況啦。

          對于上面的數(shù)組A[M][N],數(shù)組名A實質(zhì)上指向數(shù)組的首個元素的指針,也就是說這時的數(shù)組名A變質(zhì)為一個指針,指向的類型為int[N],即指向的是一個數(shù)組,而不是一個簡單的值,那么對數(shù)組名進行解引用*A,就是得到這個一維數(shù)組(這是指針解引用的定義,就如同 int *p = &a, *p 實質(zhì)上是指a是一個道理),相當(dāng)于得到了一維數(shù)組名,即*A實質(zhì)上是一個數(shù)組,(*A)可以看做這個數(shù)組的數(shù)組名,這和int a[N]是同樣的道理,即:a = *A。同樣根據(jù)數(shù)組名是指向數(shù)組的首個元素的指針,可以將*A也可以被看做為指針,但此時的指針指向的是數(shù)組A[0]的首個元素,也就是指向了A[0][0],也就是說*(*A)就是A[0][0]。由此可知,二維數(shù)組并不是簡單的指向指針的指針,而是每一次解引用對應(yīng)的都是不同的指針類型。

          對于多維的數(shù)組,假設(shè)存在int B[N][M][S]這個三維的數(shù)組,那么數(shù)組名B是一個指針,其指向的類型是int[M][S]。*B也是指針,但是其指向的類型是int[S]。**B同樣也是指針,但是指向的類型是int型。更多維的數(shù)組也可以采用類似方法的分析。所以說并不能說是多維數(shù)組的數(shù)組名多級指針,因為多維數(shù)組對數(shù)組名的解引用操作都得到了一個不同大小的數(shù)組空間的指針,并不是指向單一元素的指針。

          由上面的分析可知,二維數(shù)組名A是一個指向一維數(shù)組的指針,指針的加法是指在當(dāng)前地址上加上類型的長度,得到指向的新地址,這里的類型就是數(shù)組int[N]。因此A+i實質(zhì)上是指向二維數(shù)組的第i個元素,也就是第i個一維數(shù)組。對A+i解引用*(A+i)即得到一個數(shù)組A[i],*(A+i)就是這個數(shù)組的數(shù)組名(這樣說可能不合適,但是方便理解),同時依據(jù)數(shù)組名就是指向這個數(shù)組的首個元素的地址,可知*(A+i)實質(zhì)上還是一個指針,但是這個指針指向的是A[i][0]這個元素。

          下面總結(jié)一下二維數(shù)組中的一些結(jié)論:
          a :指向一維數(shù)組的指針。a -> a[0]

          *a :得到一維數(shù)組a[0],可認為(*a)是一維數(shù)組的數(shù)組名,而(*a)-> a[0][0]。

          *a+j :指向a[0][j]的指針,(*a)可視為一個一維數(shù)組名。

          a+i :數(shù)組a[i]的指針,也就是說a+i->a[i]。

          *(a+i): 得到一維數(shù)組a[i],其中*(a+i)可以視為數(shù)組名。*(a+i)指向了a[i]的首個元素,即:*(a+i)->a[i][0]。

          *(a+i)+j :得到數(shù)組*(a+i)的第j個元素的指針,即:*(a+i)+j -> a[i][j]。

          *(*(a+i)+j) :就是得到a[i][j]。

          我之前一直將二維數(shù)組看做指向指針的指針,現(xiàn)在想起來是不合適的,假設(shè)存在一個指向指針的指針int **p。如果另p = A,通常對p的操作都會導(dǎo)致一些錯誤,由于p是一個指向指針的指針,那么p++實質(zhì)上只是增加了4個字節(jié),而A+1則增加了N*sizeof(int)。兩者之間并不是等價的關(guān)系,因此指向指針的指針并不能表征二維數(shù)組。

          如果指向指針的指針a和二維數(shù)組名是等價的,那么下面的程序肯定能夠?qū)崿F(xiàn)數(shù)組元素的打印,但是非常不幸,下面的函數(shù)會產(chǎn)生段錯誤即訪問了非法的內(nèi)存空間。

          本文引用地址:http://www.ex-cimer.com/article/201612/324513.htm

          int print_array(int **a, int row, int col)
          {
          int i = 0 , j = 0;
          for(i = 0; i < row; ++ i)
          {
          for(j = 0; j < col; ++ j)
          printf("%d ",a[i][j]);
          printf("");
          }
          }


          簡要的說明一下,為什么會產(chǎn)生段錯誤吧,由于a是一個指向指針的指針,那么a[i]則是一個指針,他指向一個數(shù)據(jù)空間,由于數(shù)組名實際上對應(yīng)一個地址,這個地址和&A等都是相同的,a[i]實質(zhì)上是就是數(shù)組中的一個元素,但是其中的內(nèi)容也是一個指針,這時候再次解引用就很有可能導(dǎo)致內(nèi)存非法訪問,產(chǎn)生段錯誤。比如A[2][3]={{1,2,3},{4,5,6}}。調(diào)用函數(shù)print_array(A,2,3)時,由于A實質(zhì)上是一個地址,由于數(shù)組的特殊性,具有&A,A,A+0,&A[0][0]等對應(yīng)的值是相同的。a = A,實質(zhì)上a就是一個地址。這個地址就是數(shù)組的起始位置。a中的內(nèi)容實質(zhì)上就是數(shù)組的元素,因此對數(shù)組進行一次解引用(*a)得到的實質(zhì)上就是數(shù)組的一個元素,也就是1,但是a是指向指針的指針,內(nèi)容1也是一個地址,對地址1的訪問肯定發(fā)生錯誤,因為地址1處是屬于內(nèi)核,不能直接進行訪問,發(fā)生了段錯誤。這也就是為什么說二維數(shù)組和指向指針的指針之間并不是等價的。

          但是根據(jù)上面的分析,我們知道二維數(shù)組的數(shù)組名指明了數(shù)組的位置,這時候直接對位置進行訪問就能夠得到數(shù)組的元素。同時我們知道a++指向的地址恰好就是a+4。剛好也就是數(shù)組的下一個元素。因此我們可以采用解一次引用的方式實現(xiàn)數(shù)據(jù)的訪問。因此上面的代碼可以修改如下,這種方法是運用了指針加法的一些特性,也就是指向指針的指針的增長大小就是大小等于4,但是這種方法只能針對類型大小為4的數(shù)組問題,其他的類型不能運用。

          int print_array(int **a, int row, int col)
          {
          int i = 0 , j = 0;
          for(i = 0; i < row; ++ i)
          {
          for(j = 0; j < col; ++ j)
          printf("%d ",*(a+i+j));
          printf("");
          }
          }

          字符串?dāng)?shù)組是比較常用的,字符串?dāng)?shù)組定義如下:

          char *str[]={
          "One",
          "Two",
          "Three",
          "Four"
          };

          字符串?dāng)?shù)組允許出現(xiàn)鋸齒形的數(shù)組,也就是說各個字符串的長度可以是不相同的,我們知道字符串?dāng)?shù)組實質(zhì)上是一個指針數(shù)組,和二維數(shù)組之間存在一定的差別,并不是同一種類型的問題,指針數(shù)組可以轉(zhuǎn)換為指向指針的指針的問題。
          我們常見的主函數(shù)main的兩種種定義方式為:

          int main(int argc, char *argv[])
          int main(int argc, char **argv)

          這兩種定義方式使得很多的初學(xué)者認為二維數(shù)組和指向指針的指針有一定的聯(lián)系,特別是第2種寫法存在很大的誤導(dǎo)性,實質(zhì)上字符串?dāng)?shù)組和二維數(shù)組之間存在很大的差別,所以不能當(dāng)做一類問題來討論。

          二維數(shù)組作為函數(shù)的形參時也是一個應(yīng)該注意的問題。我們已經(jīng)知道二維數(shù)組不是指向指針的指針這個結(jié)論。那么如果需要傳遞一個二維數(shù)組時又該如何處理呢?我們知道數(shù)組名是一個指向數(shù)組的指針,將參數(shù)設(shè)置為這種形式即可:

          int print_array(int (*p)[N],int row, int col);
          int print_array(int a[M][N],int row, int col);

          上面的兩種定義方式是比較常見的,當(dāng)然也可以采用指向指針的指針這種方式,這種方式一般在動態(tài)分配二維數(shù)組的情況下使用。這時候的動態(tài)分配的二維數(shù)組和我們當(dāng)前討論的二維數(shù)組存在差別,更像是字符串指針數(shù)組問題。

          /*C++*/
          void array_create(int **array, int row, int col)
          {
          int i = 0, j = 0;

          array = new int *[row];

          for(i = 0; i < row; ++ i)
          {
          array[i] = new int[col];
          }
          }

          其中array首先分配行,然后行中保存了指針變量,這樣就實現(xiàn)了二維數(shù)組的動態(tài)分配,這時候的二維數(shù)組不再是線性表,這是需要注意的。在C語言中也可以直接創(chuàng)建線性表,即采用一維數(shù)組訪問。



          關(guān)鍵詞: 多維數(shù)組指針C語

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();