簡體   English   中英

C ++多維數組和指向指針表的指針

[英]C++ multidimensional array and pointers to table of pointers

這是東西。 我可以完全理解由指向數組的指針等組成的多維數組的概念(讓我們考慮一下二維)。

我們做這樣的事情:

// we can use dynamically defined size n and m
int n = 3, m = 5 ;
int **T = new int *[n];
for (int i = 0 ; i < n ; ++i)
    T[i] = new int[m];

我們得到的是:(檢查我是否在這里)

  • 5個整數的3個內存塊,放置在內存中的某個位置
  • 與int塊數(行數)相同大小的另一塊內存。 此塊是一個指向這些int行的指針(通常為4個字節,用於類似int的指針)的數組。
  • 我們最感興趣的是-指針(T),它是(** T)類型的指針。 這正是指向指針數組的指針,因為在C ++中,數組實際上是指向內存塊的指針,因此t []或t [0]表示* t,t [x]表示*(t + X)。

現在的問題是,當我們這樣做時:

int n = 3, m = 5 ;
int T[n][m] ;

我們所能做的並不是我以前展示過的事情。 我們有些奇怪。 什么是T? 當打印T時,我們得到與T [0]相同的值。 似乎我們保留了一個大小為n * m的整數塊,而沒有指向行的附加指針數組。

我的問題是:編譯器會記住數組的維數以及行和列的數量嗎? 當要求T [i] [j]時,實際上要求的是*(T + i * n + j),所以這n存儲在某個地方嗎? 問題是當我們試圖將此東西(T)傳遞給函數時。 我不知道為什么,但是如果n和m是常量,則可以將T作為指向此數組的指針傳遞,以使其在此程序中起作用:

#include <stdio.h>
const int n = 3, m = 4 ; // this is constant!
void add_5(int K[][m])
{
    for (int i = 0 ; i < n ; ++i)
        for (int j = 0 ; j < m ; j++)
            K[i][j] += 5 ;
}
int main()
{
    // n x m array the most straight forward method
    int T[n][m] ;
    for (int i = 0 ; i < n ; ++i)
        for (int j = 0 ; j < m ; ++j)
            T[i][j] = i*m + j ;

    for (int i = 0 ; i < n ; ++i)
    {
        for (int j = 0 ; j < m ; j++)
            printf("%d ",T[i][j]) ;
        printf("\n") ;
    }
    printf("\n") ;

    // adding 5 to all cells
    add_5(T) ;
    printf("it worked!!\n") ;

    for (int i = 0 ; i < n ; ++i)
    {
        for (int j = 0 ; j < m ; j++)
            printf("%d ",T[i][j]) ;
        printf("\n") ;
    }

    int ss ;
    scanf("%d",&ss) ;
}

但是,如果n和m不是常數,我們就不能。 因此,我需要的是將動態創建的多維數組的指針傳遞給函數,而無需為此手動分配內存。 這個怎么做?

在C ++中,數組實際上是指向內存塊的指針

絕對不。 數組與指針完全分開。 您可能會感到困惑的原因是由於稱為數組到指針轉換的標准轉換。 考慮:

int arr[10];

變量arr表示一個數組。 根本不是指針。 碰巧的是,在許多情況下,數組的名稱將轉換為指向其第一個元素的指針。 也就是說,轉換將其轉換為int*

int T[n][m] ;

在這種情況下, T是“ m intn數組的數組”。 您提到打印TT[0]得到相同的結果,這是由於數組到指針的轉換所致。

  1. 表達式T可以轉換為指向第一個元素的指針; 也就是int (*)[m] ,因為T的第一個元素本身就是一個包含m元素的數組。

  2. 表達式T[0]可以轉換為指向第一個子數組的第一個元素的指針。 因此,您獲得了一個指向int*類型的元素T[0][0]的指針。

由於數組在內存中的布局方式,這些指針具有相同的地址。 數組開始的地址與該數組的第一個元素的地址相同。 但是,指針的行為方式不同。 如果增加由T產生的指針,則移至下一個子數組。 如果遞增由T[0]得出的指針,則移至下一個int

與動態分配的“ 2D數組”相比,它可能有助於您查看內存中2D數組的布局圖。 3×3 2D數組如下所示:

  0,0   0,1   0,2   1,0   1,1   1,2   2,0   2,1   2,2
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ int │ int │ int │ int │ int │ int │ int │ int │ int │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘

而如果您動態分配了一個3×3的“ 2D數組”:

┌─────┐
│     │ // The int**
└──╂──┘
   ┃
   ▼
┌─────┬─────┬─────┐
│     │     │     ┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓  // An array of int*
└──╂──┴──╂──┴─────┘                            ┃
   ┃     ┗━━━━━━━━━━━━━━━┓                     ┃
   ▼                     ▼                     ▼
┌─────┬─────┬─────┐   ┌─────┬─────┬─────┐   ┌─────┬─────┬─────┐
│ int │ int │ int │   │ int │ int │ int │   │ int │ int │ int │ // Arrays of ints
└─────┴─────┴─────┘   └─────┴─────┴─────┘   └─────┴─────┴─────┘
  0,0   0,1   0,2       1,0   1,1   1,2       2,0   2,1   2,2

編譯器是否還記得數組的尺寸以及行和列的數量?

是的,如果您具有數組類型的變量,則數組的大小就是該類型的一部分。 編譯器始終知道變量的類型。

當要求T [i] [j]時,實際上要求的是*(T + i * n + j),所以這n存儲在某個地方嗎?

表達式T[i][j]等於*(*(T + i) + j) 讓我們了解它的作用。 首先,由T進行數組到指針的轉換,得到int (*)[m] 然后,我們將i添加到此以指向第i個子數組。 然后將其取消引用以獲取子數組。 接下來,此子數組也將進行數組到指針的轉換,得到一個int* 然后,向其添加j以獲得指向該子數組中第jint對象的指針。 取消引用以提供該int

問題是當我們試圖將此東西(T)傳遞給函數時。 我不知道為什么,但是如果n和m是常量,則可以將T作為指向此數組的指針傳遞給函數

這實際上是謊言。 您沒有將2D數組傳遞給函數。 實際上,沒有像數組類型這樣的參數。 您的參數int K[][m]實際上等效於int (*K)[m] 也就是說,所有數組類型參數都轉換為指針。

因此,當您使用add_5(T)調用此函數時,沒有傳遞T表示的數組。 T實際上正在進行數組到指針的轉換,以為您提供一個int (*)[m]並且指針正在傳遞到函數中。

這是二維動態數組的示例:

const int Mapsize = n

    int** GameField2 = 0;

GameField2 = new int*[Mapsize];                 // memory alocation
for(int i = 0; i < Mapsize; i++)
    GameField2[i] = new int[Mapsize];

for(int j = 0; j < Mapsize; j++)                
    for(int i = 0; i < Mapsize; i++)
        GameField2[i][j] = 0;

如果您希望在任何函數上對該數組進行操作,只需傳遞如下指針:

int Whatver(int** GameField)
{
    GameField[a][b]=x;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM