2016-05-01 7 views
1

Ich versuche C++ zu lernen, aber ich kann diesen Code hier einfach nicht einpacken, obwohl ich viel Zeit für die Suche nach einem Antwort:C++ - Grundlagen: auf der Basis von for-loop und Übergabe von C-artigen Arrays an Funktionen

#include <iostream> 

void printArray1(int (&array)[3]) { 
    for(int x : array) 
     std::cout << x << " "; 
} 

void printArray2(int array[]) { 
    for(int x : array) // compiler error, can't find begin and end 
     std::cout << x << " "; 
} 

int main() { 
    int a[3] = {34,12,88}; 

    for(int x : a) 
     std::cout << x << " "; 
    std::cout << std::endl; 

    printArray1(a); 
    printArray2(a); 
    std::cout << std::endl; 

    return 0; 
} 

In printArray1, wir erhalten einen Parameter, der eine Referenz auf ein Array der Größe ist 3. Bedeutet dies, dass wir die Adresse des gesamten Arrays erhalten oder erhalten wir nur eine Adresse an den ersten Element im Array der Größe 3? Wie wird dieser Parameter dann an die Schleife übergeben?

In printArray2 erhalten wir einen Zeiger auf das erste Element im Array, richtig? Mit anderen Worten, wir erhalten auch eine Adresse wie in printArray1? Daher wird die forwarded-basierte for-Schleife in dieser Funktion nicht kompiliert, weil wir keine Größenangaben für das Array haben, richtig?

Schließlich, wenn wir versuchen, mit der Entfernungs-basierten for-Schleife in main zu drucken, was passieren wir genau in der Schleife? Ist es hier ein Zeiger auf das erste Element im Array, und wenn ja, warum kompiliert es, wenn die for-Schleife in printArray2 den Zeiger nicht akzeptiert?

Mein Verständnis von C++ ist immer noch ziemlich elementar, so dass ich die Hilfe wirklich schätze, danke!

+0

Haben Sie es selbst gesehen, indem Sie Ihr Programm debuggen? Was druckt es? –

Antwort

2

Die bereichsbasierte for-Schleife funktioniert für alle Typen, die mit std::begin und std::end verwendet werden können.

Arrays und Zeiger sind nicht gleich. Ein Array hat eine feste Größe, ein Zeiger nicht. Daher funktionieren std::begin und std::end für Arrays - aber nicht für Zeiger. Das erklärt auch, warum die bereichsbasierte for-Schleife für einen, aber nicht für den anderen funktioniert.

Arrays können auch zu Zeigern zerfallen. Dies geschieht beispielsweise, wenn es an Funktionen übergeben wird, die einen Zeigerparameter verwenden. Oder, wenn sie an Funktionen übergeben werden, die einen Array-Parameter von unbestimmter Größe benötigen (was im Grunde dasselbe wie ein Zeigerparameter ist). Wenn das passiert, ist die Größeninformation wieder verloren.

Es hängt also davon ab, wie Sie die Funktion definieren. Die erste Funktion nimmt ein Array, die zweite einen Zeiger. Aus diesem Grund werden bei der ersten Größe Informationen beibehalten und die Schleife funktioniert.

Es begrenzt jedoch, was die Funktion ausführen kann. Die zweite Funktion kann eine int b[2] dauern, während die erste nicht kann.

+0

Also, wenn ich die Kennung _a_ in main() verwende, übergebe ich einen Array-Typ an die Schleife, richtig? Aber _a_ ist immer noch eine Adresse für das erste Element im Array, wie ein Zeiger, außer dass es eine feste Größe hat, wie Sie gesagt haben? – Joey

+0

Nicht ganz, "a" ist keine "Adresse" für das erste Element im Array, zu keinem Zeitpunkt. 'a' ist * das * Array, das eine feste Größe hat. Man sollte nicht einmal an Arrays und Zeiger als die gleichen Typen denken, Arrays haben nichts mit Adressen zu tun, die einzige Beziehung ist, dass Arrays in Zeiger bei der Zuweisung zerfallen können (ob es einer Variablen zugewiesen wird oder als Funktion übergeben wird) Parameter). Schauen Sie sich Array-Zerfall an, um mehr darüber zu erfahren. –

+1

Ah ok, so ist es gültig zu sagen, dass es keine Abnahme zum Array gibt, wenn wir _a_ an die bereichsbasierte Schleife übergeben, und dass es keine Abnahme gibt, wenn wir _a_ an die erste Funktion übergeben, wo der Parameter eine Referenz ist , Ja? – Joey

0

Im Fall [3] weiß die Funktion, wie groß das Array von seinem Typ ist. Eine Referenz wird oft als ein Zeiger auf die referenzierte Sache implementiert, aber in C++ werden große Längen durchlaufen, um ein Implementierungsdetail zu lassen (das manchmal Optimierungen ermöglicht). Referenzen sind Aliase für Daten an anderer Stelle, subly anders als Zeiger (die wie postalische Adressen sind). Iteration ist einfach, wenn der Compiler die Länge hat, und C++ macht das Richtige.

Im Fall [] ist dies die C-Syntax. Es ist keine Referenz. Es bedeutet dasselbe wie int * array. Die Größe des Arrays ist weder Teil des Kompilierzeittyps (innerhalb der Funktion) noch des Laufzeitstatus (der ein einzelner int-Zeiger ist). Eine Iteration ist ohne die Länge nicht möglich.

0

Nach cppreference über arrays und Ranged-based for loop

In printArray1 das Array Argument ist ein Array von int verweist die jeweils eine Referenz der ersten 3 Werte des Arrays, das als übergeben wird Streit.

In printArray2 das Array Argument ist ein Zeiger als Punkte auf den ersten Wert des Arrays, das als Argument weitergeleitet wird. Damit können Sie auf alle Werte des Arrays zugreifen.

Schließlich ist es kein Zeiger, sondern nur eine Referenz für das a Array. In diesem speziellen Fall ist es wichtig zu wissen, dass für jede Iteration eine Kopie des iterierten Werts an die Variable x durchgeführt wird. Wenn Sie verhindern möchten, dass all diese Kopien ausgeführt werden, sollten Sie stattdessen eine Referenz angeben.

Beispiel:

for(int &x : a) 
    std::cout << x << " "; 

Btw, sollten Sie auch auf der array container einen Blick darauf werfen, was der moderne Stil-Array ist.

Verwandte Themen