Arrays, Parameter



  • Hallo Leute!
    Ich lerne C++ und habe keine Vorkenntnisse.

    Meine Frage: Auf was muss man aufpassen wenn man Arrays als Parameter übergibt?

    Meine Antwort: Wichtig ist zu wissen das nicht das Array selbst kopiert wird sondern die Adresse werden übergeben. Aber was hat das für Auswirkungen? Änderungen der Funkion an dem Array schlagen auf das Array in der Aufrufffunktion.

    Kann mir das jemand kurz, verständlich erklären? 🙂



  • cesar++ schrieb:

    Kann mir das jemand kurz, verständlich erklären? 🙂

    Deine eigene Antwort?


  • Mod

    Man übergibt normalerweise keine Arrays, aus gleich mehreren Gründen:

    • Man kann sowieso keine Arrays an Funktionen übergeben. Zumindest wenn man mit "Array" den eingebauten Datentyp meint. Wenn eine Funktion scheinbar ein Array als Parameter hat, ist das bloß eine andere Schreibweise dafür, dass die Funktion einen Zeiger als Parameter hat:
    void foo(int bar[123]);
    // exakt gleichbedeutend zu
    void foo(int *bar);
    

    Arrays sind hier die große Ausnahme, da sie sich somit anders verhalten als alle anderen Datentypen.

    • Arrays im obigen Sinne benutzt man aber in C++ sowieso äußerst selten, insbesondere weil obige Ausnahme nervt. Normalerweise benutzt man arrayartige Datenstrukturen, wie z.B. std::vector oder std::array, die auch eine Ansammlung mehrerer Elemente sind, aber bezüglich Funktionsparametern keine komischen Ausnahmen darstellen.

    • Bei diesen arrayartigen Datenstrukturen müsste man in der Tat aufpassen, dass man nicht versehentlich teure Kopieraktionen macht, die man gar nicht möchte. Bei diesen Datentypen würde man dies, wie üblich, mittels Referenzparametern erreichen.

    • Die "richtige" Antwort ist aber, dass man überhaupt gar nicht arrayartige Datenstrukturen (und insbesondere auch keine Arrays) direkt an Funktionen übergibt. Normalerweise übergibt man einfach nur Anfang und Ende einer solchen Ansammlung von Elementen. So erreicht man gleich mehrere tolle Effekte:

    • Die ganze Kopierproblematik entfällt komplett

    • Es ist nicht mehr notwendig, zu wissen, welchen Datentyp die Ansammlung denn nun genau hat oder wie genau solch eine Ansammlung zu benutzen ist. Denn normalerweise ist einer Funktion vollkommen egal, ob die Daten nun in einem Array, einem std::vector, oder als irgendeine selbstgeschriebene Datenstruktur vorliegen. Mit dieser Technik bleibt die Funktion frei von unnötigen Einschränkungen bezüglich ihrer Benutzung.

    Diese Technik siehst du bei so ziemlich allen Funktionen der Standardbibliothek. Beispielsweise std::sort, welches (in seiner üblichsten Variante) folgende Signatur hat:

    template< class RandomIt >
    void sort( RandomIt first, RandomIt last );
    

    Keine Arrays, kein std::vector, keinerlei Festlegung auf irgendetwas. Denn std::sort ist es vollkommen egal, was genau es sortiert, Hauptsache es hat irgendwie einen Anfang (first) und ein Ende (last). Aufruf zum Beispiel so:

    int meinArray[5] = {4,7,3,9,1};
    std::sort(meinArray, meinArray+5);
    

  • Mod

    SeppJ schrieb:

    template< class RandomIt >
    void sort( RandomIt first, RandomIt last );
    

    Keine Arrays, kein std::vector, keinerlei Festlegung auf irgendetwas.

    Es legt sich auf nichts fest, das nicht nötig wäre. Ranges (Verallgemeinerung von Arrays und Containern) können etwas allgemeiner gefasst werden, wenn man einen Iterator und ein Sentinel nimmt, was im Ranges TS berücksichtigt wird. Das hat allerdings weniger mit Ausdruckskraft, als mit Effizienz zu tun (ich brauche sonst einen zusätzlichen Zustand in meinem Iterator, der das Ende signalisiert, was in einigen Fällen einen überflüssigen bool zur Folge hat).


  • Mod

    Arcoth schrieb:

    SeppJ schrieb:

    template< class RandomIt >
    void sort( RandomIt first, RandomIt last );
    

    Keine Arrays, kein std::vector, keinerlei Festlegung auf irgendetwas.

    Es legt sich auf nichts fest, das nicht nötig wäre. Ranges (Verallgemeinerung von Arrays und Containern) können etwas allgemeiner gefasst werden, wenn man einen Iterator und ein Sentinel nimmt, was im Ranges TS berücksichtigt wird. Das hat allerdings weniger mit Ausdruckskraft, als mit Effizienz zu tun (ich brauche sonst einen zusätzlichen Zustand in meinem Iterator, der das Ende signalisiert, was in einigen Fällen einen überflüssigen bool zur Folge hat).

    Ich würde mich freuen über eine Erklärung, die auch cesar++ versteht. Ich fürchte, meine Erklärung war schon viel zu hoch, weil ich quasi 400 Seiten Lehrbuch in 4 Absätzen zusammengefasst habe 😃



  • OK Danke Leute für die Antworten. Ihr habt mir weitergeholfen .
    🙂 👍
    & Danke für die rasche Rückmeldung.

    wenn ich wieder so kurze Fragen habe, kann ich jedesmal einen Thread aufmachen wenn ich nichts finde wo die Frage dazupasst? 😕


  • Mod

    Selbstredend.

    Im Übrigen war das keine "kleine" Frage, wie man an der Menge von Information, die wir dazu erwähnen konnten, sieht.


Anmelden zum Antworten