Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
c:tutorial:memory [2013/01/11 23:03]
dani93
c:tutorial:memory [2022/09/22 19:58] (aktuell)
Zeile 1: Zeile 1:
-====== Dynamische ​Speicherverwalteng ​======+====== Dynamische ​Speicherverwaltung ​======
  
-  * Wozu braucht dynamische ​Speicherveraltung?+  * Wozu braucht ​man dynamische ​Speicherverwaltung?
   * Den benötigten Speicher herausfinden   * Den benötigten Speicher herausfinden
   * Speicher anfordern und freigeben   * Speicher anfordern und freigeben
Zeile 8: Zeile 8:
   * Mit der Standard-C-Lib ins Ziel   * Mit der Standard-C-Lib ins Ziel
  
-===== Wozu braucht dynamische ​Speicherveraltung? =====+===== Wozu braucht ​man dynamische ​Speicherverwaltung? =====
  
 Bisher haben wir die Spielregeln geübt. Mit dieser Lektion kommen wir endlich in die Lage, damit zu spielen. Denn worum geht es beim Programmieren?​ Es geht darum Daten zu verarbeiten,​ und zwar Daten, die wir vorher nicht kennen. Wir werden uns hier damit beschäftigen,​ zwei Strings miteinander zu einem einzigen String zu verbinden. Eine Aufgabe, die immer wieder vorkommt, wenn man Beispielsweise einen Vornamen und den zugehörigen Nachnamen zu einem Text zusammenfügen möchte. Bisher haben wir die Spielregeln geübt. Mit dieser Lektion kommen wir endlich in die Lage, damit zu spielen. Denn worum geht es beim Programmieren?​ Es geht darum Daten zu verarbeiten,​ und zwar Daten, die wir vorher nicht kennen. Wir werden uns hier damit beschäftigen,​ zwei Strings miteinander zu einem einzigen String zu verbinden. Eine Aufgabe, die immer wieder vorkommt, wenn man Beispielsweise einen Vornamen und den zugehörigen Nachnamen zu einem Text zusammenfügen möchte.
Zeile 14: Zeile 14:
 Hierbei bekommen wir zunächst ein Problem: Beim Start des Programms wissen wir noch nicht wie lang Vorname und Nachname sein werden. Wir müssten also ein Array verwenden, von dem wir hoffen, dass es lang genug ist. Das ist ein übliches, wie auch kritisches Vorgehen. Die Größe des Arrays ist im Quelltext festgelegt und kann nicht verändert werden. Die Größe ist statisch. Wenn man davon ausgeht, dass niemand einen Namen mit mehr als 100 Buchstaben hat, dann funktioniert das Programm vermutlich für alle Personen, die Du kennst. Wenn das Programm aber von anderen verwendet wird, dann wird es garantiert jemanden geben, der einen entsprechend langen Namen hat. Hierbei bekommen wir zunächst ein Problem: Beim Start des Programms wissen wir noch nicht wie lang Vorname und Nachname sein werden. Wir müssten also ein Array verwenden, von dem wir hoffen, dass es lang genug ist. Das ist ein übliches, wie auch kritisches Vorgehen. Die Größe des Arrays ist im Quelltext festgelegt und kann nicht verändert werden. Die Größe ist statisch. Wenn man davon ausgeht, dass niemand einen Namen mit mehr als 100 Buchstaben hat, dann funktioniert das Programm vermutlich für alle Personen, die Du kennst. Wenn das Programm aber von anderen verwendet wird, dann wird es garantiert jemanden geben, der einen entsprechend langen Namen hat.
  
-Also lösen wir das Problem anders: Wir finden zunächst heraus, wie lang der Vorname und Nachname ​ist und fordern dann dynamisch Speicher an:+Also lösen wir das Problem anders: Wir finden zunächst heraus, wie lang Vorname und Nachname ​sind und fordern dann dynamisch Speicher an:
  
 ===== Den benötigten Speicher herausfinden ===== ===== Den benötigten Speicher herausfinden =====
Zeile 60: Zeile 60:
 [[c:​lib:​stdlib:​malloc()]] übergibt man die benötigte Größe in Bytes und man erhält einen Zeiger auf den bereitgestellten Speicher. Falls [[c:​lib:​stdlib:​malloc()]] einen Nullzeiger zurückgibt,​ kann das Betriebssystem keinen Speicher in der gewünschten Größe zur Verfügung stellen. [[c:​lib:​stdlib:​malloc()]] übergibt man die benötigte Größe in Bytes und man erhält einen Zeiger auf den bereitgestellten Speicher. Falls [[c:​lib:​stdlib:​malloc()]] einen Nullzeiger zurückgibt,​ kann das Betriebssystem keinen Speicher in der gewünschten Größe zur Verfügung stellen.
  
