Zu wenig Speicher für Zeiger Allokieren ?!



  • moin, ich bin im moment total verwirrt was die Speicherallokierung angeht. Zunächst einmal hab ich diesen Quellcode:

    #include <iostream>
    #include <stdlib.h>
    
    using namespace std;
    int main()
    {
    	cout << sizeof(unsigned long)<<endl;
    	unsigned long* zeiger;
    	zeiger = (unsigned long*) malloc(2);
    	*zeiger=4294967290;
    	cout << *zeiger<<endl;
    }
    

    Ich verstehe einfach nicht, warum der Code Fehlerlos ausgeführt wird. unsigned long benötigt doch 4 Byte, und ich habe doch mit malloc bloß 2 allokiert, also was passiert denn da?

    Und dann hätte ich gleich noch eine andere Frage. Wenn ich mehr Speicher allokiere als die Struktur des Zeigers benötigt, was ist dann mit dem Restlichen Speicher? Und kann ich dann auf den noch irgendwie zugreifen?
    Wäre auch sehr dankbar für Hinweise auf links ect. wo etwas zum Thema Speicherallokierung steht.
    Thx, MfG homie



  • homie849 schrieb:

    Ich verstehe einfach nicht, warum der Code Fehlerlos ausgeführt wird. unsigned long benötigt doch 4 Byte, und ich habe doch mit malloc bloß 2 allokiert, also was passiert denn da?

    Das stimmst schon. Dass das "klappt" ist zufall. Liegtwarscheinlich daran, dass das Betriebssystem den Speicher in größeren Happen (4K) zuteilt. Beim nächsten malloc würdest du wohl Probleme bekommen. Aber das ist alles Zufall.

    homie849 schrieb:

    Und dann hätte ich gleich noch eine andere Frage. Wenn ich mehr Speicher allokiere als die Struktur des Zeigers benötigt, was ist dann mit dem Restlichen Speicher? Und kann ich dann auf den noch irgendwie zugreifen?

    Ja kann man. Informiere dich einfach über Pointerarithmetik.



  • Vielen Dank, endlich beginnt der ganze Themenkomplex mit dem ich mich grad befasse, langsam wieder Sinn zu machen. Mit dem Begriff Pointerarithmetik hab ich auch endlich was, nachdem ich auch suchen kann^^.

    MfG homie



  • homie849 schrieb:

    Ich verstehe einfach nicht, warum der Code Fehlerlos ausgeführt wird. unsigned long benötigt doch 4 Byte, und ich habe doch mit malloc bloß 2 allokiert, also was passiert denn da?

    ProgChild schrieb:

    Das stimmst schon. Dass das "klappt" ist zufall. Liegtwarscheinlich daran, dass das Betriebssystem den Speicher in größeren Happen (4K) zuteilt. Beim nächsten malloc würdest du wohl Probleme bekommen. Aber das ist alles Zufall.

    Ich würde dem widersprechen. Das Betriebssystem weißt dem Programm zwei Byte Speicher (im Heap) dynamisch zu. Dadurch, das die Adresse in einem long-zeiger gespeichert wird, kannst du allerdings vier Byte reinschreiben (ohne dass der Compiler einen Fehler ausgbt). Von diesen vier Byte "gehören" zwei dem Programm und die anderen zwei "gehören" entweder niemandem (d. h. sie werden nicht verwendet) oder sie "gehören" einem anderen Programm. Man muss selber dafür sorgen, dass man nur Speicher verwendet, der einem auch "gehört".

    Als Beispiel kannst du auch mal folgendes machen (auch wenn es nicht zu empfehlen ist, so ein Program zu schreiben, weil du andere Programme dadurch beeinflussen könntest):

    #include <iostream>
    using namespace std;
    
    int main()
    {
        long* i = (long*)new short;
        cout << i;
        delete i;
        return 0;
    }
    

    ich verwende jetzt einfach mal der einfachkeit halber "new". Merk dir die Adresse, die dir das Programm ausgibt, und ändere das Programm um in:

    #include <iostream>
    using namespace std;
    
    int main()
    {
        long* i = (long*)0x3d2470;
        *i= 5;
        cout << i << endl;
        cout << *i;
        return 0;
    }
    

    wobei "0x3d2470" die Adresse ist, die das Programm davor ausgegeben hat. Wie man sieht beantragt man bei diesem Programm gar keinen Speicher, kann aber trotzdem in den Speicher ohne Fehler reinschreiben (weil die Adresse auf Speicher im Heap verweist).



  • @Anfänger: Du hast vergessen, deinen Beitrag mit "probiert das ja nicht zu Hause" zu überschreiben 😉 Sowas kann tatsächlich unter Debug-Bedingungen gut gehen - aber sobald du das Programm mit leicht geänderten Compiler-Einstellungen übersetzt, fliegt es dir um die Ohren.

    Übrigens gehören die 2 Byte, die du fälschlicherweise benutzt, vermutlich nicht einem anderen Programm, sondern dem Heap-Manager deines Programmes. Und wenn du dem seine Steuerdaten pulverisierst, fliegt dir der womöglich schon beim nächsten malloc() dein Programm um die Ohren.



  • @CStoll Ich hab' ja zumindest geschrieben, dass es nicht empfehlenswert ist es so zu machen. Dachte, das reicht. 😉

    Das Beispiel war auch eigentlich nur dafür da, zu verdeutlichen, dass Betriebssysteme nicht umbedingt eine Fehlermeldung ausgeben müssen, wenn man auf Speicher-Addressen zugreift, die Betriebssysteme auch zur "Verfügung" stellen würden, wenn man Speicher dynamisch beantragen würde.

    Um ehrlich zu sein, kenne ich mich aber jetzt auch nicht so gut mit Speicherverwaltung aus, sondern habe versucht, mir vieles selber zu erklären durch Testprogramme, wie jenes (kann auch gut sein, dass ich da vieles falsch interpretiert habe).



  • Viele Heap Implementierungen allozieren immer mindestens die grösse eines Zeigers, also 4 Byte auf normalen 32 Bit Systemen, oft auch die Grösse von 2 Zeigern oder nochmehr, also 8 oder gar 16 Byte.

    Dadurch wird auch oft nix passieren wenn man 2 Byte anfordert aber 4 verwendet, auch nicht wenn man den Speicher wieder freigibt oder danach wieder Speicher anfordert.

    Die 4K gibts an anderen Stellen, nämlich wenn man übers OS Speicher seitenweise anfordert - ein Heap wird aber immer feiner auflösen als 4K.



  • Absoluter Anfänger schrieb:

    @CStoll Ich hab' ja zumindest geschrieben, dass es nicht empfehlenswert ist es so zu machen. Dachte, das reicht. 😉

    War zu unauffällig, deswegen hatte ich das übersehen.

    Das Beispiel war auch eigentlich nur dafür da, zu verdeutlichen, dass Betriebssysteme nicht umbedingt eine Fehlermeldung ausgeben müssen, wenn man auf Speicher-Addressen zugreift, die Betriebssysteme auch zur "Verfügung" stellen würden, wenn man Speicher dynamisch beantragen würde.

    Das Beispiel zeigt vor allem, wie weit "undefiniertes Verhalten" gehen kann. Mit etwas "Glück" schaffst du es tatsächlich, dein Programm zum Laufen zu bringe, ohne daß Windows oder andere Prozesse dagegen protestieren. Aber Fakt ist, du kannst nicht voraussagen, was passiert, wenn du es startest (die Möglichkeiten reichen von "funktioniert anscheinend reibungslos" über "formatiert deine Festplatte" bis zu "löst den vierten Weltkrieg aus" (OK, letzteres ist etwas unwahrscheinlicher :D)).


Anmelden zum Antworten