Einführung in die Programmierung zusammengesetzte Datentypen, dynamischer Speicher

Ähnliche Dokumente
Praxis der Programmierung

Einführung in die Programmierung Konstanten, dynamische Datenstrukturen. Arvid Terzibaschian

Vorlesung Programmieren

Praxis der Programmierung

Teil 6: Strukturen und Unionen Gliederung

Dynamische Speicherverwaltung

F Zeiger, Felder und Strukturen in C

Teil 6: Strukturen und Unionen Gliederung

C++ - Einführung in die Programmiersprache Zeiger, Referenzen und Strukturen. Leibniz Universität IT Services Anja Aue

Advanced Programming in C

Programmiertechnik. Teil 4. C++ Funktionen: Prototypen Overloading Parameter. C++ Funktionen: Eigenschaften

Programmieren in C. Speicher anfordern, Unions und Bitfelder. Prof. Dr. Nikolaus Wulff

Informatik. Pointer (Dynamisch) Vorlesung. 17. Dezember 2018 SoSe 2018 FB Ing - SB Umwelttechnik und Dienstleistung - Informatik Thomas Hoch 1

INE1 Arrays, Zeiger, Datenstrukturen

Praxis der Programmierung

Grundlagen der Informatik 11. Zeiger

8. Referenzen und Zeiger

Dynamischer Speicher

2. Programmierung in C

C- Kurs 08 Zeiger. Dipl.- Inf. Jörn Hoffmann leipzig.de. Universität Leipzig Ins?tut für Informa?k Technische Informa?

Praxis der Programmierung

C++ Teil 5. Sven Groß. 13. Mai Sven Groß (IGPM, RWTH Aachen) C++ Teil Mai / 18

Dynamische Speicherverwaltung

Einführung Pointer. C-Kurs 2013, 2. Vorlesung. Nico Andy

Informatik 1 ( ) D-MAVT F2011. Pointer, Structs. Yves Brise Übungsstunde 6

Algorithmen und Datenstrukturen

2. Programmierung in C

Übungspaket 29 Dynamische Speicherverwaltung: malloc() und free()

C++ Teil 6. Sven Groß. 23. Nov Sven Groß (IGPM, RWTH Aachen) C++ Teil Nov / 15

Funktionen: Rückgabewert

Dynamische Datentypen. Destruktor, Copy-Konstruktor, Zuweisungsoperator, Dynamischer Datentyp, Vektoren

Teil 5: Zeiger, Felder, Zeichenketten Gliederung

C++ - Objektorientierte Programmierung Konstante und statische Elemente

6. Zeiger Allgemeines Definition eines Zeigers

Probeklausur Name: (c)

Programmiersprache 1 (C++) Prof. Dr. Stefan Enderle NTA Isny

Crashkurs C++ - Teil 1

Verschlüsseln eines Bildes. Visuelle Kryptographie. Verschlüsseln eines Bildes. Verschlüsseln eines Bildes

K Ergänzungen zur Einführung in C

C++ Teil 5. Sven Groß. 8. Mai IGPM, RWTH Aachen. Sven Groß (IGPM, RWTH Aachen) C++ Teil 5 8. Mai / 16

Programmierung mit C Zeiger

Programmierwerkstatt. Arrays, Pointer und Referenzen

Informatik. Strukturen und Aufzählungstypen. Vorlesung

Zeiger. C-Kurs 2012, 2. Vorlesung. Tino Kutschbach 10.

Propädeutikum. Dipl.-Inf. Frank Güttler

Praxis der Programmierung

Variablen und Parameter

Angewandte Mathematik und Programmierung

INE1 Speicherverwaltung und zweidimensionale Arrays. Speicherorganisation Dynamischer Speicher in C Zweidimensionale Arrays

Betriebssysteme, Rechnernetze und verteilte Systeme 1. Crashkurs C (2)

Einleitung Grundlagen Erweiterte Grundlagen Zusammenfassung Literatur. C: Funktionen. Philip Gawehn

Einführung in die Programmierung

Teil 5: Felder, Zeiger, Zeigerarithmetik Gliederung

