Sinn von Zeigern und Referenzen



  • Hallo zusammen!

    Ich bin jetzt beim Kapitel Zeiger und Referenzen angelangt.

    Hier mal eine Aussage von mir über Zeiger und Referenzen. Bitte korrigiert mich wo ihr nur könnt. Ich möchte nämlich endlich den Sinn von Zeigern und Referenzen begreifen.

    Aussage Zeiger:

    Zeiger sind "Variablen" die Adressen von Variablen eines bestimmten Typs speichern können. Zeiger können auf verschiedene Variablen vom Typ des Zeigers zeigen. Ebenfalls können sie undefiniert (wilder Zeiger) oder NULL sein (Null Zeiger).

    Aussage Referenzen:

    Referenzen sind Alias-Namen für bereits bestehende Variablen. Referenzen dürfen nie Null sein und müssen am Anfang an eine Variable gebunden sein. Der Vorteil von Referenzen ist, wenn man sie als Argument(e) in einer Funktion nutzt, erzeugt man, im Gegensatz zu normalen Variablen, keine Kopien.

    Das waren nun meine Aussagen über Referenzen und Zeiger. Wie gesagt korrigiert mich, wenn ihr einen Fehler entdeckt!!

    Nun aber zu meiner Frage: Ich habe immer noch nicht richtig den Sinn von Zeigern verstanden. Wozu brauche ich denn die Speicheradresse von einer Variablen und was ist der Vorteil von einem Zeiger gegenüber einer Normalen Variable?

    Und noch zwei kleine Fragen: Was bedeuten denn die Abkürzungen imho und stl?

    Danke im Voraus Caipi



  • Caipi schrieb:

    Hallo zusammen!

    Ich bin jetzt beim Kapitel Zeiger und Referenzen angelangt.

    Hier mal eine Aussage von mir über Zeiger und Referenzen. Bitte korrigiert mich wo ihr nur könnt. Ich möchte nämlich endlich den Sinn von Zeigern und Referenzen begreifen.

    Aussage Zeiger:

    Zeiger sind "Variablen" die Adressen von Variablen eines bestimmten Typs speichern können. Zeiger können auf verschiedene Variablen vom Typ des Zeigers zeigen. Ebenfalls können sie undefiniert (wilder Zeiger) oder NULL sein (Null Zeiger).

    Aussage Referenzen:

    Referenzen sind Alias-Namen für bereits bestehende Variablen. Referenzen dürfen nie Null sein und müssen am Anfang an eine Variable gebunden sein. Der Vorteil von Referenzen ist, wenn man sie als Argument(e) in einer Funktion nutzt, erzeugt man, im Gegensatz zu normalen Variablen, keine Kopien.

    Das waren nun meine Aussagen über Referenzen und Zeiger. Wie gesagt korrigiert mich, wenn ihr einen Fehler entdeckt!!

    Nun aber zu meiner Frage: Ich habe immer noch nicht richtig den Sinn von Zeigern verstanden. Wozu brauche ich denn die Speicheradresse von einer Variablen und was ist der Vorteil von einem Zeiger gegenüber einer Normalen Variable?

    Und noch zwei kleine Fragen: Was bedeuten denn die Abkürzungen imho und stl?

    Danke im Voraus Caipi

    Hallo,

    zeiger sind z. B. immer dann erforderlich, wenn du Speicher dynamisch
    reservierst. Du erhaelst dann die Speicheradresse des Anfangs deines
    reservierten Speicherbereiches und den speicherst du in einem Zeiger:

    int *intArray = new int[5];
    

    reserviert Speicher fuer 5 Integer-Werte. Die Adresse, an welcher der
    reservierte Speicherblock beginnt, wird an intArray zugewiesen. Von nun an
    kannst du ueber intArray auf diesen Speicherbereich zugreifen.

    IMHO ist die Abkuerzung fuer 'In my humble opinion' und bedeutet sowas wie
    "Meiner bescheidenen Meinung nach".

    STL ist die Abkuerzung fuer 'Standard Template Library'. Das ist eine
    generische Library (Klassen und Funktionen allegemeiner Art), die einem das
    Leben in der taeglichen Programmierung erleichtern. Vielleicht kennst du schon
    einige Klassen aus der STL, wie z. B. vector, list, deque.

    Hoffe ich konnte dir helfen.

    mfg
    v R



  • hab gerade meyers definition, die er in effective stl benutzt, abgetippt. aber das mistforum hat wiedermal mein posting weggeworfen.



  • Hallo nochmal!

    Erstmal vielen Dank virtuell Realisticer!

    Ich habe mir nun folgendes kleines Programm geschrieben, welches den Speicher dynamisch ermitteln soll.

    Stimmt das so, oder ist ein logischer Fehler darin? (Compilieren lässt es sich) 🙂

    #include <iostream>
    using namespace std;
    
    int main()
    {
            cout << "Bitte Text eingeben:\n";
    
            int chars = 0;
            char character;
            while(cin.get(character) && character != '\n')
            {
                    chars++;
            }
            char *textSize = new char[chars];
            cout << "Es wurde " << textSize << " Byte Speicherplatz reserviert.\n";       
    
            return 0;
    }
    

    Caipi



  • cout << "Es wurde " << textSize << " Byte Speicherplatz reserviert.\n"

    Um die anzahl der bytes zu ermitteln muss diese zeile so aussehen

    cout << "Es wurde " <<(sizeof(textSize)) << " Byte Speicherplatz reserviert.\n"



  • Hallo,

    mit

    cout << "Es wurde " << textSize << " Byte Speicherplatz reserviert.\n";
    

    gibst du lediglich die Startadresse aus, an der der reservierte Speicherbereich
    beginnt. Du gibst aber nicht aus, wieviel Speicher du reserviert hast. Gib dazu
    doch einfach 'chars' aus.

    Das Reservieren hast du korrekt gemacht, was du aber nicht gemacht hast, ist den
    Speicher wiederfreizugeben. Dir fehlt am Schluss noch ein

    delete[] textSize;
    

    Denk immer daran: Den Speicher, den du reservierst, musst du auch wieder frei-
    geben.

    mfg
    v R



  • pin schrieb:

    cout << "Es wurde " << textSize << " Byte Speicherplatz reserviert.\n"

    Um die anzahl der bytes zu ermitteln muss diese zeile so aussehen

    cout << "Es wurde " <<(sizeof(textSize)) << " Byte Speicherplatz reserviert.\n"

    Nein, dass gibt dir nur die Groesse des Zeigers aus, nicht aber die Anzahl
    reservierter Bytes.

    mfg
    v R



  • pin schrieb:

    Um die anzahl der bytes zu ermitteln muss diese zeile so aussehen
    out << "Es wurde " <<(sizeof(textSize)) << " Byte Speicherplatz reserviert.\n"

    sizeof auf nen zeiger anewandt ergibt bei mir immer 4. und das ist ja ein zeiger. wäre es ein array, wäre das was anderes, da klapt sizeof (,solange man es nicht innerhalb einer funktion macht und das array übergeben wurde, denn dabei hat der compiler es heimlich zu nem zeiger zusammen und sizeof decjt das dann auf).



  • Stimmt mein Programm nun, oder muss ich noch plus ein Byte rechnen (wegen Stringende-Zeichen)?

    Caipi

    #include <iostream>
    using namespace std;
    
    int main()
    {
            cout << "Bitte Text eingeben:\n";
    
            int chars = 0;
            char character;
            while(cin.get(character) && character != '\n')
            {
                    chars++;
            }
            char *textSize = new char[chars];
            cout << "Es wurde(n) " << 1 * chars << " Byte Speicherplatz reserviert.\n";       
            delete[] textSize;
    
            return 0;
    }
    


  • Stimmt du hast recht es ergibt immer 4 Byte das wusste ich jetzt aber auch nicht gut danke dir.

    Nur jetzt hab ich folgendes Problem festgestellt. Wenn ich bei mir das Prog laufen lasse sollte folgende zeile ja die anfangsadresse des Zeigers anzeigen.

    cout << "Es wurde " <<textSize << " Byte Speicherplatz reserviert.\n";

    Aber bei mir tut es nicht. Nur wenn ich auf die C schreibweise überspringe

    printf("\n\nDie anfang der Adresse von TextSize ist:\t%p",textSize);

    klappt dies weist du warum das so ist?
    Kann man in cpp auch mit Platzhaltern arbeiten bei der ausgabe (%i,%f,%p,%u)... oder so?



  • Caipi schrieb:

    Stimmt mein Programm nun, oder muss ich noch plus ein Byte rechnen (wegen Stringende-Zeichen)?

    Caipi

    #include <iostream>
    using namespace std;
    
    int main()
    {
            cout << "Bitte Text eingeben:\n";
            
            int chars = 0;
            char character;
            while(cin.get(character) && character != '\n')
            {
                    chars++;
            }
            char *textSize = new char[chars];
            cout << "Es wurde(n) " << 1 * chars << " Byte Speicherplatz reserviert.\n";       
            delete[] textSize;
            
            return 0;
    }
    

    Dein Programm tut ja nichts. So wie du es jetzt eingetippt hast, ist es korrekt.
    Auf das Nullterminierungszeichen und das damit verbundene "mehrreservieren von
    1 Byte" musst du eigentlich nur in Situationen folgender Art beachten:

    void just_an_example(char *cstring) {
        char *cpy_of_cstring = new char[strlen(cstring)+1]; //+1 wegen \0
        //...irgendwas
    }
    

    Wenn du natuerlich weisst, dass dein Array 80 Zeichen aufnehmen soll, musst du
    fuer 81 Zeichen Speicher reservieren, damit der C-String auch ordentlich mittels
    Nullterminierungszeichen abgeschlossen werden kann.

    Anstelle von C-Strings solltest du dir jedoch angewoehnen, die string-Klasse
    einzusetzen (ich wollts nur erwaehnt haben, bevor jetzt jeder auf mich ein-
    schlaegt ;)).

    mfg
    v R



  • Vielen Dank virtuell Realisticer!

    Jetzt aber noch eine letzte Frage:
    Wie kann ich Speicher dynamisch reservieren, wenn ich einen Text von der Laenge n eingebe und gleichzeitig der eingegebene Text an den dynamisch reservierten Speicher übergeben wird. Geht das?

    Ich habe es schon versucht, bisher erfolglos 😞

    Caipi



  • Caipi schrieb:

    Ich habe es schon versucht, bisher erfolglos 😞

    kein wunder. es ist nicht einfach.
    üblich ist folgendes:
    du schätzrt erstmal, daß 10 zeichen reichen (incl. der 0) werden, legst also new char[10] an. die machte dann auch zeichen für zeichen voll. wenn beim vollmachen irgendwann festgestellt wird, daß die 10 plätze nicht reichen, machste schnell mit new char[20] nen größeren bereich frei und kopierst die bisher eingegebenen zeichen in den größeren bereich und gibst den alten kleinen bereich mit delete[] frei. dann tuste weiter zeichen einlesen. bis endlich das '\n' kommt. naja, vielleicht wird der neue bereich auch voll bevor '\n' kommt. ist ja nicht schlimm, dann legste einfach mit new char[40] nen nochmal größeren bereich an, kopierst um, löscht und weiter geht's.
    läßt sich in ne hübsche schleife packen das, wenn man nen tag oder zwei zeit hat. 😉
    viel spaß.



  • Das ist so natuerlich erstmal nicht moeglich. Wenn du zur Zeit der Eingabe noch
    nicht weisst, wie gross n sein wird, kannst du natuerlich auch nicht n-Byte
    Speicher reservieren.

    In einem solchen Fall geht man hin und reserviert Speicher fuer eine bestimmte
    Anzahl Bytes. Ist der Text groesser als der reservierte Speicherbereich,
    reserviert man einen neuen Speicherbereich, der etwas groesser als der alte ist,
    kopiert den alten Speicherbereich in den neuen und fuegt die Zeichen, welche
    mehr da sind, dem neuen Speicherbereich an. Das geht dann natuerlich immer so
    weiter.

    Daher meine Anregung, dich mal mit der string-Klasse auseinanderzusetzen.
    Zusaetzlich benoetigst du dann auch noch die vector-Klasse. vector ist quasi das
    STL-pendant zu einem C-Array und kann z. B. so eingesetzt werden:

    #include <iostream>
    #include <vector>
    
    using namespace std; //namensraum oeffnen; wir ersparen uns dann std::vector
    
    int main() {
        vector<int>  myVec; //vector mit 0 elementen (leerer vector)
        vector<int>  myVec2(5); //vector mit 5 elementen
        vector<int>  myVec3(5, 0); //vector mit 5 elementen, initialisiert mit 0
        vector<int>  myVec4(myVec2); //vector initialisiert mit myVec2
    
           /*
              mit der push_back-Memberfunktion wird ein wert in den vector
              aufgenommen. Um den Speicherbereich, brauch man sich hier nicht
              zu kuemmern, das ist Aufgabe des vectors
           */
           for(size_t i = 0; i < 5; ++i) {
               myVec.push_back(i);
               myVec2.push_back(i);
               myVec3.push_back(i);
               myVec4.push_back(i);
           }
    
           cout<<myVec[2]<<endl; //Ausgabe des 3ten Elements in myVec
           myVec[2] = 5; //3tes Element in myVec hat jetzt den Wert 5
         return 0; //den Speicherbereich, den die vectoren belegen, werden beim
                   //Zerstoeren der vector-Objekte wieder freigegeben
    }
    

    Und diese vector-Klasse kannst du auch dafuer nutzen, um, theoretisch, Text
    einer beliebigen groesse zu Speichern:

    #include <iostream>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    int main() {
        string currentLine; //aktuelle zeile, die gelesen wird
        vector<string> content; //alle zeilen, die gelesen wurden
    
           while(getline(cin, currentLine)) //so lange von stdin gelesen werden kann
               content.push_back(content);  //zeilen in content speichern
    
           //ausgabe des inhaltes
           for(size_t i = 0; i < content.size(); ++i)
                cout<<content[i]<<"\n";
    
        return 0;
    }
    

    Wie du siehst, ist es hier nicht noetig sich per Hand um die Speicher-
    reservierung zu kuemmern. Das tut unsere vector-Klasse und somit kann es auch
    nicht vorkommen, dass wir vergessen Speicher freizugeben und somit ist schonmal
    diese Fehlerquelle beseitigt.

    Hoffe das hat dir was weitergeholfen.

    mfg
    v R



  • Vilen Dank euch allen!

    Caipi


Anmelden zum Antworten