Entwickler-Ecke

Alle Sprachen - Alle Plattformen - malloc Funktion


tomycat - Di 22.08.17 10:30
Titel: malloc Funktion
hallo,
die malloc Funktion ist eine tolle Funktion :-)
Zu meinem problem, ich habe mehrere Beispiel gefunden, aber so richtig klar ist es mir nicht.

Mit malloc resaviert man Speicher und free gibt man ihn wieder frei. Aber ich habe nicht Beispiel gesehen wie, das passiert, wenn man nicht malloc/free verwendet.


Moderiert von user profile iconTh69: Topic aus Andere .NET-Sprachen verschoben am Di 22.08.2017 um 13:12


Delete - Di 22.08.17 12:01

- Nachträglich durch die Entwickler-Ecke gelöscht -


tomycat - Di 22.08.17 12:13

sorry, es handelt sich um die Sprache C. Richtung php Erweiterung.


Delete - Di 22.08.17 12:36

- Nachträglich durch die Entwickler-Ecke gelöscht -


tomycat - Mi 23.08.17 11:21

Es ist alles richtig, was du geschrieben hast :-)

Ich stelle jetzt meine Frage mal anderst.
Laut Buch steht drin, man muss bei Motoradfahren einen Helm tragen, sonsten bekommet man ärger mit der Polizei. Dann gibt es blaue grüne und rote Motoradhelme...
Alles recht und schön. Meine Frage ist: Wann genau ist der Helm wichtig? Es kommt zum Unfall, was passiert dann alles, was könnte passieren?


Ralf Jansen - Mi 23.08.17 12:36

Zitat:
Es kommt zum Unfall, was passiert dann alles, was könnte passieren?


Wenn du Methoden zum Speicher allozieren falsch benutzt komt es zu Speicher Problemen :gruebel: Also primär Speicherlecks bis dein Speicher aus ist und dein Programm abschmiert.
Du scheinst eine spezielle Antwort zu wünschen aber das geht bei einer so allgemeinen Frage eher nicht.


Delete - Mi 23.08.17 12:46

- Nachträglich durch die Entwickler-Ecke gelöscht -


Ralf Jansen - Mi 23.08.17 14:44

Zitat:
meine ausstehende Parkplatz-Metapher ruiniert. :crying:


Mich würde die Story interessieren.


Delete - Mi 23.08.17 14:56

- Nachträglich durch die Entwickler-Ecke gelöscht -


hydemarie - Mi 23.08.17 18:09

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
malloc() und free() haben in der Sprache C ihre Berechtigung. Mit C++ kam das new hinzu, was genauso viel bewirkt wie malloc().


Das ist natürlich Unsinn nicht ganz richtig, denn new alloziiert keinen definierten Speicher, sondern erzeugt eine neue Instanz einer Klasse (inkl. Konstruktoraufruf, sofern vorhanden). malloc() schiebt erst mal einen bestimmten Speicherbereich frei, den du dann mit irgendwas - nicht zwangsläufig mit einer Klasseninstanz, sondern z.B. auch mit einem char* - vollschreiben kannst. Das geht auch in C++ noch. ;)


Delete - Mi 23.08.17 19:08

- Nachträglich durch die Entwickler-Ecke gelöscht -


Th69 - Mi 23.08.17 19:38

Sorry Frühlingsrolle, aber dein Code ist falsch (UB).


hydemarie - Mi 23.08.17 19:41

Und zu umständlich. Wenn sizeof(char) jemals nicht 1 sein sollte, ist dein Compiler mit absoluter Sicherheit kaputt.


tomycat - Do 24.08.17 07:41

ok danke Jungs,
kann man jemand ein Beispiel machen, wo man sagt HIER braucht man malloc und so stützt das Prog ab.


Th69 - Do 24.08.17 09:26

