conversione di array 2D in pointer-to-pointer

Activity solution[a][b]; ... Activity **mother = solution; 

Voglio convertire array 2D di oggetti in pointer-to-pointer. Come posso fare questo;

L’ho cercato su google. tuttavia ho trovato solo un esempio di array di dimensioni.

Una semplice conversione non ti aiuterà qui. Non c’è compatibilità di alcun tipo tra tipo di array 2D e tipo puntatore-puntatore. Tale conversione non avrebbe senso.

Se hai davvero bisogno di farlo, devi introdurre un ulteriore array intermedio “row index”, che colmerà il gap tra semantica array 2D e semantica puntatore-puntatore

 Activity solution[a][b]; Activity *solution_rows[a] = { solution[0], solution[1] /* and so on */ }; Activity **mother = solution_rows; 

Ora l’accesso alla mother[i][j] ti darà accesso alla solution[i][j] .

La ragione per cui è ansible fare ciò per gli array monodesmensionali e non per gli array bidimensionali riguarda il modo in cui gli effettivi elementi dell’array sono memorizzati in memoria. Per gli array monodesmensionali, tutti gli elementi vengono memorizzati in modo consecutivo, quindi l’ array[i] espressioni array[i] è equivalente all’espressione *(array + i) . Come puoi vedere, la dimensione dell’array non è necessaria per eseguire un’operazione di indice di array. Tuttavia, per gli array bidimensionali, gli elementi sono memorizzati in ordine “row major”, ovvero tutti gli elementi nella riga zeroth vengono memorizzati per primi, seguiti dagli elementi nella prima riga, seguiti dagli elementi nella seconda riga , ecc. Pertanto, l’ array[i][j] espressioni array[i][j] è equivalente a *(array + (i * ROW_SIZE) + j) , dove ROW_SIZE è il numero di elementi in ogni riga. Pertanto, la dimensione della riga dell’array è necessaria per eseguire un’operazione dell’indice di matrice e il cast della variabile dell’array su un puntatore perde tali informazioni.

Voglio convertire array 2D di oggetti in pointer-to-pointer. Come posso fare questo?

Perché? È perché un’interfaccia si aspetta un puntatore ai puntatori?

Se è così, dovrai creare un nuovo array che contenga quei puntatori.

 Activity solution[a][b]; Activity* solutionPtrs[a]; for (int i = 0; i < a; ++i) solutionPtrs[a] = solution[a]; Activity** mother = solutionPtrs; 

Perché non puoi semplicemente lanciare un array 2D di T a T** ? Bene, perché non hanno niente a che fare l'uno con l'altro!

È ansible trasmettere un T[a] a un T* perché si ottiene un puntatore al primo elemento dell'array.

Puoi farlo anche con gli array 2D, ma se hai un T[a][b] allora decade ad un (T[b])* perché un array 2D non è un array di puntatori, è un array di matrici .

Questo è c ++ ! Tutto è ansible! Ma questo è c ++ quindi richiede un certo livello di comprensione.

A tal fine, iniziamo con un semplice esempio di 2 matrici 1-dimensionali: char firstName[4] = { 'J', 'o', 'n', '\0' } e char lastName[4] = { 'M', 'e', 'e', '\0' } Diamo un’occhiata a un ansible layout di memoria qui:

 +------------+-------+ | Address | Value | +------------+-------+ | 0x76543210 | 0x4A | < - firstName[0] - 'J' | 0x76543211 | 0x6F | <- firstName[1] - 'o' | 0x76543212 | 0x6E | <- firstName[2] - 'n' | 0x76543213 | 0x00 | <- firstName[3] - '\0' +------------+-------+ | 0x76543214 | 0x4D | <- lastName[0] - 'M' | 0x76543215 | 0x65 | <- lastName[1] - 'e' | 0x76543216 | 0x65 | <- lastName[2] - 'e' | 0x76543217 | 0x00 | <- lastName[3] - '\0' +------------+-------+ 

Dato questo layout di memoria se dovessi fare cout < < firstName << ' ' << lastName che cout < < firstName << ' ' << lastName :

0x76543210 0x76543214

Questi array sono in realtà solo un puntatore al loro primo elemento! Questo illustra Array to Pointer Decay, che puoi leggere di più qui: http://en.cppreference.com/w/cpp/language/array#Array-to-pointer_decay

Prima di andare avanti c'è qualcosa di importante da notare, i char occupano esattamente 1 byte in modo che l'indirizzo di ciascun char successivo nell'array sarà semplicemente l'indirizzo successivo. Ciò viene sfruttato dall'operatore di sottoscrizione in questo modo: firstName[1] è equivalente a *(firstName + 1) . Questo è vero per char s ma vale anche per qualsiasi altro tipo che occupa più di 1 byte. Prendiamo ad esempio: short siArray = { 1, 2, 3, 4 } , un ansible layout di memoria di siArray sarà simile a:

 +------------+--------+ | Address | Value | +------------+--------+ | 0x76543218 | 0x0001 | < - siArray[0] - 1 | 0x7654321A | 0x0002 | <- siArray[1] - 2 | 0x7654321C | 0x0003 | <- siArray[2] - 3 | 0x7654321E | 0x0004 | <- siArray[3] - 4 +------------+--------+ 

