The two-dimensional pointer operation in C++

C中的二維指針問題總結:

概括的說,指針其實就是可變數組的首地址,說是可變數組,是
指其包含內容的數量的可變的,並且是可動態申請和釋放的,從而充
分節約寶貴的內存資源。我一向喜歡一維數組,除非萬不得已,我一
般是不用二維數組的,多維的則更是很少涉足了。因爲一維簡單,容
易理解,而用指針指向的多維數組就具有相當的複雜性了,也因此更
具有討論的必要。
閒話少說,這裏我就以三個二維數組的比較來展開討論:
(1)
int **Ptr;
(2)
int *Ptr[ 5 ];
(3)
int ( *Ptr )[ 5 ];
以上三例都是整數的二維數組,都可以用形如 Ptr[ 1 ][ 1 ]
方式訪問其內容;但它們的差別卻是很大的。下面我從四個方面對它們
進行討論:
一、內容:
它們本身都是指針,它們的最終內容都是整數。注意我這裏說
的是最終內容,而不是中間內容,比如你寫 Ptr[ 0 ],對於三者來說,
其內容都是一個整數指針,即 int *Ptr[ 1 ][ 1 ]這樣的形式才
是其最終內容。
二、意義:
(1)
int **Ptr表示指向"一羣"指向整數的指針的指針。
(2)
int *Ptr[ 5 ]表示指向 5個指向整數的指針的指針。
(3)
int ( *Ptr )[ 5 ]表示指向"一羣"指向 5 個整數數
組的指針的指針。
三、所佔空間:
(1)
int **Ptr (3)int ( *Ptr )[ 5 ]一樣,在32位平
臺裏,都是4字節,即一個指針。
(2)int *Ptr[ 5 ]不同,它是 5個指針,它佔5 * 4 = 20
個字節的內存空間。
四、用法:
(1)
int **Ptr
因爲是指針的指針,需要兩次內存分配才能使用其最終內容。
先,Ptr = ( int ** )new int*[ 5 ];這樣分配好了以後,它和(2)
意義相同了;然後要分別對 5個指針進行內存分配,例如:
Ptr[ 0 ] = new int[ 20 ];
它表示爲第 0 個指針分配 20 個整數,分配好以後,Ptr[0 ]爲指
20個整數的數組。這時可以使用下標用法 Ptr[ 0 ][ 0 ]
Ptr[ 0 ][ 19 ]
了。
如果沒有第一次內存分配,該 Ptr是個""指針,是不能使用
的,如果沒有第二次內存分配,則 Ptr[ 0 ]等也是個""指針,也
是不能用的。當然,用它指向某個已經定義的地址則是允許的,那是另外
的用法(類似於"借雞生蛋"的做法),這裏不作討論(下同)。
(2)
int *Ptr[ 5 ]
這樣定義的話,編譯器已經爲它分配了 5個指針的空間,這相當
(1)中的第一次內存分配。根據對(1)的討論可知,顯然要對其進行一次
內存分配的。否則就是""指針。
(3)
int ( *Ptr )[ 5 ]
這種定義我覺得很費解,不是不懂,而是覺得理解起來特別吃力,
也許是我不太習慣這樣的定義吧。怎麼描述它呢?它的意義是"一羣"
指針,每個指針都是指向一個 5個整數的數組。如果想分配 k個指針,
這樣寫: Ptr = ( int ( * )[ 5 ] ) new int[ sizeof( int ) * 5 * k ]
這是一次性的內存分配。分配好以後,Ptr指向一片連續的地址空間,
其中 Ptr[ 0 ]指向第 0 5 個整數數組的首地址,Ptr[ 1 ]指向第
1
5 個整數數組的首地址。
綜上所述,我覺得可以這樣理解它們:
int ** Ptr <==> int Ptr[ x ][ y ];
int *Ptr[ 5 ] <==> int Ptr[ 5 ][ x ];
int ( *Ptr )[ 5 ] <==> int Ptr[ x ][ 5 ];
這裏 x y是表示若干的意思。


二、二維數組    *****和二維指針的關係

1.代碼

[cpp] viewplaincopyprint?

1.  <span style="white-space: pre;"> </span>//test2

2.  cout<<"test2"<<endl;

3.  int b[10][10], i, j;

4.  for(i = 0; i < 10; i++)

5.  {

6.  for(j = 0; j < 10; j++)

7.  b[i][j] = i * 100 + j *10;

8.  }

9.  int (*pb)[10] = b;