Lies dir am besten mal Dynamischer Speicher [https://de.wikipedia.org/wiki/Dynamischer_Speicher] (bzw. der englische Artikel dazu: C dynamic memory allocation [https://en.wikipedia.org/wiki/C_dynamic_memory_allocation]) und für C++ Speicherverwaltung / Zusammenfassung [https://de.wikibooks.org/wiki/C%2B%2B-Programmierung/_Speicherverwaltung/_Zusammenfassung] durch.


hydemarie - Do 24.08.17 09:27

Du brauchst malloc/calloc beziehungsweise realloc zum Beispiel für C und damit auch die Interaktion mit C.

Konkreter Anwendungsfall: du möchtest eine Textdatei zeilenweise in eine Variable speichern. Da C keine std::strings und keine Vektoren kennt, bräuchtest du dafür zum Beispiel einen char**-Pointer. Die einzelnen Strings brauchen aber jedes Mal eine andere Anzahl an Byte, sie sind ja selten identisch.


C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
/* Annahme: char* textfile enthält Textdatei */
while (textfile) {
    char* next_line = strchr(textfile, '\n');
    int linelength = next_line ? (next_line - textfile) : strlen(textfile); /* berechne Zeilenlänge */
    char* temp_str = (char *)malloc(linelength + 1); /* alloziere genau so viel Speicher (plus Nullterminator)! */

    if (temp_str) {
        memcpy(temp_str, textfile, linelength);
        temp_str[linelength] = '\0';
        /* temp_str = aktuelle Zeile */
        /* mach irgendwas damit */
        free(temp_str);
    }

    textfile = next_line ? (next_line + 1) : NULL;
}


Absturz (Beispiel): Räume einen Speicherbereich frei, der dir nicht gehört.


C++-Quelltext
1:
2:
int quux = 42;
free(quux); /* peng */


Delete - Do 24.08.17 09:48

- Nachträglich durch die Entwickler-Ecke gelöscht -


hydemarie - Do 24.08.17 09:53

Es ergibt nicht viel Sinn, hier einen Pointer zu verwenden. Aber warum sollte der Code falsch sein?

Nachtrag: Warum printf?


Delete - Do 24.08.17 10:07

- Nachträglich durch die Entwickler-Ecke gelöscht -


hydemarie - Do 24.08.17 10:12

Nö, ich meinte das Beispiel aus Wikibooks.


Delete - Do 24.08.17 10:20

- Nachträglich durch die Entwickler-Ecke gelöscht -


Th69 - Do 24.08.17 11:14

OK, ich dachte, das sei offensichtlich. ;-)
Ich kommentiere ihn deshalb mal:

C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
char* cNeu = new char[3];
cNeu = "Neu"// hier weist du dem Zeiger eine neue Adresse zu (auf ein String-Literal), daher ist der vorherige Zeigerwert überschrieben
printf("%s", cNeu);
delete(cNeu); // und hier hast du zwei Fehler:
              // 1. bei Arrays immer delete [] verwenden
              // 2. Undefined behaviour (UB), da jetzt in cNeu die Adresse des String-Literals steht (und nicht der von new allokierte)
// eventuell noch NULL setzen

char* cAlt = (char*)malloc(3 * sizeof(char));
cAlt = "Alt"// selbiges wie oben
printf("%s", cAlt);
free(cAlt); // also auch hier UB

Wahrscheinlich meintest du in Zeile 2 (und [jetzt] 10):

C++-Quelltext
1:
2:
3:
strncpy(cNeu, "Neu"3);
// bzw.
strncpy(cAlt, "Alt"3);

d.h. du schreibst in den mittels new/malloc allozierten Speicherbereich etwas rein (s. strncpy [http://www.cplusplus.com/reference/cstring/strncpy/]).

Ergänzung: Bedenke, daß aber hier der String dann nicht null-terminiert ist, d.h. die Ausgaben mittels cout oder printf dann ebenso UB sind!


Delete - Do 24.08.17 11:43

- Nachträglich durch die Entwickler-Ecke gelöscht -


hydemarie - Do 24.08.17 11:59

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Da müsste man mit strncpy() arbeiten.


Je nach System. Der C11-Standard und Microsoft empfehlen strncpy_s, ältere C-Standards strncpy(), unter bestimmten Systemen mit bestimmten C-Standardbibliotheken bietet sich vielleicht eher strlcpy() an. Und so weiter. :wink:

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:

C++-Quelltext
1:
*cNeu = "Neu"// findet hier eine Stringzuweisung statt?                    


Ja, aber cNeu ist hinterher immer noch NULL. 8)


Th69 - Do 24.08.17 13:29


C++-Quelltext
1:
*cNeu = "Neu";                    

Dies gibt einen Compilerfehler (oder zumindestens eine Warnung): Ideone-Code [https://ideone.com/N27rzo], sofern cNeu weiterhin als char * deklariert ist, denn *cNeu entspricht ja cNeu[0], d.h. nur der Wert der Speicheradresse (also hier ein einzelnes Zeichen (char)).

----------------
hydemarie hat folgendes geschrieben:
Ja, aber cNeu ist hinterher immer noch NULL.

Was meinst du damit??? Wie kommst du auf NULL?


hydemarie - Do 24.08.17 13:42

Gegenfrage: Mit welchem Wert (nicht: Typ) ist cNeu denn initialisiert?


Th69 - Do 24.08.17 13:53

Wir reden (bzw. schreiben) hier doch von:

C++-Quelltext
1:
char* cNeu = new char[3];                    

also hat cNeu wohl einen anderen Wert als NULL (und sollte new keinen Speicher mehr allozieren können, dann gibt es eine bad_alloc Exception).


hydemarie - Do 24.08.17 14:04

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
also hat cNeu wohl einen anderen Wert als NULL


Nämlich?

Was ist denn der Standardwert eines char?


Th69 - Do 24.08.17 14:12

Ich verstehe dich leider immer noch nicht. Bitte poste nochmals den gesamten Code, auf den du dich beziehst.


hydemarie - Do 24.08.17 14:20

Du behauptest, cNeu habe einen anderen Wert als NULL. Welchen hat er denn deiner Meinung nach? Das war doch eine eigentlich ganz einfach formulierte Frage.

Nachtrag:


C++-Quelltext
1:
printf("cNeu ist %s\n", cNeu);                    


Th69 - Do 24.08.17 14:36

cNeu ist ein Zeiger, d.h. es enthält eine Adresse:

C++-Quelltext
1:
printf("%x", cNeu);                    

Wenn du

C++-Quelltext
1:
printf("cNeu ist %s\n", cNeu);                    

ausgibst, dann gibt du den Inhalt als nullterminierten String aus, auf den cNeu zeigt (das ist etwas ganz anderes - und NULL wird dann auch nicht ausgegeben).


hydemarie - Do 24.08.17 14:44

Du hast meine Frage nicht beantwortet.

Der Wert, der an der Adresse, auf die der Zeiger zeigt, steht, ist was, wenn nicht NULL?

Was ist der Standardwert eines nicht initialisierten char*? :)

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
NULL wird dann auch nicht ausgegeben).