-Damit nicht mehr benötigter Speicher ​an anderer Stelle wieder verwendet werden darf, muss man ihn erst wieder freigeben. Hierfür übergibt man der Funktion [[c:​lib:​stdlib:​free()]] den Zeiger, den man zuvor von malloc() erhalten hat. Man darf zwar den Nullzeiger, aber nicht bereits einmal freigegebenen Speicher ein zweites Mal freigeben.+Damit Speicher der nicht mehr benötigt wird an anderer Stelle wieder verwendet werden darf, muss man ihn erst wieder freigeben. Hierfür übergibt man der Funktion [[c:​lib:​stdlib:​free()]] den Zeiger, den man zuvor von malloc() erhalten hat. Man darf zwar den Nullzeiger, aber nicht bereits einmal freigegebenen Speicher ein zweites Mal freigeben.
  
 [[c:​lib:​stdio:​printf()]] wird in der Headerdatei [[c:​lib:​stdio:​|stdio.h]] deklariert, für die Funktionen [[c:​lib:​stdlib:​malloc()]] und [[c:​lib:​stdlib:​free()]] benötigen wir zusätzlich die [[c:​lib:​stdlib:​|stdlib.h]] [[c:​lib:​stdio:​printf()]] wird in der Headerdatei [[c:​lib:​stdio:​|stdio.h]] deklariert, für die Funktionen [[c:​lib:​stdlib:​malloc()]] und [[c:​lib:​stdlib:​free()]] benötigen wir zusätzlich die [[c:​lib:​stdlib:​|stdlib.h]]
- 
  
 <code cpp> <code cpp>
Zeile 105: Zeile 104:
  
 <code cpp> ​ char * name = (char *) malloc( length );</​code>​ <code cpp> ​ char * name = (char *) malloc( length );</​code>​
-Auch das ist gültiges C, was hier genau passiert, nennt sich "​Casting"​ und ist bei einem C++ Compiler erforderlich. Was Casting ist, erkläre ich in einer späteren Lektion.+Auch das ist gültiges C, was hier genau passiert, nennt sich "​Casting"​ und ist bei einem C++ Compiler erforderlich. Was Casting ist wird in einer späteren Lektion ​erklärt.
  
 ===== Zugriff auf den angeforderten Speicher ===== ===== Zugriff auf den angeforderten Speicher =====
  
-Wir haben in der [[pointer|vorherigen Lektion über Zeiger]] gelernt, dass man mit Zeigern ​genauso arbeiten kann, wie mit Arrays. Wir können nun eine Funktion schreiben, die einen String kopiert.+Wir haben in der [[pointer|vorherigen Lektion über Zeiger]] gelernt, dass man mit ihnen genauso arbeiten kann, wie mit Arrays. Wir können nun eine Funktion schreiben, die einen String kopiert.
  
 Das mache ich jetzt einfach mal, lies sie Dir gut durch und bemühe Dich sie nachzuvollziehen:​ Das mache ich jetzt einfach mal, lies sie Dir gut durch und bemühe Dich sie nachzuvollziehen:​
Zeile 180: Zeile 179:
  
 ^ 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 ^ 8 ^ 9 ^ 10 ^ 11 ^ 12 ^ 13 ^ 14 ^ 15 ^ 16 ^ ^ 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 ^ 8 ^ 9 ^ 10 ^ 11 ^ 12 ^ 13 ^ 14 ^ 15 ^ 16 ^
-| H | a | n | s | '\0‘ | @ | @ | @ | @ | @ | @ | @ | @ | @ | @ | @ | @ |+| H | a | n | s | '\0' ​| @ | @ | @ | @ | @ | @ | @ | @ | @ | @ | @ | @ |
  
 Die Funktion hat 4 Buchstaben kopiert und gibt entsprechend 4 zurück, die in der Variablen ''​position''​ gespeichert. Anschließend wird an ''​position''​ das Nullbyte mit dem Leerzeichen überschrieben:​ Die Funktion hat 4 Buchstaben kopiert und gibt entsprechend 4 zurück, die in der Variablen ''​position''​ gespeichert. Anschließend wird an ''​position''​ das Nullbyte mit dem Leerzeichen überschrieben:​
  
 ^ 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 ^ 8 ^ 9 ^ 10 ^ 11 ^ 12 ^ 13 ^ 14 ^ 15 ^ 16 ^ ^ 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 ^ 8 ^ 9 ^ 10 ^ 11 ^ 12 ^ 13 ^ 14 ^ 15 ^ 16 ^