10. cout<<pb<<' '<<pb+1<<endl;

11. cout<<(*pb)<<' '<<(*pb+1)<<endl;

12. cout<<*pb<<' '<<*(pb+1)<<' '<<*(pb+1)+1<<endl;

13. cout<<**pb<<' '<<**pb+1<<endl;

14. cout<<(*(*pb))<<' '<<(*(*pb+1))<<' '<<(*(*pb+1)+1)<<endl;

15. cout<<**(pb)<<' '<<**(pb+1)<<' '<<**(pb+1)+1<<endl;

   //test2
   cout<<"test2"<<endl;
   int b[10][10], i, j;
   for(i = 0; i < 10; i++)
   {
     for(j = 0; j < 10; j++)
      b[i][j] = i * 100 + j * 10;
   }
   int (*pb)[10] = b;
   cout<<pb<<' '<<pb+1<<endl;
   cout<<(*pb)<<' '<<(*pb+1)<<endl;
   cout<<*pb<<' '<<*(pb+1)<<' '<<*(pb+1)+1<<endl;
   cout<<**pb<<' '<<**pb+1<<endl;
   cout<<(*(*pb))<<' '<<(*(*pb+1))<<' '<<(*(*pb+1)+1)<<endl;
   cout<<**(pb)<<' '<<**(pb+1)<<' '<<**(pb+1)+1<<endl;

 

2.輸出結果

3.解釋

第一行:

pb:b[0]的地址。pb是指向b[0]的指針,b[0]是一個int[10]數組。

pb+1:b[1]的地址。pb指向的對象是一個數組,所以pb和pb+1相差0x28

第二行:

*pb:b[0][0]的地址。*pb是指向b[0][0]的指針,b[0][0]是一個int。雖然b[0]和b[0][0]的地址是一樣的,但是兩個指針指向的對象是不一樣的。

*pb+1:b[0][1]的地址。pb是指向b[0][1]的指針,b[0][1]是一個int。因此*pb和*pb+1相關4

第三行:

*pb:b[0][0]的地址。

*(pb+1):b[1][0]的地址。pb+1指向b[1]。

*(pb+1)+1:b[1][1]的地址。

第四行:

**pb:pb[0][0]。pb指向pb[0]。*pb指向pb[0][0]。**pb是pb[0][0]的內容。

**pb+1:b[0][0]+1。

第五行:

*(*pb):pb[0][0]

(*(*pb+1)):pb[1][0]

(*(*pb+1)+1):pb[1][1]

第六行:

**(pb):pb[0][0]

**(pb+1):pb[1][0]

**(pb+1)+1:pb[1][0]+1

 

 二維指針對字符串的操作:

1. #include<string>

2. using namespace std;

3. int main(){

4. char **mychr;

5. char chr[]={"I love cplusplus"};

6. char chrs[]={"I love cplusplus"};

7. char *p=chr;

8. mychr=&p;

9.  

10.if(strcmp(*mychr,chrs)==0)

11.{

12.cout<<"equal"<<endl;

13.}

14.else

15.{

16.cout<<"not equal"<<endl;

17.}

18. 

19.cout<<&chr[0]<<endl;

20.cout<<&p<<endl;

21.cout<<&(*mychr)<<endl;

22.cout<<**mychr<<endl;

23.system("pause");

24.return 0;

25.}

 

 

 

二維數組指針指向一維數組

#include<stdio.h>

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

int (*p)[5]=&array;

for(int i=0;i<5;i++)
{
printf("%d ",*(*p+i));
}

printf("\n");

return 0;
}
在這裏面我們定義了一個指針變量p,這個指針變量指向的是一個含有5個元素的一維數組,它指向的是一個一維數組的整體,所以將用&array賦值給它,*p其實是*(p+0),按照我們一維數組的理解,*(p+0)應該是指向我們數組的第一個元素,即p[0],也即我們所指數組的第一個元素&array[0],這個地址再後移i個元素後得到我們想要的地址,然後再加上*就得到本地址裏面所存儲的整形數據的內容。

博客:http://blog.csdn.net/zwb8848happy/article/details/7389622

對二維指針和二維數組講解的非常詳細

(二)二維數組和指針

(1)地址代表的意義
首先理解,二維數組,例如
int arry[2][3]={{2,3,1},
{23,45,6}};

這樣寫是最好理解的,也就是說2行3列。其中也可以看成是2個一維數組的整合,也就是
arry[0] = {2,3,1};
arry[1] = {23,45,6};

