Festplatte / Arbeitsspeicher



  • Hallo liebes Forum,

    ich beschäftige mich jetzt nun seit Längerem mit C++ und mache auch schon so meine Fortschritte.
    Jedoch scheitert es immer wieder an Begriffen wie Stack, Heap, Buffer, Bufferoverflow, Gültigkeitsbereich, Gültigkeitsbereichsüberschreitung, benötigter Speicher.... und und und 😮

    So ganz grob verstehe ich ja, was mit all diesen Begriffen gemeint ist, aber ich verstehe leider den Zusammenhang nicht und es macht mich ehrlich gesagt verrückt mit der Zeit!!!

    Wenn ich ein Programm schreibe und eine Variable deklariere, hat sie dann schon einen Speicherplatz?? Und ist dieser dann auch schon belegt oder hat sie nur eine Speicheradresse oder keins von beiden?

    Und wo hat sie dann diesen Speicher?? Sofern ich kein New oder delete angebe wohl im Stack, oder? Aber wo befindet sich der Stack und ist er begrenzt?? Hat das komplette Programm nur einen Stack und einen Heap zur Verfügung?? Wie ist der Arbeitsspeicher denn genau aufgebaut? Aus lauter Stacks und Heaps?? Oder gibts da noch spezielle Bereiche für spezielle Variablen oder spezielle Programme??
    Und was hat es mit dem Puffer auf sich? Was ist der Puffer und wie kann der überlaufen?? Ist der Stack der Puffer?? Wie groß ist denn der Stack und wie groß ist der Puffer und wie groß ist der Heap? Schließlich heißt es ja, wenn man mehr Speicher reservieren möchte, dann sollte man den Heap nehmen (auch wegen der Sicherheit wegen Gültigkeitsbereich etc)...aber was heißt das? Wie kann es vorkommen dass eine Variable den Gültigkeitsbereich überschreitet? Was genau passiert denn dann und wo schreibt die Variable dann hin - Heap oder Stack oder beides oder keins von beidem????? 😕 😕 😕

    Und gibt es eine Möglichkeit, wie ich diese Variablen in den Festplattenspeicher bekomme??

    Könnte mir jemand den Aufbau des Arbeitsspeichers grob erklären, denn ich hab kein Plan wo sich da Heap bzw Stack bzw mehrere Heaps bzw. mehrere Stacks befinden...

    Hoffe auf eine baldige Antwort
    Gapa



  • Hi.

    Phu.. Da hast du aber eine ganze Menge an Fragen. 🙂

    Also in C++ sollte man nicht mehr vom "Stack" und "Heap" reden, auch wenn man sich das etwa so vorstellen kann. Rein theoretisch ist ein Stack ja nichts schweres und sagt eigentlich mit dem Namen schon alles ein Stapel. Und Heap ebenso. ein Haufen (Also der ganze Rest.). Darauf werde ich jetzt nicht eingenen, weil du auf die verknüpfung anspielst.

    In C++ interessiert dich das eigentlich nicht, sondern nur, WER sich um die Daten/Freigabe kümmert. Wenn du eine Variable deklarierst, geschieht das implizit mit dem Keyword "auto", was soviel heisst, dass DU dich nicht darum kümmern musst, wann das Objekt freigegeben wird. Das macht die Sprache für dich. Das heisst, dass diese Variable solange gültig ist, wie sie sich im deklarierten Gültigkeitsbereich befindet. Beispiel:

    {
       int a;
    // hier ist a gülti und man kann damit machen, was man will.
    }//a wird hier zerstört
    
    //Hier gibt es a nicht mehr und ein Zugriff darauf ist auch nicht möglich.
    

    a befindet sich in einem Gültigkeitsbereich, der mit dem Klammer {} angegeben wird.

    Wenn du jetzt aber Speicher per new anforderst, bist DU für das aufräumen verantwortlich und musst dich darüm kümmern. Der Vorteil ist, dass der Speicher solange gültig ist, wie du ihn nicht freigibst. Beispiel:

    int* i;
    {
       i = new int; //Speicher anfordern
    }
    //Hier kann i immernoch gebraucht werden.
    

    Jetzt denkst du vielleicht, klar, i ist ja ausserhalb deklariert worden. Aber es geht hier nicht um den NAMEN, sondern um Speicherbereich, den du angefodert hast.
    Und ja der "Stack" ist begrenzt. Liegt afaik irgendwo bei ein paar MB. Ist aber abhängig von der Implementierung. (Kannst ja mal ein grosses Array erstellen und schauen, wielange du keinen Fehler bekommst.)
    Der Heap ist da wesentlich grösser (irgendwo bei ein paar GB, je nachdem).
    Ein Buffer ist eigentlich nichts anderes, als eine Variable (oder ein Array).
    Wenn du jetzt ein Array hast, das 4 Byte gross ist und da versuchst einen Speicherbereich von 8 Byte reinzukopieren, überfüllt es dir den Speicher und du kriegst unter umständen einen Absturz des Programmes. (nicht zwingend).

    Wenn du etwas auf die HD speichern willst, macht man das über Files. (in C++ z.B std::ofstream).

    Ich hoffe mal das reicht fürs erste und es ist ein wenig klarer geworden. 😉



  • @drakon:
    Hey WOW super vielen Dank für die ausführliche Antwort! 👍
    Ok also wenn ich das richtig verstehe, gibt es für jedes laufende Programm also einen Stack, und für alle Programme zusammen einen Heap?
    Und wenn ich jetzt beispielsweise ein Programm Gapa1.exe starte, und 5 Minuten später ein Programm Gapa2.exe parallel dazu starte, wer hat dann wo seinen Stack, und wie sehen die Speicheradressen da drinn aus?
    Wie muss ich mir denn einen solchen Stack bildhaft vorstellen? Etwa so:
    -------------------------
    - 0x23ff70 -
    - 0x23ff74 -
    - 0x23ff78 -
    - 0x23ff7C -
    - 0x23ff80 -
    - 0x23ff84 -
    - 0x23ff88 -
    - 0x23ff8C -
    - 0x23ff90 -
    -------------------------
    Wäre das jetzt ein Stack aus lauter Int - speicheradressen (4Bytes) ??
    Wenn ja, wie sähe er dann aus, wenn da noch zusätzlich double-speicheradressen drinn wären??
    Dann wäre da ja nichts mehr einheitlich??
    Und kann ich nicht auch selbst irgendwie die Speicheradresse einer Variable bestimmen, oder bleibt mir da nur die Auswahl der Adressen des Stacks (hier 0x23ff70 - 0x23ff90) ??
    Und wie kommt eine solche Adresse (0x23ff70) zusammen? Was bedeuten diese einzelnen Zeichen??
    Und warum sieht der Stack nicht so aus:

    -------------------------
    - 0x23ff70 -
    - 0x23ff71 -
    - 0x23ff72 -
    - 0x23ff73 -
    - 0x23ff84 -
    - 0x23ff85 -
    - 0x23ff86 -
    - 0x23ff87 -
    - 0x23ff98 -
    -------------------------

    ??
    Diese Vierer-Schritte haben ja schon etwas mit den 4 Bytes Int-Speicher zu tun, oder? Aber dann müsste ein Int-Wert mit 3Bytes Speicher ja irgendwo zwischen der Speicheradresse 0x23ff70 und 0x23ff74 liegen, oder?? Ich blick das nicht so ganz... 😕

    Wäre sehr dankbar für Antworten (falls jetzt nicht jeder konfused ist^^)
    Grüße
    Gapa



  • Jedes Programm hat seinen eigenen Adressraum. Sonst könnte es ja Probleme mit Zeiger geben. Die wüssten ja nicht, von welchem Programm was benutzt werden müsste.

    Der Speicherbereich ist in 4 Byte Schritten aufgeteilt. Es ist nur ein Zufall, dass ein Int auch genau 4 Byte hat. Wenn jetzt ein anderer Datentyp gebraucht wird, wird einfahc mehr als 4 Byte eingenommen. z.B 8 Byte.

    Der Adressraum wird in Hex angezeigt. http://de.wikipedia.org/wiki/Hexadezimalsystem
    Kannst ja mal nachlesen, was das ist.



  • Supi vielen Dank...jetzt ist mir das Meiste klar geworden!

    Nun hätte ich nur noch 2 Fragen:

    1. Nach dem was jetzt gesagt wurde heißt ein Bufferoverflow nichts weiter als das Überladen eines Arrays oder einer Variable...aber was passiert dann mit dem Teil der überläuft? Denn ich habe jetzt schon öfter davon gehört, dass sich mit so einem Überlauf auch Viren einschleusen können bzw. Viren diesen Fehler irgendwie nutzen...aber ich kann mir gar nicht vorstellen was genau damit gemeint ist? Wie soll denn ein Virus diesen Bufferoverflow zu seinem Gunsten nutzen können, denn schließlich hat ja auch jedes Programm seinen eigenen Stack... 😕

    2. Diese Frage trifft nicht genau das Thema, aber wenn wir schon dabei sind:
    Wo liegt der Unterschied zwischen folgenden Begriffen:

    - Bezeichner
    - Methode
    - Eigenschaft
    - Funktion
    - Daten
    - Klasse
    - Objekt
    - Gültigkeitsbereich
    - Sichtbarkeitsbereich
    - Namensraum
    - Variable
    - Speicherort
    - Speicheradresse

    🙄 🙄



  • drakon schrieb:

    Der Speicherbereich ist in 4 Byte Schritten aufgeteilt.

    Bist Du da sicher? Also ich kann bei mir jedes Byte adressieren.



  • Tachyon schrieb:

    drakon schrieb:

    Der Speicherbereich ist in 4 Byte Schritten aufgeteilt.

    Bist Du da sicher? Also ich kann bei mir jedes Byte adressieren.

    Stimmt natürlich. 😉 - Im übrigen kann man ja auch noch auf die Bit's zugreifen. 🙂



  • @Tachyon:
    AHA! Das ist interessant!

    1. Was meinst du mit "ich kann bei mir jedes Byte adressieren"??
    Kann man eine Speicheradresse selbst festlegen oder kann man sie nur anzeigen lassen?

    2. Ja ich bin mir sicher:

    int a, b c;
    a = 1;
    b = 2;
    c = 3;
    
    cout << &a << '\n' << &b << '\n' << &c << '\n';
    

    Ausgabe:
    0x23ff70
    0x23ff6c
    0x23ff68

    Also woran liegt das??? 😕



  • Das liegt dadran das du int Variablen anlegst und die hat nunmal 4 Byte. Darum ist der Abstand auch immer 4 Byte.
    Kannst ja mal mit char Variablen Versuchen, dann ist der Abstand immer nur 1 Byte.
    Tip: Wenn du die Adresse einer char Variable ausgeben willst musst du zuerst nach int* casten.


  • Mod

    Tanren schrieb:

    Tip: Wenn du die Adresse einer char Variable ausgeben willst musst du zuerst nach int* casten.

    undefiniert. Der benötigte Overload benutzt const void* - dies sollte folglich der Zieltyp des Casts sein.



  • Ist es denn möglich, den Wert einer Speicheradresse zu bekommen...
    Also was ich damit meine ist, ob es möglich ist, die Adresse 0x23ff70 anzusprechen?
    Und warum kann ich Zeigern die Adresse nicht einfach so direkt zuweisen:

    int *adr;
    
    adr = 0x23ff70      //-->geht nicht...aber warum?
    adr = &var          //nur das geht...warum??
    

    Und ich hoffe auch auf Antwort auf die Frage nach den Begriffen ein paar Posts zuvor bzw auf die Frage mit dem Bufferoverflow!

    Grüße
    Gapa



  • Also ein Bufferoverflow funktioniert in etwa so:

    Zuerst mal ein Loch finde, wo es überhaupt möglich ist. Also eine Stelle, wo du was eingeben kannst und das nachher zur Überfüllung führt. (z.B eine unsichre memcpy funktion)
    Dann musst du das ganze zum Überlaufen bringen und die Rücksprungadresse verändern nämlich dorthin, wo dein Shellcode steht, der dann ausgeführt wird.
    Um so was zu machen, muss man aber fitt sein in Assembler und auch sonst ein wenig von Rechnerarchitektur verstehen. 🙂



  • drakon schrieb:

    Also in C++ sollte man nicht mehr vom "Stack" und "Heap" reden, auch wenn man sich das etwa so vorstellen kann.

    Warum? Ist ein Stack-Overflow jetzt kein Stack-Overflow mehr?



  • - Bezeichner ---> das sind die variablen namen im programm

    int i;   // i ist der bezeichner, achtung auch funktionsnamen sind bezeichner
    

    - Methode ---> das ist eine Funktion innerhalb einer Klasse, in Java wirst du nur methoden fidnen und keine Funktionen da java ja eine klassen sprache ist(oder wie das heist)

    class test 
    { 
    public: 
        void test();   // das ist eine methode, oder auch memberfunktion
    }[/cpp
    
    - Eigenschaft               ---> eigenschaften können vieles sein, ich weis jez so nicht wod as in der C++ programmierung vorkommt...
    
    - Funktion                  ---> Funktion ist ein programmteil der nicht direkt an die entsprechende programmstelle geschrieben werden muss und somit auch mehrmals aufgerufen werden kann
    [cpp]
    void test()               // funktionsdefinition und gleichzeitige deklaration
    {
        cout<<"test"<<endl;
    }
    
    int main()
    {
        test();              // funktionsaufruf nr1
        // bla bla mehr programm
        test();              // funktionsaufruf nr2
    }
    // funktionen sind dazu da das proramm übersichtlicher zu halten 
    // und nicht mehrmals denselben quellcode neus chreiben zu müssen
    // daraus resultiert eine geringere fehleranfälligkeit
    

    - Daten
    - Klasse ---> ist ein abstrakter datentyp (int und float... sind datentypen), klassen können viele verschiedene variablen in sich haben und haben interne funktionen um mit ihren variablen umzugehen
    - Objekt --> Objekte sind instantierte klassen, also was int i für den normalen datentyp ist, ist hier Klasse objekt, quasi ist int eine klasse und i das objekt

    class Test        // klassendeklaration
    {
    private:          // private interne variablen
        int i;
        float x;
    public:
        void setIX(int a, float b)  // methode/memberfunktion
        {
            i = a;
            x = b;
        }
    };
    
    int main()
    {
        int m = 4;
        float n = 6.435f;
        Test lol;                  // instantierung der klasse Test -> lol = objekt von der klasse Test
        lol.setIX(m, n);           // methodenaufruf für das objekt lol
    }
    

    - Gültigkeitsbereich ---> variablen sind nur begrenz gültig, d.h. sie existieren, in diesem bereich gibt es sie einfach nur

    - Sichtbarkeitsbereich ---> bei auto variablen gleich mit dem gültigkeitsbereich, bei mit new angelegten variablen oft viel kleiner als der gültigkeitsbereich, im sichtbarkeitsbereich lässt sich eine variable ansprechen und benutzen

    void test()
    {
        int i;     // die variable i wird erzeugt, sie existiert hier, und gleichzeitg ist sie hier sichtbar
        // blabla code
        int *a = new int;     // die zweite variable a wird mit new erzeugt und ist somit gültig biszu ihrem delete, gesehen werden kann sie aber auch nur bis zum ende dieser funktion(und das delete muss bis dahin gekommen sein, sosnt ist der speicher weg
    }              // die variable i wird zerstört, d.h. es gibt sie nicht mehr und sie ist nicht mehr zu sehen
    
    int main()
    {
                // i aus der fukntion test ist nicht mehr zu sehen und existiert derzeitig auch nicht mal
        //blabla
        test();
        // i ist auch hier nicht sichtbar und existiert auch schon nicht mehr
        // delete a; geht nicht weil der sichtbarkeitsbereich verlassen wurde, existieren tut a aber schon noch
    }
    

    - Namensraum ---> mit namespaces kann man zumbeispiel seinen eigenen quellcode versehen um namensüberschneidungen zu verhindern
    [cpp]
    //firma a hat diese funktion programmiert
    int multiplizieren(int a, int b)
    {
    return a*b;
    }

    // firma b hat dies produziert
    int multiplizieren(int a, int b)
    {
    return 2*a*2*b;
    }

    int main()
    {
    int erg = multiplizieren(3, 5); // welche funktion ist gemeint???
    }

    //beide firmen können nun hingehen und ihre funktionen in einen namespace packen
    namespace a
    {
    int multiplizieren(int a, int b)
    { ... }
    }

    namespace b
    {
    int multiplizieren(int a, int b)
    { ... }
    }

    int main()
    {
    int erg = a::multiplizieren(3, 5); // dank dem a:: (oder auch b::) wird nun auf den entsprechenden namepsace zugegriffen und
    }
    - Variable ---> eine variable ist ein speicherplatz im computer auf dem du irgendwas speichern kannst
    - Speicherort ---> dort wird die variable gespeichert

    - Speicheradresse ---> jeder speicherort hat eine adresse mit de rer angesprochen wird, quasi eine hausnummer

    ich hoffe das reicht erstmal, aber das meiste davon lernt man bei duing
    und wenn du fragst was eine klasse ist, aber nichtmals weist was eine variable ist dann solltest du dich wirklich mal fragen was du eigendlich mit C++ willst...



  • Na also supi vielen vielen DANK!!

    und wenn du fragst was eine klasse ist, aber nichtmals weist was eine variable ist dann solltest du dich wirklich mal fragen was du eigendlich mit C++ willst...

    Keine Sorge, ich wusste schon was eine Variable ist, wollte es nur der Übersicht halber nicht weglassen.

    Um jedoch nochmal die Objekte anzusprechen:
    In meinem Buch komme ich jetzt gerade in das Kapitel "Objektorientierte Programmierung (OOP)"
    Und da steht folgendes (was mich verwirrt):

    Das OOP-Konzept ist ein neues Konzept mit vielen Vorteilen gegenüber dem alten "Prozedualen Konzept". Bei der klassischen prozedualen Programmierung war es immer so, dass Daten und Funktionen keine Eineit bildeten:

    Funktion Funktion
    - - -
    - - -
    - - -
    - - -
    Daten Daten

    Bei der objektorientierten Programmierung hingegen bilden die Objekte eine echte Einheit aus Daten und Funktionen, wobei in der OOP die Daten als Eigenschaften und die Funktionen als Methode bezeichnet werden:

    --------------- ---------------
    - Eigenschaft - - Eigenschaft -
    - Methode - - Methode -
    --------------- ---------------
    Objekt A Objekt B

    <<

    Mir ist nun noch nicht so ganz klar, was hier als Objekt bezeichnet wird und was genau "Objektorientierte Programmiersprache" bedeutet (nach was orientiert sich diese Sprache???)?? 😕 😕

    Und warum spricht man dort bei Daten von Eigenschaft und bei Funktionen von Methode?? Was genau sind denn "Daten" darauf hin bezogen?

    Könnte mir das vielleicht noch jemand erklären so dass ich den Zusammenhang besser verstehe und vielleicht ein kleiner Vergleich zwischen "prozedualem und objektorientiertem" Programmieren besser erläutern??

    Vielen Dank schon im Voraus!
    Gapa



  • class mensch{
    int alter;        //Daten,kann auch als "Eigenschaft" von einem Menschen angesehen werden
    int anzahlKinder; 
    ...
    public:
    
    void macheKind (int anzahl = 1){ //Methode = Funktion in einem Objekt
    anzahlKinder += anzahl;
    }
    
    };
    
    struct datenMensch{
    int alter;
    int anzahlKinder;
    };
    
    void macheKind (datenMensch* obj; anzahl = 1)
    {
    obj->anzahlKinder += anzahl;
    }
    
    int main (){
    mensch m1;       //Objektorienert
    m1.macheKind ();
    
    datenMensch m2;  //Daten von Funktionen getrennt
    macheKind (m2);
    }
    

Anmelden zum Antworten