[Novize] Dynamic Memory Alloc ohne das User festlegt wie oft?



  • Hey Leute,

    Zerbreche mir hier gerade den Kopf an einer Aufgabe. Was ich hier machen möchte ist eine beliebige Anzahl von floating-point Werten vom User eingeben zu lassen. Der User kann soviele eingeben wie er möchte muss dafür auch vorher nicht angeben wieviel er eingeben wird.

    Daher muss das Ganze mit "malloc" funktionieren.

    Mein Problem hier jedoch ist das ich nicht genau herausbekomme wie ich ständig eine neue Speicheraddresse anfordere und am Ende das Ganze wie bei einem array loop abrufen kann.

    Habe mir nen Pointer ausgesucht welche die malloc zugewiesen bekommt und dieser Pointer soll dann immer einen Addressenschritt in Größe "double" (bei mir 8 Byte) vorrücken um bei einer erneuten Eingabe wiederrum "malloc" abzurufen und Speicher einzuräumen.

    Vorher legte ich einen pTemp fest welcher die erste Addresse des Pointers speichert (alá Pointer[0]) damit ich am Ende über nen Loop und increment "i" die Ganzen Werte abrufen kann - wie bei nem Array halt.

    Problem hier:

    pNumber++ setzt meine Pointer Addresse zwar um 8 byte weiter - jedoch wurde diese Addresse nicht allocalisiert. Das Ganze mache ich dann trotzdem mit malloc um sicherzugehen - wobei dann jedoch ne Ganz neue Addresse zugewiesen wird - demnach wird pTemp nutzlos.

    int main(void)
    {
    	double *pNumber = NULL;
    	double *pTemp = NULL;	
    	int i;
    	int scanf_check = 0;	
    
    	printf("\nPlease enter floating-point values.\nIf you are finished,"
    							" just type \"exit\" to end prompt.\n");
    
    	do
    	{
    		pNumber = (double*)malloc(sizeof(double));
    
    		if(pTemp == 0)
    			pTemp = pNumber;
    
    		scanf_check = scanf("%lf", pNumber);		
    		pNumber++;		
    
    	}while(scanf_check);
    
    	for(i = 0; i < 10; i++)
    	{
    		printf("Address for pNumber+%d = %d\tValue here = %lf\n",
    									i,   pTemp+i,      		*(pTemp+i));
    	}
    
    	return 0;
    }
    

    Schaut euch einfach mal an was ich hier versuche - bitte versucht meinen Wissensstand zu erkennen damit ich nicht mit lauter neuen Infos zugeschmissen werde 😉

    Eine Lösung auf meinem Niveau wäre sehr wünschenswert!

    Bedanke mich schonmal für eure Hilfe!

    gruß Charlie


  • Mod

    Völlig falscher Ansatz. Gravierendes Fehlverständnis. Ich weiß nicht, wo ich anfangen soll, zu korrigieren. Vielleicht lieber gar nicht korrigieren und stattdessen einen ganz anderen Vorschlag in einem Wort machen: realloc.

    Und guck dir ganz, ganz dringend noch einmal die Grundlagen zu Zeigern, malloc & Co. in einem guten Lehrbuch an! Dir fehlt da sehr viel essentielles Wissen.



  • Oh man das hör ich garnicht gerne.

    Habe das Thema Pointer im Buch "Beginning C from Novice to Professionell" von Ivor Horton wirklich zweimal wiederholt - weil ich beim ersten Durchgang den Faden verloren habe.

    Ich verstehe Pointer soweit was das Prinzip mit Adresse angeht inwiefern ein incerement des Pointers sich auswirkt und wie ein type das Ganze beeinflusst.

    Auch malloc habe ich soweit verstanden - und realloc kenne ich auch fand aber keinen Ansatz das hier irgendwie zu nutzen. Ich soll laut Buch auch nicht malloc im Kleinen Stile nutzen sondern lieber große chunks anwenden als lauter viele kleiner - also nicht wie in meinem Beispiel.

    Jedoch kann ich ja keine große Menge von malloc aufrufen wenn der User doch eh unendlich viele Werte holen kann.

    Kann mir denn keiner ne Lösung für das Problem mal aufzeigen damit ich vielleicht 'nen AHA Effekt erziele 😞



  • http://ideone.com/pQBfeo

    free() am Ende fehlt hierbei noch.



  • Wutz schrieb:

    http://ideone.com/pQBfeo

    realloc(pNumber,++i*sizeof*pNumber);
    

    Na das nenn ich mal gut lesbar.


  • Mod

    Falke88[tmp] schrieb:

    Auch malloc habe ich soweit verstanden - und realloc kenne ich auch fand aber keinen Ansatz das hier irgendwie zu nutzen.

    Ich vermute, dann hast du es nicht verstanden. Du brauchst immer größer werdende Speicherbereiche. Wie kannst du da keine Anwendung von realloc sehen?

    Eine alternative Vorgehensweise ohne realloc wäre eine list oder deque Datenstruktur (oder auch andere Strukturen, es gibt sehr viele). Das kann ich mir aber auf diesem Niveau nicht als gesuchte Lösung vorstellen.

    Ich soll laut Buch auch nicht malloc im Kleinen Stile nutzen sondern lieber große chunks anwenden als lauter viele kleiner - also nicht wie in meinem Beispiel.

    Das ist dann Stufe 2. Dafür sollte aber erst einmal das Grundgerüst stehen. Eine gute Strategie ist, bei Bedarf doppelt so viel Speicher zu holen wie man bisher hatte.



  • Wutz schrieb:

    http://ideone.com/pQBfeo

    Oh man danke...wenn ich das dort so sehe sieht es alles so logisch aus...
    Hier der Vorteil von realloc das er anstatt wie malloc ne Ganz andere Speicheradresse wählt - nimmt realloc ja die Erstaddresse von pNumber wieder auf um von dort aus den benötigten Speicher neu ranzuholen. Das war das Ding was mir die Ganze Zeit gefehlt hat.

    Ich dachte immer realloc könnte den neu alocalisierten Speicher nie über die Größe die Argument 1 hier pNumber schon hatte... d.h. er würde nicht über die 8 Byte eines doubles gehen.

    Lag ich wohl falsch...

    Danke für den Hinweis !



  • Falke88{tmp] schrieb:

    - nimmt realloc ja die Erstaddresse von pNumber wieder auf um von dort aus den benötigten Speicher neu ranzuholen.

    Nein, das ist bei realloc nicht garantiert.
    realloc liefert (je nach Implementierung häufig) eben nicht immer den gleichen Zeiger zurück, sondern kann auch einen anderen Speicherbereich adressieren, wobei dann aber die im Originalspeicher liegenden Daten kopiert werden (in realloc).
    Sicher kann man realloc-Aufrufe optimieren, auf gängigen Systemen sollte aber eher die Tastatur kaputtgehen, als dass der Speicher für neue sizeof(double)-Speicherbereiche ausgeht.



  • Ach falls die alte Addresse von pNumber nicht mehr verfügbar wäre (warum auch immer) würde realloc die Ganzen Daten mitnehmen auf ne neue Addresse??

    Wollte nämlich gerade sagen falls realloc woanders anfängt würde pNumber[i] ja nichts mehr bringen da die Werte ja noch auf der alten Addresse liegen.

    Interessant :o



  • Falke[tmp] schrieb:

    Ach falls die alte Addresse von pNumber nicht mehr verfügbar wäre (warum auch immer) würde realloc die Ganzen Daten mitnehmen auf ne neue Addresse?

    Wutz schrieb:

    realloc liefert eben nicht immer den gleichen Zeiger zurück, sondern kann auch einen anderen Speicherbereich adressieren, wobei dann aber die im Originalspeicher liegenden Daten kopiert werden (in realloc).



  • ich habe es mal in einer Anwendung so gemacht, - erst mal 10K reserviert und
    bei der Eingabe mitgezählt - wenn dann noch 1K übrig war (Länge der Eingabe stand fest), einfach wieder per realloc 10k angefordert usw.
    Dann spart man sich das einzel-realloc und das ganze wird dann wohl auch performanter. (In diesem Fall ging es um die Anzeige von Buchungsdatenzeilen in einem Fenster aus ner Postgresql-DB, wobei die Anzahl der Buchungen vorher nicht feststand)



  • pferdefreund schrieb:

    ich habe es mal in einer Anwendung so gemacht, - erst mal 10K reserviert und
    bei der Eingabe mitgezählt - wenn dann noch 1K übrig war (Länge der Eingabe stand fest), einfach wieder per realloc 10k angefordert usw.
    Dann spart man sich das einzel-realloc und das ganze wird dann wohl auch performanter. (In diesem Fall ging es um die Anzeige von Buchungsdatenzeilen in einem Fenster aus ner Postgresql-DB, wobei die Anzahl der Buchungen vorher nicht feststand)

    An sich guter Plan.
    Aber man sollte sich anfgewöhnen, statt +=10000 gleich *=2 zu machen. Dadurch wird es nicht langsamer, wenn die Anzahl sehr sehr groß wird.



  • volkard schrieb:

    Aber man sollte sich anfgewöhnen, statt +=10000 gleich *=2 zu machen. Dadurch wird es nicht langsamer, wenn die Anzahl sehr sehr groß wird.

    wobei man das auch begrenzen muss. spaetestens wenn die groesse bei 1 GB ist sollte das naechste malloc nicht gleich 2 GB anfordern. Ich weis nur nicht wo man am besten die grenze zieht... Bei 10 MB? 100?



  • Real Locater schrieb:

    volkard schrieb:

    Aber man sollte sich anfgewöhnen, statt +=10000 gleich *=2 zu machen. Dadurch wird es nicht langsamer, wenn die Anzahl sehr sehr groß wird.

    wobei man das auch begrenzen muss. spaetestens wenn die groesse bei 1 GB ist sollte das naechste malloc nicht gleich 2 GB anfordern. Ich weis nur nicht wo man am besten die grenze zieht... Bei 10 MB? 100?

    Doch, einfach Durchziehen.

    Lass uns mal Testhalber die Grenze bei 100M ziehen. Dann haste Vergrößerungen evtl mit Kopieren alle Elelente von 100M auf 200M, von 200M auf 300M...
    100+200+300+400+500+600+700+800+900=4500 Kopierungen, also 4.5 pro Nutzbyte.
    Und es wird um so schlimmer, je mehr Speicher belegt wird. Das wird ein Programm, das prinzipiell nur mit kleinen Datenmengen zurechtkommt, selbst wenn sich der User 16G Ram und 120G Swapspace gönnt.

    bei 10+20+30+...+990=49500(geschätzt), also 49.5 pro Nutzbyte.
    Und es wird um so schlimmer, je mehr Speicher belegt wird.

    Bei 10+20+40+80+...+655360=1310710, also 1.3 pro Nutzbyte.
    Und es wird nicht schlimmer, sondern bleibt zwischen 1 und 2.

    Kannst aber auch einen schwächeren Faktor nehmen, wie 1.5, solltest aber exponentiell bleiben.



  • hm, ok, hast mich überzeugt mit deinen Zahlen!

    Ich kam auf den Trichter, weil ich mal bei so einer Funktion dann zum Testen eine 600 MB Datei reingeschoben habe und mir nicht gefiel, als dann malloc schiefging, weil es gleich 1 GB anfordern wollte.

    Aber wenn man mit Speicherbereichen hantiert, die gut die Hälfte des Gesamtspeichers verbrauchen, sollte man da wohl eh anders rangehen.



  • Aber wenn man mit Speicherbereichen hantiert, die gut die Hälfte des Gesamtspeichers verbrauchen, sollte man da wohl eh anders rangehen.

    Dumme Frage: Macht es perfomance-technisch etwas aus, wenn ich 200 MByte Chunks allokiere, als wenn ich diese mittels einer Liste allokieren würde?


  • Mod

    In wie kleinen Teilen liegt denn deine Liste vor? Allgemein sind Listen im Vergleich zu anderen Datenstrukturen unglaublich lahm, außer bei ihrer einen Spezialität, dem Umhängen von Elementen. Je kleiner die Listenelemente, desto schlimmer.



  • Bitte ein Bit schrieb:

    Aber wenn man mit Speicherbereichen hantiert, die gut die Hälfte des Gesamtspeichers verbrauchen, sollte man da wohl eh anders rangehen.

    Dumme Frage: Macht es perfomance-technisch etwas aus, wenn ich 200 MByte Chunks allokiere, als wenn ich diese mittels einer Liste allokieren würde?

    Chunks sind natürlich auch enorm gut. Die können auch nur 8k groß sein. Da wird der Index-Zugriff ganz ein Bißchen langsamer nur. Oder bei nur linearem Zugriff eine verkettet Liste von Chunks. Und dafür hat man gleich mal 0 Umkopierungen. Ist halt ein Bißchen mehr Programmieraufwand.

    Aber ich würde mal nicht vernachlässigen, daß man immer mehr von 64-Bittern mit gigantischem Adressraum ausgehen kann. Ich habe neulich mit Feldern von 60G gearbeitet. Das ging noch recht schmerzfrei. Auslagerungsdatei groß genug machen und los geht's. 🙂

    Eine normale verkettete Liste ohne Chunks ist bei kleinen Datenobjekten eher tödlich. Wenn ich bei 8Bytes Nutzdasten 24Bytes Verkettunsgkram- oder Speichermanagement-Kram habe, bräuchte ich dann 240G und so groß ich die SSD nicht und die Platte ist mal richtig lahm.



  • In wie kleinen Teilen liegt denn deine Liste vor?

    Elementgröße liegt zwischen 20 und 100 Bytes, bei einer maximalen Größe des Array's von 100000 Elemente. Ok, hier macht eine Liste tatsächlich weniger Sinn.

    Chunks sind natürlich auch enorm gut. Die können auch nur 8k groß sein.

    Das verstehe ich nicht ganz. Unter Chunks meinte ich nur die Reservierung eines Speicherbereichs, in dem Elemente gespeichert werden (Array)

    Was versteht du unter eine Chunk? Und warum können dies nur 8k groß werden?


  • Mod

    Bitte ein Bit schrieb:

    Was versteht du unter eine Chunk? Und warum können dies nur 8k groß werden?

    In C++-Sprech meint volkard so etwas wie die deque. Also eine dynamische Datenstruktur, die intern eine Art Mischung aus Liste und Vektor ist, wobei die Daten in Blöcken vektorartig gespeichert werden, die wiederum listenartig verbunden sind. Mit "nur" meint er, dass sich das schon ab ein paar Kilobyte Blockgröße lohnt.

    edit: "lohnt" mit Vorbehalt. Ein reiner Vektor wäre natürlich besser, aber wenn das nicht geht ist eine Liste nicht soooo schlimm, wenn sie bloß einigermaßen große Blöcke hat. Also nicht 20 Byte wie bei dir.


Anmelden zum Antworten