Variablen. Deklaration: «Datentyp» «Variablenname» Datentyp bestimmt Größe in Bytes: sizeof Beispiel: long int v; Größe: 4 Bytes

Einführung in die Programmiersprache C

Einführung in die Programmierung für Physiker. Die Programmiersprache C Strukturen ("struct...")

Einführung in die Programmierung für Physiker. Die Programmiersprache C Strukturen ("struct...")

Kapitel 5: Funktionen. Inhalt

Grundlagen der Programmiersprache C für Studierende der Naturwissenschaften

Programmieren in Java

einlesen n > 0? Ausgabe Negative Zahl

Arrays,Strings&Pointer in C/C++

Inhalt. 4.5 Arbeit mit Zeigern (engl. Pointer)

Einführung in die Programmiersprache C

Vorkurs C++ Programmierung

Einführung in die Programmiersprache C

Programmieren I. Kapitel 12. Referenzen

Einführung in die Informatik für Naturwissenschaftler und Ingenieure (alias Einführung in die Programmierung)

Repetitorium Programmieren I + II

Einführung in die Programmierung Arrays, Zeiger, Strings. Arvid Terzibaschian

Übersicht. Speichertypen. Speicherverwaltung und -nutzung. Programmieren in C

Operatoren in C. Gastvorlesung Andreas Textor

Visuelle Kryptographie. Anwendung von Zufallszahlen

Übungspaket 29 Dynamische Speicherverwaltung: malloc() und free()

Grundlagen der OO- Programmierung in C#

Felder, Zeiger und Adreßrechnung

Einführung in die Programmierung Konstanten, dynamische Datenstrukturen. Arvid Terzibaschian

Java Referenzdatentypen genauer betrachtet

Zeiger (engl. Pointer)

Software Entwicklung 1

Strukturen in C. Strukturen stellen eine Zusammenfassung von Datenelementen unterschiedlichen Typs unter einem Namen dar.

Teil 8: Dynamische Speicherverwaltung. Prof. Dr. Herbert Fischer Fachhochschule Deggendorf Prof. Dr. Manfred Beham Fachhochschule Amberg-Weiden

2. Programmierung in C

Dynamische Speicherverwaltung

Arrays (Felder/Vektoren)

Programmierung und Angewandte Mathematik

Informatik 1 ( ) D-MAVT F2010. Schleifen, Felder. Yves Brise Übungsstunde 5

Einführung in C. Alexander Batoulis. 5. Mai Fakutltät IV Technische Universität Berlin

Bei for-schleifen muss man nur immer bedenken, dass die letzte Anweisung immer erst nach der Ausführung der restlichen Anweisungen der Schleife

2. Programmierung in C

Bereits behandelt: Einfache Datentypen / Variablen. Schleifen und Verzweigungen. Funktionen. Heute: Felder, Zeiger, Referenzen. Freispeicherverwaltung

Einführung in die Programmiersprache C

Pointer und Arrays. INE1, Montag M. Thaler, Office TG208. ZHAW, M. Thaler, K. Rege, G.

9. Vektoren. (auch Felder/array)

Zeiger in C und C++ Zeiger in Java und C/C++

Dynamisches Speichermanagement

Praxisorientierte Einführung in C++ Lektion: "Dynamische Speicherverwaltung"

Zeiger und dynamischer Speicher

Transkript:

Einführung in die Programmierung zusammengesetzte Datentypen, dynamischer Speicher Arvid Terzibaschian 1

Zusammengesetzte Datentypen 2

Wozu zusammengesetzte Datentypen? Anforderung: Sie sollen ein Kundenverzeichnis anlegen. Für jeden Kunden sollen Kenndaten gespeichert werden: Name Adresse Umsätze der letzten Monate Kundennummer Telefon Wie kann man das Modellieren? 3

