Frage

Wenn Sie den folgenden Code kompilieren:

void DoSomething(int Numbers[])
{
    int SomeArray[] = Numbers;
}

der VS2005-Compiler mit dem Fehler C2440 klagt: 'initialisieren': Konvertierung von 'int []' to 'int []

Ich verstehe, dass es versucht, einen Zeiger auf ein Array wirklich zu werfen, die zur Arbeit geht nicht. Aber wie erklären Sie den Fehler zu jemandem Lernen C ++?

War es hilfreich?

Lösung

Es gibt drei Dinge, die Sie an die Person zu erklären, müssen Sie zu helfen, sind versuchen:

  1. Arrays können nicht von Wert an eine Funktion in C weitergegeben ++. tun, was Sie zu tun versuchen, müssen Sie die Adresse des Beginns des Arrays zu übergeben DoSomething() sowie die Größe des Arrays in einem separaten int Argumente (na ja, size_t, aber ich würde das nicht die Mühe zu sagen). Sie können die Adresse des Beginns einiger Array myArray mit dem Ausdruck &(myArray[0]) bekommen. Da es sich um eine solche gemeinsame Sache tun zu wollen, C ++ können Sie nur den Namen des Arrays verwenden - zum Beispiel myArray - die Adresse seines ersten Elements zu erhalten. (Welche hilfreich oder verwirrend sein kann, je nachdem, welche Art und Weise man es betrachtet.) Um die Dinge noch verwirrender, C ++ können Sie ein Array-Typ (zB int Numbers[]) als Parameter an eine Funktion spezifizieren, aber heimlich behandelt es, dass der Parameter ein erklärter als Zeiger (int *Numbers in diesem Fall), als ob es war - man kann sogar Numbers += 5 innen DoSomething() tun, um es auf ein Array zu machen Punkt der sechsten Position beim Start

  2. Wenn Sie ein Array-Variable wie SomeArray in C ++ deklarieren, müssen Sie entweder eine explizite Größe zur Verfügung stellen oder eine „initialiser Liste“ , die eine durch Kommata getrennte Liste von Werten zwischen Klammer ist . Es ist nicht möglich, dass der Compiler die Größe des Arrays auf einem anderen Array basierte ableiten, dass Sie mit ihm zu initialisieren versuchen, weil ...

  3. Sie können ein Array in eine anderen nicht kopieren, oder von einem anderen in C einen Array initialisieren ++. So, selbst wenn der Parameter Numbers war wirklich ein Array (etwa der Größe 1000) und nicht ein Zeiger, und die Größe von SomeArray (wieder sagen, 1000) angegeben, würde die Linie int SomeArray[1000] = Numbers; illegal sein.


Zu tun, was Sie in DoSomething() tun wollen, zuerst fragen Sie sich:

  1. Muss ich alle Werte in Numbers ändern müssen?
  2. Wenn ja, kann ich den Anrufer verhindern möchten, dass diese Änderungen zu sehen?

Wenn die Antwort auf beide Fragen „Nein“ lautet, können Sie in der Tat nicht über eine Kopie von Numbers in erster Linie machen müssen -. Es einfach verwenden wie es ist, und vergessen einen separaten SomeArray Array über die Herstellung

Wenn die Antwort auf beide Fragen „Ja“ lautet, müssen Sie eine Kopie von Numbers in SomeArray machen und stattdessen daran zu arbeiten. In diesem Fall sollten Sie wirklich SomeArray eine C ++ vector<int> anstelle eines anderen Array machen, da dies wirklich die Dinge vereinfacht. (Erklären Sie die Vorteile von Vektoren über manuelle dynamische Speicherzuweisung, einschließlich der Tatsache, dass sie können aus anderen Arrays oder Vektoren initialisiert werden, und sie werden Elementkonstruktoren rufen, wenn nötig, im Gegensatz zu einem C-Stil memcpy().)

Andere Tipps

Sprich

, dass es Typen und unvollständige Typen:

struct A;

Ist ein unvollständiger Typ einer Struktur namens A. Während

struct A { };

