2009-11-20 10 views
9

Sto cercando di far puntare un puntatore a un array 2D di puntatori. Qual è la sintassi e come accedo agli elementi?Come allocare un array 2D di puntatori in C++

+0

è la dimensione del sapere al momento della compilazione o creato da dimensioni fisse in fase di esecuzione? Le file e le colonne di Rows hanno dimensioni fisse o cresciute dinamicamente, portando a matrici frastagliate? I puntatori sono di proprietà dell'array o sono semplicemente detenuti? I puntatori sono tutti correlati (cioè lo stesso tipo di base)? –

risposta

17

Con la lettera della legge, ecco come fare it:

// Create 2D array of pointers: 
int*** array2d = new (int**)[rows]; 
for (int i = 0; i < rows; ++i) { 
    array2d[i] = new (int*)[cols]; 
} 

// Null out the pointers contained in the array: 
for (int i = 0; i < rows; ++i) { 
    for (int j = 0; j < cols; ++j) { 
    array2d[i][j] = NULL; 
    } 
} 

Fare attenzione a eliminare i puntatori contenuti, gli array di righe e l'array di colonne tutti separatamente e nell'ordine corretto.

Tuttavia, più frequentemente in C++ si dovrebbe creare una classe che gestisca internamente un array di puntatori 1D e sovraccarichi l'operatore di chiamata di funzione per fornire l'indicizzazione 2D. In questo modo hai davvero una serie contigua di puntatori, piuttosto che una serie di matrici di indicatori.

+1

Più simile a un puntatore a un array di puntatori agli array. – Crashworks

+1

@Crahsworks: So. Se cova come un'anatra, è un'anatra. –

+1

Dipende da cosa OP indica con "2d array". Se intende semplicemente qualcosa a cui è possibile accedere con due operatori di pedici 'a [n] [m]', allora sì, questo è digitato anatra come array multidim. Se intende ciò che lo standard specifica come un array 2D, che è una regione contigua di n * m molti elementi, allora un array 1D di puntatori agli array 1D non è la stessa cosa. – Crashworks

3
double** array = new double*[rowCnt]; 
for (int row = 0; row < rowCnt; ++row) 
    array[row] = new double[colCnt]; 
for (int row = 0; row < rowCnt; ++row) 
    for (int col = 0; col < colCnt; ++col) 
    array[row][col] = 0; 
+2

questo è solo un puntatore che punta a un array 1D di puntatori. – TheFuzz

+0

Forse la sintassi dell'array [row] [col] lo chiarisce? –

+0

Ma non è ancora contiguo. – Crashworks

1

È possibile definire un vettore di vettori:

typedef my_type *my_pointer; 

typedef vector<vector<my_pointer> > my_pointer2D; 

che creare una classe derivata da my_pointer2D, come:

class PointersField: public my_pointer2D 
{ 
    PointsField(int n, int m) 
    { 
    // Resize vectors.... 
    } 
} 

PointsField pf(10,10); // Will create a 10x10 matrix of my_pointer 
+0

punto! = Puntatore. –

+0

ahh, qualunque sia ... – Elalfer

+1

Inoltre, non si dovrebbe ereditare dai contenitori STL –

4
int *pointerArray[X][Y]; 
int **ptrToPointerArray = pointerArray; 

Ecco come si crea una matrice multidimensionale (contigua alla memoria) vera.

Ma renditi conto che una volta lanciato un array multidimensionale su un puntatore del genere, perdi la capacità di indicizzarlo automaticamente. Si dovrebbe fare manualmente la parte multidimensionale dell'indicizzazione:

int *pointerArray[8][6]; // declare array of pointers 
int **ptrToPointerArray = &pointerArray[0][0]; // make a pointer to the array 
int *foo = pointerArray[3][1]; // access one element in the array 
int *bar = *(ptrToPointerArray + 3*8 + 1); // manually perform row-major indexing for 2d array 

foo == bar; // true 
int *baz = ptrToPointerArray[3][1]; // syntax error 
+0

C++ è una conversione fortemente tipizzata da int * a int ** non è consentita senza un cast esplicito. –

+0

Vero. Tuttavia, la conversione da int * [] a int **, che è quello che faccio qui, è automatica. – Crashworks

+0

True: Tuttavia questa non è la conversione: int ** ptrToPointerArray = pointerArray; Prova a compilare il codice con un compilatore C++ e vedrai l'errore. –

0

Vedere il mio codice. Funziona sul mio FC9 sistema x86_64:

#include <stdio.h> 

template<typename t> 
struct array_2d { 
     struct array_1d { 
       t *array; 
       array_1d(void) { array = 0; } 
       ~array_1d() 
       { 
        if (array) { 
         delete[] array; 
         array = 0; 
        } 
       } 
       t &operator[](size_t index) { return array[index]; } 
     } *array; 
     array_2d(void) { array = 0; } 
     array_2d(array_2d<t> *a) { array = a->array; a->array = 0; } 
     void init(size_t a, size_t b) 
     { 
       array = new array_1d[a]; 
       for (size_t i = 0; i < a; i++) { 
         array[i].array = new t[b]; 
       } 
     } 
     ~array_2d() 
     { 
       if (array) { 
         delete[] array; 
         array = 0; 
       } 
     } 
     array_1d &operator[](size_t index) { return array[index]; } 
}; 

