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 ++?

È stato utile?

Soluzione

Ci sono tre cose è necessario spiegare alla persona che si sta cercando di aiutare:

  1. 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 un int separata (beh, size_t, ma vorrei non preoccupatevi dicendo che) argomentazione. È possibile ottenere l'indirizzo di inizio di qualche myArray 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 esempio myArray - 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 esempio int 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 fare Numbers += 5 all'interno DoSomething() per renderlo puntare a una serie a partire dalla sesta posizione

  2. 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é ...

  3. 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 del SomeArray (di nuovo come dire 1000), la linea di int SomeArray[1000] = Numbers; sarebbe illegale.


Per fare ciò che si vuole fare in DoSomething(), prima chiedetevi:

  1. Ho bisogno di cambiare uno dei valori in Numbers?
  2. 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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top