Come si fa a dare un senso l'errore: non può convertire da 'int []' a 'int []'
-
22-08-2019 - |
Domanda
Quando si compila il seguente codice:
void DoSomething(int Numbers[])
{
int SomeArray[] = Numbers;
}
il compilatore VS2005 si lamenta con il C2440 errore: 'inizializzazione': impossibile convertire da 'int []' a 'int []'
ho capito che in realtà si sta cercando di lanciare un puntatore ad un array che non sta andando a lavorare. Ma come si spiega l'errore a qualcuno imparare C ++?
Soluzione
Ci sono tre cose è necessario spiegare alla persona che si sta cercando di aiutare:
-
array non possono essere passati per valore a una funzione in C ++. Per fare ciò che si sta cercando di fare, è necessario passare l'indirizzo di inizio della matrice per
DoSomething()
, così come la dimensione della matrice in unint
separata (beh,size_t
, ma vorrei non preoccupatevi dicendo che) argomentazione. È possibile ottenere l'indirizzo di inizio di qualchemyArray
array con il&(myArray[0])
espressione. Dal momento che questa è una cosa comune a voler fare, C ++ consente di utilizzare solo il nome della matrice - per esempiomyArray
- per ottenere l'indirizzo del suo primo elemento. (Che può essere utile o confuse, a seconda del modo in cui la si guarda.) Per rendere le cose ancora più confuse, C ++ consente di specificare un tipo di matrice (ad esempioint Numbers[]
) come parametro a una funzione, ma segretamente si tratta quel parametro come se fosse un dichiarato come un puntatore (int *Numbers
in questo caso!) - si può anche fareNumbers += 5
all'internoDoSomething()
per renderlo puntare a una serie a partire dalla sesta posizione -
Quando si dichiara una variabile di matrice come
SomeArray
in C ++, è necessario fornire una dimensione esplicita o un "elenco initialiser" , che è un elenco separato da virgole di valori tra parentesi . Non è possibile per il compilatore di dedurre la dimensione della matrice in base a un altro array che si sta tentando di inizializzare con, perché ... -
Non è possibile copiare un array in un altro, o inizializzare un array da un altro in C ++. Quindi, anche se il parametro
Numbers
è stato davvero un array (ad esempio del formato 1000) e non un puntatore, e si è specificato la dimensione delSomeArray
(di nuovo come dire 1000), la linea diint SomeArray[1000] = Numbers;
sarebbe illegale.
Per fare ciò che si vuole fare in DoSomething()
, prima chiedetevi:
- Ho bisogno di cambiare uno dei valori in
Numbers
? - Se è così, voglio evitare che il chiamante di vedere questi cambiamenti?
Se la risposta ad entrambe le domande è "No", non è infatti necessario effettuare una copia di Numbers
in primo luogo -. Basta usare come è, e dimenticare di fare un allineamento SomeArray
separata
Se la risposta ad entrambe le domande è "Sì", sarà necessario fare una copia di Numbers
in SomeArray
e lavorare su questo, invece. In questo caso, si dovrebbe davvero fare un SomeArray
vector<int>
C ++ al posto di un altro array, in quanto ciò semplifica molto le cose. (Spiegare i vantaggi dei vettori oltre allocazione dinamica della memoria manuale, compresi i fatti che hanno possono essere inizializzato da altri array o vettori, e si chiameranno costruttori di elementi quando necessario, a differenza di un memcpy()
C-style.)
Altri suggerimenti
dicono che ci sono tipi e tipi incomplete:
struct A;
È un tipo incompleto di una struttura chiamata A. Mentre
struct A { };
è un tipo completo di una struttura chiamata A. La dimensione del primo non è ancora noto, mentre la dimensione della seconda è noto.
Ci sono tipi di classe incompleti come struct sopra. Ma ci sono anche i tipi di array incomplete:
typedef int A[];
Questo è un tipo di matrice incompleta chiamato A. La sua dimensione non è ancora noto. Non è possibile creare una matrice fuori di esso, perché il compilatore non sa quanto è grande l'array è. Ma si può usare per creare un array, solo se si inizializza esso subito:
A SomeArray = { 1, 2, 3 };
Ora, il compilatore conosce la matrice è un array int con 3 elementi. Se si tenta di inizializzare l'array con un puntatore, il compilatore non essere più intelligente di prima, e rifiutare, perché non sarà dare la dimensione della matrice da creare.
Nel tentativo di rendere il messaggio di errore più utile, il compilatore è in realtà le cose confuse. Anche se il parametro Numbers
viene dichiarato come una matrice, C / C ++ non (non può) in realtà passare un array -. Il parametro Numbers
è in realtà un puntatore
Quindi, l'errore in realtà dovrebbe dire "cannot convert from 'int *' to 'int []'"
Ma allora non ci sarebbe confusione - "hey, non c'è int*
coinvolti nell'espressione", qualcuno potrebbe dire
Per questo motivo è davvero meglio evitare parametri array - li dichiarare come puntatori, dato che è quello che stai veramente ottenere comunque. E la spiegazione a qualcuno l'apprendimento C / C ++ li dovrebbe educare sul fatto che i parametri di matrice sono una finzione -. Sono davvero puntatori
Quando sto cercando di spiegare qualcosa, cerco sempre di andare giù al livello più basso, e costruire da lì. Questo è il loro modo mi piace imparare le cose, e trovo che le persone sono più a suo agio se si inizia con le nozioni di base che sanno, e costruire da lì.
In questo caso, probabilmente iniziare con qualcosa di simile:
Il compilatore sta cercando di fare il assegnazione, perché hai scritto un operazione di assegnazione. In C ++, è non può assegnare direttamente a una matrice, perché non ha alcuna assegnazione incorporato operatore (di qualsiasi tipo, solo inizializzatore e indicizzazione è supportata per gli array). Perché supporti C ++ operatori di overload per i tipi, le compilatore cerca poi per un sovraccarico operatore di assegnazione per la "Assigned-to" tipo che prende il "Assegnato-da" tipo come argomento. Dal momento che c'è anche nessun sovraccarico operatore int [] che prende int [] come argomento, gli errori del compilatore su la linea, e gli errori sta dicendo il motivo per cui il compilatore non è in grado di elaborare la linea.
Sì, è probabilmente eccessivo vs solo dicendo qualcosa circa la conoscenza delle dimensioni, tipi incompleti, ecc mi rendo conto che è anche non completo (ad es: nessuna discussione di assegnazione di inizializzazione vs assegnazione normale, ecc). Tuttavia, il mio obiettivo è di solito per convincere la gente a cui possono capire la risposta successiva se stessi, e per questo di solito si vuole tracciare il processo di pensiero per arrivare alla risposta.
Forse la tua risposta potrebbe essere: "Perché il compilatore non sa quanto è grande la matrice è".
Il tuo esempio potrebbe funzionare se non ci fossero formati matrice espliciti (magari con un typedef per chiarezza), e quindi si può spiegare puntatori mentre l'introduzione di allocazioni di dimensioni variabili.