2013-04-02 27 views
9

ho tale matrice nel mio programma:C++ colata statica a doppia matrice bidimensionale di raddoppiare **

double m[3][4] = 
    { 
     {2, 4, 5, 7}, 
     {4, 5, 1, 12}, 
     {9, 12, 13, -4} 
    }; 

E vorrei gettarlo ai double** tipo.

Ho già provato semplice double** a = (double**)m;, ma non funziona (quando provo a leggere qualsiasi valore, ottengo "Accesso alla violazione di lettura posizione 0x00000000.", Il che significa che sto cercando di leggere dall'indirizzo NULL.

ho trovato quasi soluzione di lavoro:

double *b = &m[0][0]; 
double **c = &b; 

funziona quando ho letto campo c[0][any] ma lo stesso indirizzo NULL problema di lettura si verifica, quando si tenta di leggere il valore dal campo c[1][0]

.

Qual è il modo corretto di trasmettere la mia matrice double m[3][4] per digitare double**?

modifica: Tu dici che è impossibile. Quindi cambierò un problema un po '. Come posso passare il doppio array bidimensionale come parametro per una funzione? La mia funzione ha un prototipo:

void calculate(double **matrix, int n); //where matrix size is always n by n+1 

E funziona perfettamente con array allocati dinamicamente. Dubito che l'unico modo per farlo funzionare è allocare nuovo array dinamico e copiare un array statico originale un elemento di un altro ...

+0

casting non ha intenzione di fare questo lavoro. Un 'double **' richiede un puntatore a un puntatore a un double, e non è quello che hai. È possibile * probabilmente * cavarsela con un 'double *' e passare in modo esplicito le dimensioni dell'array. –

+1

Un array di matrici e un puntatore a un puntatore non è la stessa cosa. Il layout in memoria non corrisponde, quindi non è possibile utilizzarne uno per l'altro. –

+1

Usa la tecnica proposta da Vaughn Cato. Se prende un 'double **', devi dargli un 'double **' e non un array bidimensionale. –

risposta

9

Non è possibile trasmettere l'array. Si sta andando ad avere per creare qualcosa di simile:

double m[3][4] = 
    { 
     {2, 4, 5, 7}, 
     {4, 5, 1, 12}, 
     {9, 12, 13, -4} 
    }; 

double *marray[3] = {m[0],m[1],m[2]}; 
calculate(marray,3); 

Oppure si può utilizzare un ciclo:

const size_t n = 3; 
double *marray[n]; 
for (size_t i=0; i!=n; ++i) { 
    marray[i] = m[i]; 
} 
calculate(marray,n); 
+0

Questo non funzionerà nel mio caso. La matrice può avere dimensioni, ad esempio 100 x 100. E non scriverò '{m [0], m [1], m [2], ..., m [99]};' nel mio codice :) –

+1

@gogowitczak: In tal caso, puoi usare un ciclo (risposta aggiornata). –

+0

Non è così semplice. Suppongo che 'array' possa avere dimensioni differenti che non sono conosciute in fase di compilazione, ovvero,' n' non è una costante di tempo di compilazione. Quindi 'marray' deve essere assegnato dinamicamente. Potrebbe andare bene, ma se vuoi evitare l'allocazione dinamica usa un modello come spiegherò nella mia risposta. –

14

Non è possibile.

La notazione double** si riferisce a una matrice di puntatori. Non hai una serie di puntatori, hai una matrice di matrici di doppi.

0

È possibile passare una matrice 2D come parametro di funzione:

void calculate(double matrix[][y], int n);

0

Fino a quando gli array di lunghezza variabile sono nello standard C++, le tue scelte includono:

  • Se il compilatore supporta array di lunghezza variabile come un'estensione, è probabile che li passi con una dichiarazione di funzione come void foo(std::size_t n, double a[][n+1]). Si noti che il compilatore probabilmente richiede che sia passato n prima di una dichiarazione di parametro che utilizza n o richiede una sintassi speciale.
  • È possibile passare un double * e fare index aritmetica manualmente nella funzione: void foo(std::size_t n, double *a) { … a[row*(n+1) + column] … }
  • È possibile creare una classe implementa le matrici di lunghezza variabile facendo aritmetica dell'indice nelle sue funzioni di accesso.
  • È possibile allocare lo spazio per i puntatori n su double, riempire i puntatori con puntatori a ciascuna riga della matrice e passare l'indirizzo dello spazio.