int main(int argc, char **argv) 
{ 
     array_2d<int> arr = new array_2d<int>; 
     arr.init(16, 8); 

     arr[8][2] = 18; 
     printf("%d\n", 
       arr[8][2] 
       ); 

     return 0; 
} 

effo UPD: una risposta a "? Non è che un array di puntatori ad array", aggiungendo l'esempio di array di puntatori, molto semplice:

int main(int argc, char **argv) 
{ 
     array_2d<int*> parr = new array_2d<int*>; 
     int i = 10; 
     parr.init(16, 8); 
     parr[10][5] = &i; 
     printf("%p %d\n", 
       parr[10][5], 
       parr[10][5][0] 
       ); 

     return 0; 
} 

Ho ancora frainteso la tua domanda?

e si potrebbe anche

typedef array_2d<int*> cell_type; 
typedef array_2d<cell_type*> array_type; 

int main(int argc, char **argv) 
{ 
    array_type parr = new array_type; 
    parr.init(16, 8); 
    parr[10][5] = new cell_type; 
    cell_type *cell = parr[10][5]; 
    cell->init(8, 16); 
    int i = 10; 
    (*cell)[2][2] = &i; 

    printf("%p %d\n", 
      (*cell)[2][2], 
      (*cell)[2][2][0] 
      ); 

    delete cell; 

    return 0; 
} 

Funziona anche sul mio sistema FC9 x86_64.

+0

Non è un array di puntatori agli array? – Crashworks

+0

@Crashworks. Anche questo funziona ancora come un array 2D. –

+0

@Effo: questa implementazione ha alcuni bug gravi. Operatore di assegnazione mancante. Possibile doppia eliminazione di puntatori se utilizzati in modo errato. array_1 può essere copiato accidentalmente su una copia locale e al momento della cancellazione verrà eliminata una riga nella matrice. –

1

:)

ho avuto questi, una volta in un pezzo di codice che ho scritto.

Ero lo zimbello della squadra quando sono usciti i primi bug. Inoltre, utilizziamo la notazione ungherese, che porta a un nome come papChannel - un puntatore a un array di puntatori ...

Non è bello. È meglio usare typedef per definire una "riga di colonne" o viceversa. Rende anche l'indicizzazione più chiara.

typedef int Cell; 
typedef Cell Row[30]; 
typedef Row Table[20]; 

Table * pTable = new Table; 

for(Row* pRow = *pTable; pRow != *pTable+_countof(*pTable); ++pRow) { 
    for(Cell* pCell = *pRow; pCell != *pRow + _countof(*pRow); ++pCell) { 
    ... do something with cells. 
    } 
} 
4

Dipende. Può essere semplice come:

int main() 
{ 
    int* data1[10][20]; // Fixed size known at compile time 

    data1[2][3] = new int(4); 
} 

Se volete i formati dinamici in fase di esecuzione è necessario fare un certo lavoro.
Ma Boost ha coperto:

int main() 
{ 
    int x; 
    int y; 
    getWidthAndHeight(x,y); 

    // declare a 2D array of int* 
    boost::multi_array<int*,2> data1(boost::extents[x][y]); 

    data[2][3] = new int(6); 
} 

Se si sta bene con jagged arrays che può crescere in modo dinamico:

int main() 
{ 
    std::vector<std::vector<int*> > data1; 

    data1.push_back(std::vector<int*>(10,NULL)); 
    data1[0][3] = new int(7); 
} 

Nota: In tutto quanto sopra. Suppongo che l'array non possieda il puntatore. Quindi non ha fatto alcuna gestione sui puntatori che contiene (anche se per brevità sto usando new int() negli esempi). Per fare correttamente la gestione della memoria è necessario fare un po 'più di lavoro.

3

Si potrebbe provare Boost :: MultiArray.

Per ulteriori dettagli, consultare questo page.

1

Preferisco utilizzare l'operatore(). Ci sono molte ragioni per questo (FAQ C++ 13.10). Modificare la rappresentazione interna ad un std::vector se ti piace:

template <class T, int WIDTH, int HIEGHT> 
class Array2d 
{ 
public: 
    const T& operator()(size_t col, size_t row) const 
    { 
     // Assert col < WIDTH and row < HIEGHT 
     return m_data [(row * WIDTH + col)]; 
    } 
    T& operator()(size_t col, size_t row) 
    { 
     // Assert col < WIDTH and row < HIEGHT 
     return m_data [(row * WIDTH + col)]; 
    } 
private: 
T m_data[WIDTH * HIEGHT]; 
}; 

Si può usare in questo modo:

Array2d< Object*, 10, 10 > myObjectArray; 
myObjectArray(5,6) = new Object();