Ist eine Art einer Struktur namens A. Die Größe des ersten ist noch nicht bekannt, während die Größe des zweiten bekannt ist.

Es gibt unvollständige Klassentypen wie die oben genannte Struktur. Aber es gibt auch unvollständige Array-Typen:

typedef int A[];

Das ist ein unvollständiger Array-Typ namens A. Seine Größe ist noch nicht bekannt. Sie können nicht ein Array aus ihm heraus erstellen, da der Compiler nicht weiß, wie groß das Feld ist. Aber Sie können verwenden es ein Array zu erstellen, nur , wenn Sie initialisieren es sofort:

A SomeArray = { 1, 2, 3 };

Nun weiß die Compiler das Array ein int-Array mit 3 Elementen ist. Wenn Sie versuchen, das Array mit einem Zeiger zu initialisieren, wird der Compiler nicht klüger als zuvor sein, und weigert sich, denn das wird ihm nicht die Größe des Arrays gibt geschaffen werden.

Bei dem Versuch, die Fehlermeldung hilfreicher zu machen, ist der Compiler tatsächlich verwirrend Dinge. Auch wenn der Numbers Parameter als ein Array deklariert wird, C / C ++ nicht (kann nicht) tatsächlich ein Array übergeben -. Der Numbers Parameter ist eigentlich ein Zeiger

So ist der Fehler sollte wirklich "cannot convert from 'int *' to 'int []'" sagen

Aber dann wäre es Verwirrung sein - „Hey, es gibt keine int* im Ausdruck beteiligt“, könnte jemand sagen,

.

Aus diesem Grunde ist es wirklich besser Array-Parameter zu vermeiden - erklären sie als Zeiger, denn das ist, was Sie wirklich sowieso bekommen. Und die Erklärung jemand Lernen C / C ++ sollte sich auf der Tatsache erziehen, dass Array-Parameter sind eine Fiktion -. Sie sind wirklich Zeiger

Wenn ich versuche, etwas zu erklären, ich versuche immer zu gehen bis auf die unterste Ebene und bauen von dort oben. Das ist sie Art und Weise Ich mag Dinge lernen, und ich finde, dass die Menschen sich wohler, wenn Sie mit den Grundlagen beginnen, die sie kennen, und bauen von dort aus.

In diesem Fall würde ich wahrscheinlich mit etwas beginnen wie:

  

Der Compiler versucht, das zu tun   Zuordnung, da Sie schrieb ein   Zuweisungsoperation. In C ++, Sie   kann nicht direkt zu einem Array zugeordnet werden,   denn es verfügt über keine integrierte in Zuordnung   Operator (jeglicher Art, Nur   Initialisierer und Indexieren wird unterstützt   für Arrays). Da C ++ unterstützt   überladene Operatoren für Arten, die   Compiler sucht dann nach einem überlasteten   Zuweisungsoperator für die   „Zugeordnet zu“ Typ, der nimmt die   „Zugewiesen-vom“ Typ als Argument.   Da gibt es auch überlastet keine   Operator für int [] der nimmt int []   als Argument, die Compiler-Fehler auf   die Linie, und die Fehler sagen Ihnen,   warum kann der Compiler nicht die Zeile verarbeiten.

Ja, es ist wahrscheinlich übertrieben vs nur sagen, etwas über das Wissen der Größe, unvollständige Typen, etc. Ich weiß, es ist auch nicht vollständig (zB: keine Diskussion über initializer Zuordnung im Vergleich zu normaler Zuordnung, etc.). Aber mein Ziel ist es in der Regel Menschen zu bekommen, wo sie die nächsten Antwort selbst herausfinden können, und für, dass Sie in der Regel legen wollen den Denkprozess bei der Antwort für ankommen.

Vielleicht ist Ihre Antwort könnte sein: „Weil der Compiler nicht weiß, wie groß das Feld ist.“

Ihr Beispiel funktionieren könnte, wenn es explizit Feldgrößen waren (vielleicht mit einem typedef für Klarheit), und dann können Sie Zeiger erklären, während variable Größe Zuweisungen einzuführen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top