Das liegt daran, dass NULL nicht ausgegeben werden kann. Auf ideone steht da stattdessen (null) ... ;)

Nachtrag:

Die ursprüngliche Frage war ja:


C++-Quelltext
1:
*cNeu = "Neu"// findet hier eine Stringzuweisung statt?                    


Ich unterstelle, dass das so gemeint war, dass hinterher in cNeu "Neu" drinsteht. @Frühlingsrolle mag mich diesbezüglich korrigieren. Die Ausgabe von cNeu ist und bleibt hinterher aber "leer".


Th69 - Do 24.08.17 14:53

Das ist UB, denn bei einem nicht-initialisierten Zeiger weiß man ja gar nicht, worauf der Zeiger zeigt (irgendeine beliebige Speicheradresse):

C++-Quelltext
1:
2:
3:
4:
5:
6:
int main()
{
  char *cNeu;
  printf("%x\n", cNeu);
  printf("%s\n", cNeu);
}

(Im Debug-Modus werden diese [lokalen Variablen] zwar von einigen Compilern mit 0 initialisiert, aber spätestens im Release-Modus führst dies zu undefinertem Verhalten).

Nachtrag:
Dein letzter Satz ist jetzt aber erst recht widersprüchlich:
Wenn da "Neu" drinsteht (also wenn man es korrekt z.B. mittels strncpy oder strcpy kopiert), dann wird auch "Neu" ausgegeben!
Warum sollte der vorher zugewiesene Zeiger auf einem mal NULL sein???


hydemarie - Do 24.08.17 14:56

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Das ist UB, denn bei einem nicht-initialisierten Zeiger weiß man ja gar nicht, worauf der Zeiger zeigt


Und wenn du ihn ausgibst, ist das Verhalten in jedem mir bekannten Compiler gleich: Da steht dann "nichts" drin. ;)

(N.b.: calloc() ist in vielen Fällen die deutlich bessere Wahl, wenn man sich über die Werte nicht ganz sicher ist.)


Th69 - Do 24.08.17 15:11

Hier nochmal als Ideone-Code [https://ideone.com/ht5Aci] -> Runtime error!


Delete - Do 24.08.17 17:22

- Nachträglich durch die Entwickler-Ecke gelöscht -


tomycat - Fr 25.08.17 08:16

user profile iconhydemarie hat folgendes geschrieben Zum zitierten Posting springen:
Du brauchst malloc/calloc beziehungsweise realloc zum Beispiel für C und damit auch die Interaktion mit C.

Konkreter Anwendungsfall: du möchtest eine Textdatei zeilenweise in eine Variable speichern. Da C keine std::strings und keine Vektoren kennt, bräuchtest du dafür zum Beispiel einen char**-Pointer. Die einzelnen Strings brauchen aber jedes Mal eine andere Anzahl an Byte, sie sind ja selten identisch.


C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
/* Annahme: char* textfile enthält Textdatei */
while (textfile) {
    char* next_line = strchr(textfile, '\n');
    int linelength = next_line ? (next_line - textfile) : strlen(textfile); /* berechne Zeilenlänge */
    char* temp_str = (char *)malloc(linelength + 1); /* alloziere genau so viel Speicher (plus Nullterminator)! */

    if (temp_str) {
        memcpy(temp_str, textfile, linelength);
        temp_str[linelength] = '\0';
        /* temp_str = aktuelle Zeile */
        /* mach irgendwas damit */
        free(temp_str);
    }

    textfile = next_line ? (next_line + 1) : NULL;
}


Absturz (Beispiel): Räume einen Speicherbereich frei, der dir nicht gehört.


C++-Quelltext
1:
2:
int quux = 42;
free(quux); /* peng */


ok, wenn ich es richtig verstanden habe, lese ich eine Text Datei zeilenweise aus und jedesmal beantrage ich einen Speicherbereich. Erst am Ende mache ich den Speicher wieder frei?


hydemarie - Fr 25.08.17 09:20

Du machst den Speicher frei, sobald du ihn beziehungsweise den Wert nicht mehr brauchst. :)
Am Ende würde auch gehen, aber dann müsstest du realloc() (Neubelegen noch reservierten Speichers) für jede Zeile nutzen. Vorteil: du müsstest nur noch einmal aufräumen. Ist aber gefährlicher, was mögliche Memleaks, also auch nach dem Programmende noch belegten Speicher, betrifft, zum Beispiel bei Fehlern in der Schleife.