1

Se si utilizzano sempre gli array (senza puntatori) per l'inizializzazione e si è in grado di evitare il puntatore nella funzione di calcolo, è possibile prendere in considerazione la seguente opzione, che utilizza la deduzione delle dimensioni per modelli.

template<int m, int n> 
void doubleFunc(double (&mat)[m][n]) 
{ 
    for (auto i = 0; i < m; i++) 
    { 
     for (auto j = 0; j < n; j++) 
     { 
      std::cout << mat[i][j] << std::endl; 
     } 
    } 
} 

Ha funzionato durante il mio test rapido.

double m[3][4] = 
{ 
    {2, 4, 5, 7}, 
    {4, 5, 1, 12}, 
    {9, 12, 13, -4} 
}; 

doubleFunc(m); 
7

Quando si scrive

double m[3][4] 
    { 
     {2, 4, 5, 7}, 
     {4, 5, 1, 12}, 
     {9, 12, 13, -4} 
    }; 

Il compilatore crea effettivamente una serie di doppie come se si fosse scritto

double _m[] = {2, 4, 5, 7, 4, 5, 1, 12, 9, 12, 13, -4}; 

Tuttavia, grazie al sistema di tipo C/C++, il compilatore ricorda il tipo m è double [3][4]. In particolare si ricorda le grandezze 3 e 4.

Quando si scrive

m[i][j] 

il compilatore sostituisce con

_m[i * 4 + j]; 

(Il 4 proviene dalla seconda dimensione in double [3][4].) Ad esempio , m[1][2] == 1 e _m[1 * 4 + 2] == _m[6] == 1 pure.

Come altri hanno detto, uno double** è un tipo diverso che non supporta le dimensioni con esso. Considerare double** a come una matrice 3 x 4, a[0], a[1] e a[2] devono essere puntatori a double (cioè, double*) che punta al primo elemento della riga corrispondente . È possibile raggiungere questo obiettivo con

double* rows[] = { &m[0][0], &m[1][0], &m[2][0] }; 
double** a = &rows[0]; 

Una semplice fusione non crea la variabile rows sopra. Mi permetta di presentare altri modi alternativa (ma equivalente) per definire rows

double* rows[] = { &m[0][0], &m[0][0] + 4, &m[0][0] + 2 * 4}; 
double* rows[] = { &_m[0], &_m[4], &_m[2 * 4]}; 

Come si può vedere, solo la seconda dimensione (cioè 4) è necessario. In generale, per gli array multidimensionali , sono necessarie tutte le dimensioni, ma la prima. Per questo motivo una matrice 1-dimensionale

double x[4] = { 1, 2, 3, 4 }; 

può essere convertito in modo implicito un double*

double* y = x; 

Usando questo fatto si può anche scrivere

double* rows[] = { _m, _m + 4, _m + 2 * 4}; 

Infatti, _m viene convertito a double* che punta a m[0].Quindi, in _m + 4, _m viene convertito in un double* che punta a m[0] ea questo puntatore è aggiunto 4. Quindi, _m + 4 è un puntatore della quarta doppia successiva a _m[0], che è _m[4] e così via.

Finora ho spiegato il motivo per cui non è possibile trasmettere uno double [3][4] (o altre dimensioni) a double**. Ora, mostrerò, nel tuo caso particolare, come può essere calcolato il calcolo.

template <int N> 
void calculate(double (&m)[N][N+1]) { 
    // use m as a double[N][N+1] 
} 

ti chiamano

calculate(m); 

e il compilatore dedurre la dimensione N per voi. In generale (vale a dire, quando la seconda dimensione non è il N + 1) è possibile scrivere

template <int N, int M> 
void calculate(double (&m)[N][M]) { 
    // use m as a double[N][M] 
}