天天看點

C++動态數組,多重指針問題

今天遇到一個問題,要開辟一個二維指針空間,詳細的看了一下網上有關動态指針、動态數組等開辟方法以及學習前輩們對于動态數組問題的解決經驗!

一、 

首先說明一下多重指針問題,這裡解釋到第三層,為了友善了解,我們可以将三重指針了解為三維數組,

首先看一個經典的例子:

int ***a,x=10,y=20;

a=(int ***)malloc(sizeof(int)*x);//配置設定是什麼?

for(i=1;i<10;i++){

(*a)[i]=(int *)malloc(sizeof(int)*y);//配置設定的又是什麼?

}

for(i=1;i<x;i++)

 for(j=1;j<y;j++)

 {

(*a)[i][j]=10;//這樣指派對不

}

1:   *a=(int **)malloc(sizeof(int)*x);可以了解為二重指針的第一層,配置設定了10個int型的二重指針空間

a是三重指針的位址,*a是二重指針的首位址;(*a)[0];(*a)[1];(*a)[2];(*a)[3];(*a)[4]........

2:    (*a)[i]=(int *)malloc(sizeof(int)*y);這個代表每一個二層指針又被配置設定了空間;這裡每一二層指針被配置設定了

20個(int *)的指針;即,每一二層指針又有20個孩子

3:   (*a)[i][j]=10;這樣指派正确,前邊的(*a)是擷取一個二維數組,後邊是一個二維數組的一個元素。直接指派是可以的

4:  我們同樣可以了解為樹形,幾重指針就是幾層樹

以上是關于三維指針的解釋,二維指針也就是可以了解成二維數組。

二、數組的指針、指針數組以及指向指針的指針

  考慮數組的指針的時候我們要同時考慮類型和維數這兩個屬性。換一句話,就是說一個數組排除在其中存儲的數值,那麼可以用類型和維數來位置表示他的種類。

A)一維數組

  在c和c++中數組的指針就是數組的起始位址(也就第一個元素的位址),而且标準文檔規定數組名代表數組的位址(這是位址數值層面的數組表示)。例如:

int a[10]; int *p;

p=&a[0]//和p=a是等價的:

  因為a是數組名,是以他是該數組的位址,同時因為第一個元素為a[0],那麼&a[0]也代表了該數組的位址。但是我們是不是就說一個數組名和該數組的第一個元素的&運算是一回事呢?在一維的時候當時是的,但是在高維的時候,我們要考慮到維數給數組帶來的影響。

  a[10]是一個數組,a是數組名,它是一個包含10個int類型的數組類型,不是一般的指針變量噢!(雖然标準文檔規定在c++中從int[]到int*直接轉換是可以的,在使用的時候似乎在函數的參數為指針的時候,我們将該數組名指派沒有任何異樣),a代表數組的首位址,在數字層面和a[10]的位址一樣。這樣我們就可以使用指針變量以及a來操作這個數組了。

是以我們要注意以下問題:

(1) p[i]和a[i]都是代表該數組的第i+1個元素;

(2) p+i和a+i代表了第i+1個元素的位址,是以我們也可以使用 *(p+I)和*(a+I)來引用對象元素;

(3)p+1不是對于指針數量上加一,而是表示從目前的位置跳過目前指針指向類型長度的空間,對于win32的int為4byte;

B)多元數組

  對于二維數組a[4][6];由于數組名代表數組的起始位址,是以a(第一層)和第一個元素a[0][0]位址的數字是相同的,但是意義卻是不同的。對于該數組我們可以了解為:a的一維數組(第一層),它有四個元素a[0]、a[1]、a[2]、a[3](第二層),而每個元素又含有6個元素a[0][0],a[0][1],a[0][2],a[0][3],a[0][4],a[0][5](第三層),…到此我們終于通路到了每個元素了,這個過程我們經曆了:a->a[0]->a[0][0];

  整體來講:a是一個4行5列的二維數組,a表示它指向的數組的首位址(第一個元素位址&a[0]),同時a[0]指向一行,它是這個行的名字(和該行的第一個元素的首位址相同(第一個元素為位址&a[0][0]))。是以從數字角度說:a、a[0]、&a[0][0]是相同的,但是他們所處的層次是不同的。

  既然a代表二維數組,那麼a+i就表示它的第i+1個元素*(a+i)的位址,而在二維數組中

*(a+i)又指向一個數組,*(a+i)+j表示這個數組的第j+1個元素的位址,是以要通路這個元素可以使用 *(*(a+i)+j)(也就是a[i][j])。

他們的示意圖為(虛線代表不是實際存在的):

對照這個圖,如下的一些說法都是正确的(對于a[4][6]):

a是一個數組類型,*a指向一個數組;a+i指向一個數組;a、*a和&a[0][0]數值相同;a[i]+j和*(a+i)+j是同一個概念;

  總結一下就是:我們對于二維指針a,他指向數組a[0,1,2,3],使用*,可以使他降級到第二層次,這樣*a就指向了第一個真正的數組。對于其他的情況我們也可以采用相同的方式,對于其他維數和類型的數組我們可以采用相類似的思想。

說到指向數組的指針,我們還可以聲明一個指針變量讓它指向一個數組。例如:

int (*p)[5];