tomycat - Fr 25.08.17 16:10

ok,
Zeile 2: Wenn textfile Null, dann bricht die Schleife ab.
Zeile 3: Es wird Untersucht ob ein \n in textfile vorhanden ist, das wird in nextline gespeichert.
Zeile 4: ist nextline wahr, dann kommt es zu einer Subtaktion, ähh das geht ?!? Zeichenlänge wird berechnet
Zeile 5: Dann reserviere ich mir einen Speicherplatz für linelenth und weise Ihn dem temp_str zu, richtig?

Wird die If Abfrage ausgeführt, bei 10 Zeilen, 10 mal ausgeführt. Dann wird doch immer der Speicher wieder freigegeben?


hydemarie - Fr 25.08.17 16:18

Das ist so richtig, ja. :)


tomycat - Sa 26.08.17 00:20

user profile iconhydemarie hat folgendes geschrieben Zum zitierten Posting springen:
Das ist so richtig, ja. :)

Aber warum kommt es dannn zu crash?


hydemarie - Sa 26.08.17 00:22

Wo?


tomycat - Mo 28.08.17 14:14

THX,
Ok, ich nehme an wenn ich free auskokumentiere, dann kommt es zum crash?!?
Woher weis ich, ok, jetzt brauche ich malloc?
Wo orientiere ich mich?
Wo ist die Grenze?


hydemarie - Mo 28.08.17 15:53

Wenn du irgendwo free() auskommentierst, dann hast du ein Speicherleck, aber keinen Absturz.

Es gibt keine Grenze. :)


tomycat - Mo 28.08.17 21:02

@hydemarie
danke dass du mich verstehst :-)
ok, dann habe ich ein Speicherleck, wieder was gelernt.
sorry, wenn ich nerve. Aber ich weis immer noch nicht, wann ich malloc verwenden soll?
Ich lass free weg, woher weis ich wann dann creash kommt, oder geht der Rechner in die Knie?
Nach was soll ich googlen?


hydemarie - Mo 28.08.17 21:10

user profile icontomycat hat folgendes geschrieben Zum zitierten Posting springen:
sorry, wenn ich nerve. Aber ich weis immer noch nicht, wann ich malloc verwenden soll?


Das sollte dir auch leid tun! :D
malloc() verwendest du überall dort, wo dir kein RAII [https://de.wikipedia.org/wiki/RAII] zur Verfügung steht, also meist im Umgang mit C-Schnittstellen oder wenn du direkt C benutzst.

user profile icontomycat hat folgendes geschrieben Zum zitierten Posting springen:
Ich lass free weg, woher weis ich wann dann creash kommt


Crash kommt, wenn das Programm plötzlich ausgeht. :!:

user profile icontomycat hat folgendes geschrieben Zum zitierten Posting springen:
oder geht der Rechner in die Knie?


Theoretisch könntest du mit malloc() und daraus folgenden Speicherlecks einen Rechner quasi lahmlegen, ja.
Wenn du mehr Speicher belegst als du frei hast. Das kann aber auf heutigen Systemen dauern. ;)

Trotzdem solltest du das natürlich nicht vernachlässigen. Jedes weggeworfene Byte ist ein weggeworfenes Byte.

user profile icontomycat hat folgendes geschrieben Zum zitierten Posting springen:
Nach was soll ich googlen?


Grundsätzlich nach Taylor Swift. Die macht bessere Musik als es oft kolportiert wird. Thematisch allerdings empfehle ich allenfalls Wikibooks [https://de.wikibooks.org/wiki/C-Programmierung:_Speicherverwaltung].


tomycat - Di 29.08.17 16:35

danke, jetzt habe ich eine Richtung.