Wozu zusammengesetzte Datentypen? Anforderung: Sie sollen ein Kundenverzeichnis anlegen. Wie kann man das Modellieren? Ansatz 1: Eine Array-Variable für jedes Feld (für 256 Kunden) Probleme: Zusammengehörigkeit der Variablen nicht sichergestellt Übergabe an Funktionen nur einzeln möglich Andere Möglichkeit? int kundennummer[256]; char *name[256]; char *adresse[256]; Kunde: Name,Adresse, Telefon Umsätze,Kundennummer 4

Zusammengesetzte Datentypen: structs Anforderung: Sie sollen ein Kundenverzeichnis anlegen. Lösung: structs erlauben das zusammensetzen von Datentypen zu neuen, komplexeren Datentypen Modellierung mit structs: Kunde: Name,Adresse, Telefon Umsätze,Kundennummer int kundennummer[256]; char *name[256]; char *adresse[256]; struct t_kunde { int kundennummer; char name[64]; char adresse[64]; ; dynamischer String: Platz für 63 Zeichen struct t_kunde kunden[256]; 5

Zusammengesetzte Datentypen: structs structs erlauben Zusammensetzen komplexer Datentypen Definition meist außerhalb von Funktionen der Ausdruck struct { definiert immer einen Datentyp: neuer struct-datentyp: struct t_kunde struct t_kunde { int kundennummer; char name[64]; char adresse[64]; ; Elemente des struct-datentyps: Deklaration wie Variablen/Zeiger struct t_kunde kunden[256]; neue (Array-)Variable kunden mit Datentyp struct t_kunde 6

struct-datentypen zusammengesetzte Datentypen sind elementares Konzept der Softwareentwicklung bilden Zusammengehörigkeit bestimmter Daten direkt ab erleichtern das Modellieren von komplexen Problemen viele Dinge der Realität können mit zusammengesetzten Datentypen wesentlich besser modelliert werden als durch elementaren Zahlen und Strings == [10110101001000010]?? erhöhen die Lesbarkeit und damit Wartbarkeit des Quellcodes z.b. ist eine struct-variable kunden wesentlich aussagekräftiger als ein Array für je Adresse, Telefonnummer 7

Arbeiten mit struct-variablen Zugriff auf einzelne Elementvariablen: per Punkte-Operator strcpy(kunde1.name, Bill Gates ); kunde1.kundennummer = 12; Initialisieren von struct-variablen: in Initialwerte in Reihenfolge der struct-elemente angeben Zuweisen von struct-variablen struct kunde_t { int kundennummer; char name[64]; char adresse[64]; ; /*<- neuer Typ */ /* neue Variable: */ struct kunde_t kunde1; struct kunde_t kunde2; Warum einmal strcpy und einmal Bill Gates? struct kunde_t kunde3 = {20, Bill Gates, USA ; strcpy(kunde1.adresse, Zehlendorf ); kunde2 = kunde1; // Kopiert Werte aller Elementvariablen strcpy(kunde1.adresse, Lichtenberg ); Value-Semantik wie bei elementaren Variablen: Kopieren aller Werte Was ergibt printf(kunde2.adresse)? 8

struct und Speicher Elemente der struct-variablen liegen hintereinander im Speicher Beispiel: struct kunde_t kunden[3]; struct kunde_t { int kundennummer; char name[64]; char adresse[64]; ; /*<- neuer Typ */ /* neue Variable: */ struct kunde_t kunde1; struct kunde_t kunde2; Adresse Element Größe 0xF000 kunde[0].kundennummer 4 Byte kunde[0] 0xF000+4 kunde[0].name 64 Byte 0xF000+68 kunde[0].adresse 64 Byte 0xF000+132 kunde[1].kundennummer 4 Byte kunde[1] kunde[1].name 64 Byte kunde[1].adresse 64 Byte 0xF000+264 kunde[2].kundennummer 4 Byte kunde[2] kunde[2].name 64 Byte kunde[2].adresse 64 Byte 9

struct und Funktionen struct kunde_t { int kundennummer; char name[64]; char adresse[64]; ; /*<- neuer Typ */ Parameter von Funktionen mit struct-datentyp void drucke_kunde(struct kunde_t k) { printf( Name: %s,k.name); printf( Adresse: %s,k.adresse); printf( KdNr: %d,k.kundennummer); Bei Aufruf Call-By-Value-Semantik nur Kopie wird Funktion übergeben Rückgabewerte mit struct-datentyp struct kunde_t neuer_kunde() { kunde_t k = {0, Mustermann, Musterstraße 123 ; return k; 10 auch hier wird Werte-Kopie als Ergebnis zurückgegeben

struct und Funktionen struct-parameter werden immer per Call-By-Value übergeben: void drucke_kunde(struct kunde_t k) { printf( Name: %s,k.name); printf( Adresse: %s,k.adresse); printf( KdNr: %d,k.kundennummer); struct kunde_t { int kundennummer; char name[64]; char adresse[64]; ; /*<- neuer Typ */ Folgerungen: int main() { kunde_t k1 = {10, Karl-Heinz, Berlin ; drucke_kunde(k); unnötiges Kopieren von Werten Rechen- und Speicherkosten Funktionen können Werte nicht bearbeiten k1 wird kopiert und dann druck_kunde mit Kopie aufgerufen Alternative: Call-by-Reference-Semantik via struct-zeigern 11

struct und Funktionen Call-By-Reference mit struct-zeigern void drucke_kunde(struct kunde_t *k) { printf( Name: %s,k->name); printf( Adresse: %s,k->adresse); printf( KdNr: %d,k->kundennummer); Folgerungen: kein unnötiges kopieren Veränderungen von struct-variablen durch Funktionen möglich Problem: Zeiger können nicht initialisiert sein Programmierer hat volle Verantwortung struct kunde_t { int kundennummer; char name[64]; char adresse[64]; ; /*<- neuer Typ */ Operator -> greift auf Elemente von struct-zeigern zu Achtung: keine Gültigkeitsprüfung (!= NULL) des Zeigers k int main() { kunde_t k1 = {10, Karl-Heinz, Berlin ; drucke_kunde(&k1); struct-zeiger auf Variable k1 wird übergeben 12

Einschub: Typedef typedef erlaubt Aliasnamen für Datentypen zu erstellen: struct kunde_t { int kundennummer; char *name; char *adresse; ; typedef struct kunde_t customer; alter Datentyp Aliasname für Datentyp Aliasname customer kann wie struct kunde_t verwendet werden: struct kunde_t kunde1; = customer kunde1; 13

struct und Funktionen Erhöhen der Kundennummer mit Call-By-Value typedef struct kunde_t { int kdnr; char name[64]; char adresse[64]; cust; Call-By-Reference (~Pointer) Daten 3x kopiert Daten 0x kopiert cust inc_kundennr(cust c) { c.kdnr++; return c; 2 int main() { cust kunde = {1, Frank, Berlin ; 1 kunde = inc_kundennr(kunde); 3 printf( Nr: %d,kunde.kdnr); void inc_kundennr(cust *c) { c->kdnr++; ; int main() { cust kunde = {1, Frank, Berlin ; inc_kundennr(&kunde); printf( Nr: %d,kunde.kdnr); bei Aufruf der Funktion beim return in der Funktion beim Zuweisen nach der Funktion aber: Compiler kann hier oft optimieren maximale Geschwindigkeit aber: Pointer sind fehleranfälliger 14

structs in structs struct-datentypen können andere structs enthalten: struct schueler_t { const char name[64]; int note; ; struct raum_t { int haus; int etage; int nr; ; struct kurs_t { const char lehrer[64]; const char name[64]; struct schueler_t schueler[30]; struct raum_t raum; ; struct kurs_t k; strcpy(k.name, Mathe ); k.raum.haus = 3; k.schueler[1].note = 1; structs können sich nicht selbst enthalten nur als Zeiger für z.b. dynamische Strukturen 15

Zusammenfassung struct Bilden zusammengesetzte Datentypen wichtig für Modellierung komplexer Probleme structs können structs enthalten Können als Datentypen für Variablen und Arrays verwendet werden Können als Parameter von Funktionen genutzt werden Call-By-Value-Semantik ohne Zeiger Werte-Kopien Call-By-Reference-Semantik mit Zeigern Adress-übergabe 16

Dynamischer Speicher der Heap 17

Dynamischer Speicher: Warum? Daten bisher gespeichert in elementaren Variablen Größe und Anzahl der Variablen vorher festgelegt struct-variablen Größe und Anzahl der Variablen vorher festgelegt Arrays und Strings Größe und Anzahl der Arrays/Strings vorher festgelegt Problem: oft Anzahl Elemente/ Speicherplätze erst zur Laufzeit berechenbar max. Größe anzunehmen Speicherverschwendung 18

Dynamischer Speicher: Warum? Problem: oft ist Größe der benötigten Datenspeicher vor Laufzeit des Programms nicht bekannt Länge von Arrays und Strings erst zur Laufzeit bestimmbar immer max. Größe anzunehmen ist Speicherverschwendung Lösung: Dynamische Speicherreservierung mit malloc() und free() Speicherreservierung on demand Vorteile: optimale Speichernutzung und dynamische Strukturen Nachteile: komplexere Programmlogik fehleranfälligerer Code Speicherverlust möglich (Memory-Leaks) 19

Speicherbereiche eines Programms gesamter Speicher des Programmes. Vom Betriebssystem zugewiesen 20 Programm-Stack: wird automatisch verwaltet alle Variablen Größe und Anzahl der Variablen alle Arrays zur Compile-Time bekannt alle Parameter von Funktionsaufrufen temporäre Werte zur Berechnung Funktionsaufrufsliste (Funktions-Stack) statische Daten konstante Werte z.b. bei Initialisierung von Strings und Variablen statischer Maschinencode kompilierte Anweisungen Inhalt der ausführbaren Maschinencode- Datei Programm-Heap dynamischer Speicherbereich Programm kann Speicher dynamisch vom Was ist das? Betriebssystem anfordern wird durch Programm in C mit malloc() verwaltet kann vom Programm freigegeben werden in C mit free();

Dyn. Speicher vom Heap Anforderung: ganze Zahlen von 1 N in Array speichern Größe des Arrays zur Laufzeit nicht bekannt Lösung: Funktion malloc() nutzen, um Speicher für n Elemente zur Laufzeit zur Verfügung zu stellen: Funktion void* malloc(int nbytes); reserviert n Bytes Speicher vom Heap und gibt Anfangsadresse als Zeiger zurück Stack int n = 25; int i; int *nums; nums = malloc(n * sizeof(int)); for(i = 0;i<n;++i { nums[i] = i; statische Daten statischer Code Heap [~RAM] sizeof(datentyp) bestimmt die Größe eines Datentyps in Byte Erinnere: Zeiger kann wie Array betrachtet werden 21

Dyn. Speicher vom Heap Funktion malloc() nutzen, um Speicher für n Elemente zur Laufzeit zur Verfügung zu stellen: Funktion void* malloc(int nbytes); reserviert n Bytes Speicher vom Heap und gibt Anfangsadresse als Zeiger zurück Problem: int n = 25; int i; int *nums; nums = malloc(n * sizeof(int)); for(i = 0;i<n;++i { nums[i] = i; Stack statische Daten statischer Code Heap [~RAM] Speicher wird nicht automatisch wieder freigegeben Unterschied zu klassischen Variablen und Arrays (Stackvariablen) Memory-Leaks sind die Folge Lösung: Funktion free() zum Freigeben von Speicher 22

Dyn. Speicher vom Heap Speicher alloziieren und wieder freigeben: Speicher für 25 int-werte auf Heap reservieren Werte wie ein Array nutzen Speicher freigeben (optional: Zeiger nums als invalid kennzeichnen) int n = 25; int i; int *nums; nums = malloc(n * sizeof(int)); for(i = 0;i<n;++i { nums[i] = i; free(nums); nums = NULL; Stack statische Daten statischer Code Heap [~RAM] free erwartet Zeiger auf Anfang des Speicherbereichs Programmierer hat volle Verantwortung, free() auch aufzurufen Grundregel: zu jedem malloc() gehört [irgendwann] ein free() 23

Speicher vom Heap: Probleme Grundsätzliches Problem: Speicher vom Heap muss Programm verwalten zu jedem malloc() muss irgendwann ein passendes free() aufgerufen werden sonst: Memory-Leaks und Segmentation-Fault Für alle Programmiersprachen gilt: Es gibt keine triviale Lösung zur dynamischen Speicherverwaltung Probleme treten immer dann auf, wenn Speicher zu früh, gar nicht, oder mehrmals freigegeben wird Lösungsansatz: Einsatz von Zeigern und Speicher vom Heap so wenig wie möglich & so viel wie nötig. bei Funktionen Call-By-Value sicherer als Call-By-Pointer bei dynamische Arrays/Strings reichen oft auch temporäre Array-Variablen mit fester Maximallänger Stack statische Daten statischer Code Heap [~RAM] 24

Dynamischer Speicher und Zur Erinnerung: Strings = Char-Arrays = Zeiger auf das erste Element dynamische Strings können auch auf dem Heap gespeichert werden Beispiel: char tmp[2048]; printf( Wie geht s? ); fgets(tmp,2048,stdin); printf(tmp); vs char *tmp = malloc(2048*sizeof(char)); printf( Wie geht s? ); fgets(tmp,2048,stdin); printf(tmp); free(tmp); tmp ist char-array-variable Speicher im Stack automatisch gelöscht Nachteil: Stack-Speicher oft begrenzt 25 tmp ist Zeiger Speicher vom Heap mit malloc Nachteil: manuelles löschen mit free pflicht Vorteil: Heap-Speicher viel größer als Stack

Dynamischer Speicher und Strukturen Speicher alloziieren und freigeben funktioniert analog zu elementaren Typen: Speicher für 128 Kunden auf Heap reservieren Wie ein Array nutzen Speicher freigeben Gibt es in diesem Beispiel ein Problem? Problem: dynamischer Speicher und Rückgabewert: ohne free: Memory-Leak? typedef struct kunde_t { int kdnr; char name[64]; char adresse[64]; cust; cust* new_database(int n) { int i; cust *kunden; kunden = malloc(n * sizeof(cust)); for(i = 0;i<n;++i) { sprintf(kunden[i].name, Kunde %d,i); free(kunden); return kunden; mit free: Absturz des Programmes 26

Dynamischer Speicher und Rückgabewerte Frage der Zuständigkeit Wer gibt den Speicher wieder frei? Nicht trivial zu lösen. cust* create_database(int n) { int i; cust *kunden; kunden = malloc(n * sizeof(cust)); for(i = 0;i<n;++i) { sprintf(kunden[i].name, Kunde %d,i); free(kunden); return kunden; 27 typedef struct kunde_t { int kdnr; char name[64]; char adresse[64]; cust; void delete_database(cust* db) { if(db!= NULL) free(db); möglicher Lösungsansatz : Funktionspaar ähnlich malloc() und free() dynamische Speicherallokationsfunktionen mit create_**** Funktion reserviert Speicher auf Heap und gibt Datenstruktur zurück dynamische Speicherfreigabefunktionen mit delete_***** Funktion löscht Speicherreservierung für bestimmte Datenstruktur Aufrufer der create_* und delete_*-funktionen ist zuständig

Zusammenfassung: Dynamischer Speicher Programm kann dynamisch Speicher auf Heap anfordern malloc(n*sizeof(datentyp)) alloziiert Speicher für ein Array mit n Elementen sowohl elementare als auch zusammengesetzte Datentypen erlaubt free(adresse) gibt Speicher wieder frei jedem malloc() sein free() ohne free(): Memory-Leak mehr als ein free(): Programmabsturz dynamische Speicherverwaltung benötigt Zeiger Zeiger = typische Fehlerquelle Programmierer trägt volle Verantwortung für korrekten Programmcode korrektes Arbeiten mit dynamischem Speicher ist niemals trivial! sollte nur bei Alternativlosigkeit eingesetzt werden 28

Vielen Dank! Bei Fragen einfach eine Mail an: arvid@terzibaschian.de 29