10 Stimmen

Kann nicht von 'int *' in 'int []' konvertiert werden?

Ich weiß, dass dies eine häufig gestellte Frage sein könnte, aber ich habe versucht zu suchen, aber kann immer noch keine klare Antwort finden.

Ich habe den folgenden Code:

int* f() {
    int a[] = {1,2,3};
    return a;
}

int main() {

    int a[] = f(); // Fehler hier

    getch();
    return 0;
}

Dieser Code generiert die Fehlermeldung: "Kann nicht von 'int *' in 'int []' konvertiert werden"

Ich fand das ziemlich seltsam, weil ich gelesen habe, dass Pointer und Arrays ähnlich sind. Zum Beispiel können wir a[i] anstelle von *(a + i) verwenden. Kann mir bitte jemand eine klare Erklärung geben?

23voto

Alexander Gessler Punkte 44223

Es gibt tatsächlich zwei Fehler in diesem Code.

Erstens gibst du die Adresse eines temporären Objekts zurück (das int-Array innerhalb von f), daher sind seine Inhalte nach dem Funktionsaufruf nicht definiert. Jeder Versuch, auf den Speicher zuzugreifen, auf den der zurückgegebene Zeiger zeigt, wird zu undefiniertem Verhalten führen.

Zweitens gibt es in C++ keine implizite Konvertierung von Zeigern auf Array-Typen. Sie sind ähnlich, aber nicht identisch. Arrays können zu Zeigern zerfallen, aber andersherum funktioniert es nicht, da Informationen verloren gehen - ein Zeiger repräsentiert nur eine Speicheradresse, während ein Array die Adresse eines zusammenhängenden Bereichs repräsentiert, typischerweise mit einer bestimmten Größe. Außerdem können Arrays nicht zugewiesen werden.

Zum Beispiel können wir a[i] statt *(a + i) verwenden

Dies hat jedoch wenig mit den Unterschieden zwischen Arrays und Zeigern zu tun, es handelt sich nur um eine syntaktische Regel für Zeigertypen. Da Arrays zu Zeigern zerfallen, funktioniert es auch für Arrays.

12voto

Matteo Italia Punkte 119470

Der Typ int[] existiert eigentlich nicht.

Wenn Sie ein Array wie folgt definieren und initialisieren:

int a[] = {1,2,3};

dann zählt der Compiler die Elemente im Initialisierer und erstellt ein Array der richtigen Größe; in diesem Fall wird es magischerweise zu:

int a[3] = {1,2,3};

int[], wenn es als Parameter an eine Funktion übergeben wird, ist einfach nur int *, also ein Zeiger auf das erste Element des Arrays. Es wird keine weitere Information damit übertragen, insbesondere nicht über die Größe. Das Gleiche gilt, wenn Sie einen Zeiger zurückgeben

Beachten Sie, dass ein Array kein Zeiger ist: Ein Zeiger kann so geändert werden, dass er auf andere Dinge zeigt, während ein Array immer auf denselben Speicher verweist; Ein Zeiger weiß nicht, wie groß der Speicherplatz ist, auf den er zeigt, während die Größe eines Arrays immer zur Kompilierzeit bekannt ist. Die Verwirrung entsteht daraus, dass ein Array in vielen Situationen zu einem Zeiger auf sein erstes Element zerfällt, und das an eine Funktion übergeben/aus einer Funktion zurückgegeben wird.

Warum funktioniert Ihr Code also nicht? Es gibt zwei große Fehler:

  1. Sie versuchen, ein Array mit einem Zeiger zu initialisieren. Wir haben gesagt, dass ein int * keine Informationen über die Größe des Arrays enthält. Es ist nur ein Zeiger auf das erste Element. Der Compiler kann also nicht wissen, wie groß a gemacht werden sollte, um das von f() zurückgegebene Zeug aufzunehmen.

  2. In f geben Sie einen Zeiger auf eine Variable zurück, die lokal für diese Funktion ist. Das ist falsch, weil ein Zeiger die Daten tatsächlich nicht speichert, er zeigt nur darauf, wo die Daten gespeichert sind, also in Ihrem Fall auf das in f lokale a. Da dieses Array lokal für die Funktion ist, hört es auf zu existieren, wenn die Funktion verlassen wird (also beim return).

    Dies bedeutet, dass der von Ihnen zurückgegebene Zeiger auf Dinge zeigt, die nicht mehr existieren; betrachten Sie den Code:

    int * a = f();

    Diese Initialisierung funktioniert, und Sie können versuchen, a später in der Funktion zu verwenden, aber a wird auf das nicht mehr existierende Array von f zeigen; im besten Fall wird Ihr Programm abstürzen (und Ihnen sofort auffallen, dass Sie etwas falsch gemacht haben), im schlimmsten Fall wird es eine Weile zu funktionieren scheinen und dann seltsame Ergebnisse liefern.

2voto

Heisenbug Punkte 38304

Int * und int [] sind ähnlich aber unterschiedlich. int * ist ein echter Zeiger, während int[] eine Array-Referenz (eine Art "konstanter Zeiger" zum Beginn der Daten) ist, der nicht geändert werden kann. Ein int * kann also wie ein int [] behandelt werden, aber nicht umgekehrt.

0voto

David Hammen Punkte 31452

Sie können a[b] und *(a+b) austauschbar verwenden, weil genau so a[b] definiert ist, wenn einer von a oder b ein Zeiger ist und der andere vom Typ Integer oder Aufzählung ist.

Hinweis: Das bedeutet auch, dass Ausdrücke wie 42[a] völlig legal sind. Menschliche Leser könnten sich stark dagegen wehren, aber der Compiler wird deswegen kein Augenlid zucken.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X