Anche se cout < < siArray << ' ' << &(siArray[1]) produrrà:

0x76543218 0x7654321A

*(siArray + 1) indicizzerà ancora lo stesso elemento di siArray come siArray[1] . Questo perché quando si esegue l'aritmetica del puntatore c ++ considera il tipo di indirizzo su cui si sta operando, quindi incrementando un short* aumenterà effettivamente l'indirizzo per sizeof(short) . Puoi leggere ulteriori informazioni sull'aritmetica dei puntatori qui: http://en.cppreference.com/w/cpp/language/operator_arithmetic

Infine vediamo come c ++ memorizza gli array bidimensionali. Dato: char name[2][4] = { { 'J', 'o', 'n', '\0' }, { 'M', 'e', 'e', '\0' } } un ansible layout di memoria potrebbe essere:

 +------------+-------+ | Address | Value | +------------+-------+ | 0x76543220 | 0x4A | < - name[0][0] - 'J' | 0x76543221 | 0x6F | <- name[0][1] - 'o' | 0x76543222 | 0x6E | <- name[0][2] - 'n' | 0x76543223 | 0x00 | <- name[0][3] - '\0' | 0x76543224 | 0x4D | <- name[1][0] - 'M' | 0x76543225 | 0x65 | <- name[1][1] - 'e' | 0x76543226 | 0x65 | <- name[1][2] - 'e' | 0x76543227 | 0x00 | <- name[1][3] - '\0' +------------+-------+ 

Dato che sappiamo che un valore di array 1-dimensionale è in realtà solo un puntatore, possiamo vedere da questo layout di memoria che il name[0] non è un puntatore, è solo il primo carattere del primo array. Quindi il name non contiene 2 puntatori di matrice 1-dimensionale, ma contiene il contenuto dei 2 array. (Per inciso su una macchina a 32 bit che non memorizza i puntatori salva 8-byte di memoria, che è piuttosto consistente per un array bidimensionale a 8 byte.) Quindi provare a trattare il name come un char** proverebbe a usare i caratteri come un puntatore.


Compreso questo, abbiamo davvero bisogno di evitare di usare l'aritmetica del puntatore di c ++ per trovare il valore di dereferenziazione. Per fare ciò dovremo lavorare con un char* modo che l'aggiunta di 1 sia in realtà solo l'aggiunta di 1. Quindi, ad esempio:

 const short si2DArray[2][3] = { { 11, 12, 13 }, { 21, 22, 23 } }; const auto psi2DPointer = reinterpret_cast(si2DArray); for(auto i = 0U; i < size(si2DArray); ++i) { for(auto j = 0U; j < size(*si2DArray); ++j) { cout << *reinterpret_cast(psi2DPointer + i * sizeof(*si2DArray) + j * sizeof(**si2DArray)) < < '\t'; } cout << endl; } 

Esempio dal vivo

Si noti che in questo esempio, anche se faccio riferimento a si2DArray ho pensato che psi2DPointer stia ancora utilizzando le informazioni da si2DArray per fare l'indicizzazione, vale a dire:

  1. Quanti array sono nella dimensione principale: size(si2DArray)
  2. Quanti elementi ci sono nella dimensione minore: size(*si2DArray)
  3. Qual è la dimensione in memoria della dimensione minore: sizeof(*si2DArray)
  4. Qual è il tipo di elemento dell'array: sizeof(**si2DArray)

Si può quindi vedere che la perdita di informazioni dalla conversione da una matrice a un puntatore è sostanziale. Potresti essere tentato di preservare il tipo di elemento, semplificando in tal modo anche l'aritmetica del puntatore. Vale la pena notare che solo una conversione in char* è considerata un comportamento definito da reinterpret_cast : http://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing

Non puoi Sono tipi fondamentalmente diversi.

Non sono sicuro se stavi cercando qualcosa di simile. Dovresti fornire maggiori dettagli su ciò che desideri ottenere. Sono tipi fondamentalmente diversi. Una soluzione è sotto.

Per la cronaca, se qualcuno lo trova utile:

 // define matrix double A[3][3] = { { 1, 2, 3}, { 4, 5, 6}, { 7, 8, 9} }; // allocate memory double ** A_ptr = (double **) malloc(sizeof (double *) * 3); for (int i = 0; i < 3; i++) A_ptr[i] = (double *) malloc(sizeof (double) * 3); // copy matrix for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { A_ptr[i][j] = A[i][j]; printf(" %f ", A_ptr[i][j]); } }