這時p就是一個指針,要指向一個含有5個int類型元素的數組,指向其他的就會出現問題。

這個時候我們可以使用上面的什麼東西來初始化呢?

我們可以使用*a,*(a+1),a[2]等。

原因很簡單:我們在一個二維的數組中,那麼表達方式有上面的互相類似的意義呢?隻有 *a,*(a+1),a[2]等,

C)指針數組

  一個指針數組是指一個數組中的每個元素都是一個指針,例如:

int *p[10];//而不能是int (*p)[10]

或者

char *p[10];

此時p是一個指針(數值上和&p[0]一樣);

在前面有int t[10];

int * pt=t;//使用pt指向t

那麼這裡我們用什麼指向int *t[10]中的t呢?我們要使用一個指針的指針:

int **pt=t;

  這是因為:在int *t[10]中,每個元素是指針,那麼同時t又指向這個數組,數組上和&t[0]相同,也就是指向t[0],指向一個指針變量,可以說是一個指針的指針了,是以自然要用

int **pt;

D)指針的指針

  一個指針變量内部可以存儲一個值,這個值是另外一個對象的位址,是以我們說一個指針變量可以指向一個普通變量,同樣這個指針變量也有一個位址,也就是說有一個東西可以指向這個指針變量,然後再通過這個指針變量指向這個對象。那麼如何來指向這個指針變量呢?由于指針變量本身已經是一個指針了(右值),那麼我們這裡就不能用一般的指針了,需要在指針上展現出來這些特點,我們需要定義指針的指針(二重指針)。

int *p1=&i; int**p2=&p1;

綜合以上的所有點,下面是我們常常看到一些比對(也是經常出錯的地方):

int a[3],b[2][3],c,*d[3]; void fun1(int *p); void fun2(int (*p)[3]); void fun3(int **p); void fun4(int p[3]); void fun5(int p[]); void fun6(int p[2][3]); void fun7(int (&p)[3]);

函數 不會産生編譯時刻的可能值(但邏輯上不一定都對)

函數 不會産生編譯時刻的可能值(但邏輯上不一定都對)
fun1 a, &a[i], *b ,b[i],&b[i][j] ,&c ,d[i]
fun2 b,b+i,
fun3 d
fun4 a, &a[i], *b ,b[i],&b[i][j] ,&c ,d[i]
fun5 a, &a[i], *b ,b[i],&b[i][j] ,&c ,d[i]
fun6 b
fun7 a

此段文章出處:http://apps.hi.baidu.com/share/detail/38102294

三、

對于動态數組問題:

參閱他人的建議得知:使用一維數組實作多為數組的功能。定義動态啊的一維數組比較簡單,而且所派分的記憶體單元都是連續的,其實在記憶體中的存儲都是在一塊連續的記憶體塊上存儲,性質一樣!是以建議使用一維數組實作多元的功能;

執行個體如下:

1、用一重指針

int i,j,num1,num2;

int *p=new int[num1*num2];

for(i=0;i<num1;i++)

{

     for(j=0;j<num2;j++)

    {

     p[i*num1+j]=i*j+5;//給數組指派,調用的時候也是如此。

}

2、用二重指針

int num1,num2;

int **p;

p=new int*[num1];//開辟空間,了解起來有點難

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

    p[i]=new int[num2];

另外兩個執行個體:

一維動态數組的執行個體:

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. int *arr;
  6. int n;
  7. cout<<"請輸入一個整數指定數組大小:";
  8. cin>>n;
  9. arr = new int[n];
  10. for(int i=1;i<=n;i++)
  11. {
  12. cout<<"請輸入第"<<i<<"個元素:";
  13. cin>>arr[i-1];
  14. }
  15.  cout<<endl;//輸出一個空行
  16.   for(int i=1;i<=n;i++)
  17. {
  18. cout<<"第"<<i<<"個元素是:"<<arr[i-1]<<endl;
  19. }
  20. delete [] arr;//動态空間釋放
  21. }

複制代碼 二維動态數組的執行個體:

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. int **arr;
  6. int n=0,m=0;
  7. cout<<"請輸入一個整數指定數組第一維:";
  8. cin >> n;
  9. cout<<"再輸入一個整數指定數組第二維:";
  10. cin>>m;
  11. arr = new int*[n];
  12. for(int i=0;i<n;i++) //建立動态數組
  13. {
  14. arr[i] = new int[m];
  15. }
  16. cout<<"*****************下面是輸入部分*****************"<<endl;
  17. for(int i=0;i<n;i++)//讀入數組元素
  18. {
  19. for(int j =0;j<m;j++)
  20. {
  21. cout<<"請輸入"<<"arr["<<i<<"]["<<j<<"]的值:";
  22. cin>>arr[i][j];
  23. }
  24. }
  25. cout<<"*****************下面是輸出部分*****************"<<endl;
  26. for(int i=0;i<n;i++)//輸出數組元素
  27. {
  28. for(int j =0;j<m;j++)
  29. {
  30. cout<<"arr["<<i<<"]["<<j<<"]="<<arr[i][j]<<endl;
  31. }
  32. }
  33. for(int i=0;i<n;i++)//動态空間釋放
  34. delete[] arr[i];
  35. delete[] arr;
  36. arr=NULL;
  37. }