-| H | a | n | s | ' ​‘ | @ | @ | @ | @ | @ | @ | @ | @ | @ | @ | @ | @ |+| H | a | n | s | ' ​' ​| @ | @ | @ | @ | @ | @ | @ | @ | @ | @ | @ | @ |
  
 Anschließend wird ''​position''​ um eins erhöht. Anschließend wird ''​position''​ um eins erhöht.
Zeile 194: Zeile 193:
  
 ^ 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 ^ 8 ^ 9 ^ 10 ^ 11 ^ 12 ^ 13 ^ 14 ^ 15 ^ 16 ^ ^ 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 ^ 8 ^ 9 ^ 10 ^ 11 ^ 12 ^ 13 ^ 14 ^ 15 ^ 16 ^
-| H | a | n | s | ' ​‘ | M | u | s | t | e | r | m | a | n | n | '​\0'​ | @ |+| H | a | n | s | ' ​' ​| M | u | s | t | e | r | m | a | n | n | '​\0'​ | @ |
  
 Die 16 Bytes, die wir alloziert haben verlaufen vom 0. bis zum 15. Byte und das 16. Byte ist von uns nicht berührt worden - das ist wichtig, denn wir dürfen dieses Byte weder lesen noch schreiben! Die 16 Bytes, die wir alloziert haben verlaufen vom 0. bis zum 15. Byte und das 16. Byte ist von uns nicht berührt worden - das ist wichtig, denn wir dürfen dieses Byte weder lesen noch schreiben!
Zeile 250: Zeile 249:
 <code cpp>​printf( "%s %s", vorname, nachname );</​code>​ <code cpp>​printf( "%s %s", vorname, nachname );</​code>​
  
-Freundlicherweise kann man mit [[c:​lib:​stdio:​sprintf()]] auch einfach in den Speicher schreiben. Aber man muss hierbei sehr gut aufpassen, dass man sich hier nicht in der Länge vertut. Zahlen, die per ''​%d''​ eingefügt werden, können schließlich einstellig (1) oder auch mehrstellig (1234) sein. Genauso muss die Länge der eingefügten Strings berücksichtigt werden.+Freundlicherweise kann man mit [[c:​lib:​stdio:​sprintf()]] auch einfach in den Speicher schreiben. Aber man muss hierbei sehr gut aufpassen, dass man sich hier nicht in der Länge vertut. Zahlen, die per ''​%d''​ eingefügt werden, können schließlich einstellig (z.B. 1) oder auch mehrstellig (z.B. 1234) sein. Genauso muss die Länge der eingefügten Strings berücksichtigt werden.
  
 <code cpp> <code cpp>
Zeile 278: Zeile 277:
 </​code>​ </​code>​
  
-Damit haben wir unsere ganzen bisherigen Bemühungen ​hier auf eine Zeile mit der [[c:​lib:​stdio:​sprintf()]]-Funktion auf eine Zeile verkürzt - ein Blick in die [[c:​lib:​|C-Standard-Library]] kann also lohnen.+Damit haben wir unsere ganzen bisherigen Bemühungen mit der [[c:​lib:​stdio:​sprintf()]]-Funktion auf eine Zeile verkürzt - ein Blick in die [[c:​lib:​|C-Standard-Library]] kann sich also lohnen.
  
-Mit [[c:​lib:​stdio:​sprintf()]] lassen sich all die schönen Transformationen ​durchführend, genauso wie mit [[c:​lib:​stdio:​printf()]],​ entsprechend des übergebenen [[c:​lib:​stdio:​formatstring|Formatstrings]].+Mit [[c:​lib:​stdio:​sprintf()]] lassen sich all die schönen Transformationen ​durchführen, genauso wie mit [[c:​lib:​stdio:​printf()]],​ entsprechend des übergebenen [[c:​lib:​stdio:​formatstring|Formatstrings]].
  
 ====== Ziel dieser Lektion ====== ====== Ziel dieser Lektion ======
Zeile 289: Zeile 288:
  
 Im nächsten Kapitel werden wir uns ansehen, was es neben ''​const''​ noch für [[c:​tutorial:​Attribute]] gibt, um Einfluss auf die Verwendung von Datentypen zu nehmen. Im nächsten Kapitel werden wir uns ansehen, was es neben ''​const''​ noch für [[c:​tutorial:​Attribute]] gibt, um Einfluss auf die Verwendung von Datentypen zu nehmen.
 +
 +----
 +[[https://​www.proggen.org/​forum/​viewtopic.php?​f=39&​t=6138|Autorendiskussion]]\\