簡單測試一下一些符號究竟代表的是什麼意思
printf("n%x",arry);
printf("n%x",arry[0]);
printf("n%x",&arry[0][0]);
printf("n%x",arry+1);
printf("n%x",arry[1]+1);
printf("n%x",&arry[1][1]+1);
從編譯運行的結果來看
12ff68
12ff68
12ff68
12ff74
12ff78
12ff7c
arry 是這個數組的名字,也就是代表着入口地址,剛纔說了,二維數組實際可以看成N個
一維數組,例如本例中,arry[0] 代表着其中的第一個一維數組,那麼 arry[1] 就代表着
第二個一維數組,而且這裏是地址,注意 arry[0] 本身就代表着地址了。
arry[0][0]本身代表着這個元素,那麼取地址之後 &arry[0][0] 就變成了,這個元素的地址
然而將每個地址加一後發現,這些地址代表的語義並不相同。
arry+1 之後地址變成 12ff68 到 12ff74 也就是說,指向了第二行第一個元素 23
arry[1]本身就代表着第二個一維數組的入口地址,加一之後就只想這個數組的第二個元素
那麼就應該指向 45,從地址可以看出。
&arry[1][1]+1 這個是以元素爲單位,首先 arry[1][1]這個元素爲基準,也就是 45 ,然後
再後移一個元素,所以應該指向 6.
參考


(2)二維數組怎麼傳遞參數

void disparry(int a[2][3])
{
printf("n%d,%d,%d",a[0][0],a[0][1],a[0][2]);
}

void main(void)
{
int arry[2][3]={{2,3,1},
{23,45,6}};
int (*c)[3]=arry;
int *p;

p =(int *)arry;
disparry((int (*)[3])p);

disparry(c);

}

可以通過兩種辦法,第一是通過 int * 類型的指針 *p 來處理。首先因爲 p 是 int* 類型,
而 arry是二維數組,不等價不能直接賦值,那麼就簡單的將二維數組指針轉換爲 int* 類型
這樣就匹配了,產生的效果是 p 指向了 arry 的入口。
然後 disparry 函數需要的參數的類型是 inta[2][3],很顯然,這個時候 p又不能作爲參數
了,當然直接傳遞的話,運行結果不錯,但是會有 warning 的。於是再一次將 int * 轉換爲
需要的 int (*)[3] 類型,說白了,就是 數組指針。
那麼第二種辦法就很乾脆,定義一個數組指針c指向 arry,那麼 c就可以直接傳遞了。

(3)使用 typedef 定義二維數組
typedef int A[2];
A b[3]={32,11,23,45,6,7};
printf("n%d",b[1][0]);

可以看出,先定義一種新的數據類型 A,他是一個 2個元素的一維數組。然後再定義一個含有
3個 A 類型的一維數組b,這樣b其實就是一個二維數組了,b[3]代表的是有3行這樣的一維數組
所以這樣下來實際上等效於 b[3][2]。


C/C++中的二維指針問題--轉載 (內存分配

 指針是可變數組的首地址。正因爲是可變數組,所以一般使用指針時都是採用動態內存分配和釋放的方式。一維指針形式簡單,容易理解。平時應用較多。二維數組和二維指針比較複雜,並且在動態內存分配與釋放方面比較複雜且難以理解。但是二維數組和二維指針是非常有用的。

     考慮以下應用:對一幅圖像進行模板運算。這必然會牽涉到對圖像的各象素點的操作。此時使用一維指針進行圖像傳遞時,不可避免的會使用形如*(p+i*width+j)的方式完成對圖像象素點的訪問。這種方式很不直觀並且編寫程序時容易出錯。如果使用二維指針進行圖像數據的傳遞,則會收到很好的效果。可以採用p[i][j]的方式直接操作象素點,直觀又便於維護。因此掌握二維數組和二維指針是必要的。

使用http://www.wangchao.net.cn/bbsdetail_59038.html中的示例。

定義如下3個二維數組和二維指針進行說明:

1.         int** ptr;

2.         int *ptr[M];

3.         int (*ptr)[M];

以上都是存放整數的二維數組,並且都可以通過ptr[i][j]的形式訪問內容。但是它們之間有很大的差別。以下依照文中提到的方面進行分析。

l         內容
三個ptr本身都是指針,並且是二維指針,但是它們的最終內容總是整數。但中間內容,形如ptr[i]並不是整數,而是指針int *.

l         意義
1. int** ptr 表示指向(一組指向整數數據指針)的指針;
2. int *ptr[M] 是指針數組,表示指向(M個指向整數指針)的指針;
3. int (*ptr)[M]表示指向一組(指向包含M個整型數據的指針)的指針。

l         所佔空間
1和3佔用一個內存空間,在32位平臺上爲4個字節,也就是一個指針。
2是M個指針,在其定義過程中編譯器即對其進行了分配,佔用4*M共4M個字節。

l         用法
1. int** ptr 表示指向(一組指向整數數據指針)的指針,是一個二維指針。在其定義過程中,編譯器並不對其進行內存的分配,因此必須自己管理其內存的分配與釋放。典型使用如下:

     
使用上述方法分配內存,最終ptr耗費的內存空間爲M*sizeof(int*)+M*N*sizeof(int)

2. int *ptr[M] 是指針數組,表示指向(M個指向整數指針)的指針。是一個二維指針。但是在定義的時候,編譯器已經爲ptr指向的M個指向整數的指針ptr[0:M-1]分配了內存。也就是說,定義之後即可得到ptr的地址以及用於存放ptr[0:M-1]的內存空間4MB。要使用ptr必須對ptr[i]分配內存。分配內存後,ptr地址相應內存空間填入ptr[i]指向內存地址。使用如下操作:

使用上述方法分配內存,最終ptr耗費的內存空間爲M*sizeof(int*)+M*N*sizeof(int),其中M*sizeof(int*)爲編譯器分配,M*N*sizeof(int)爲程序員自己分配。

3. int (*ptr)[M]表示指向一組(指向包含M個整型數據的指針)的指針。該定義限定了ptr[i][0:M-1],所有指針ptr[i]必須指向長度爲M的數組。使用方式如下:
  
使用上述方法分配內存後,ptr所佔內存空間爲M*N*sizeof(int)(不考慮不同操作系統用於管理的內存)。ptr內存空間中保存的爲最終內容而非ptr[i]地址。

    

         最後回到開始考慮的應用,使用以下解決方案:

        

  1. // Function Prototype: int test( char* data,  
  2. // const int N_H, const int N_V);  
  3. // Function name: test  
  4. // Return type: int  
  5. // Argument: char* data 輸入圖像數據  
  6. // Argument: const int N_H, const int N_V 圖像尺寸  
  7. int test( char* data, const int N_H, const int N_V);  
  8. {  
  9.     char** ppData = NULL;  
  10.     int i = 0;  
  11.   
  12.     ppData = (char**)malloc(sizeof(char*)*N_V);  
  13.   
  14.     if (ppData == NULL)  
  15.     {  
  16.         printf("Error in mem location!/n");  
  17.         return 0;  
  18.     }  
  19.   
  20.     for (i=0;i<N_V;i++)  
  21.     {  
  22.         ppData[i] = data + i * N_H;  
  23.     }  
  24.            
  25.          //其他操作  
  26.     free(ppData);  
  27.     return 1;  
  28. }  

C++中用new給二維指針分配內存及delete刪除


C++中用new可以通過以下方法爲二維指針分配內存,例如分配整型5*4的空間:

1、化二維爲一維

int *p;

p=new int[5*4];

2、可以直接定義二維指針,通過兩步申請內存,但是從二維數組的角度看內存不連續。

int **p;
int x;
p=new int*[5];
for (int i=0;i<5;i++)
{
p[i]=new int[4];
}

使用時:

for(int i=0;i<5;i++)
for(int j=0;j<4;j++)
p[i][j]=i+j;
for(int i=0;i<5;i++)
for(int j=0;j<4;j++)
{
std::cout<<p[i][j];
if(j==3)
std::cout<<std::endl;
}

釋放內存時應該注意釋放方法:

for(int i=0;i<5;i++)

delete[] p[i];

delete[] p;

3、可以先定義一維指針並分配夠需要的空間,然後自己根據情況映射到二維指針。

int *p1=new int[5*4];
int **p;
int x;
p=new int*[5];
for (int i=0;i<5;i++)
{
p[i]=p1+i*4;
}

使用時仍然是:

for(int i=0;i<5;i++)
for(int j=0;j<4;j++)
p[i][j]=i+j;
for(int i=0;i<5;i++)
for(int j=0;j<4;j++)
{
std::cout<<p[i][j];
if(j==3)
std::cout<<std::endl;
}

此時釋放空間:

delete[] p;





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章