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

Ähnliche Dokumente
Dynamische Speicherverwaltung

Algorithmen und Datenstrukturen

Advanced Programming in C

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

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

Einführung in die Programmierung zusammengesetzte Datentypen, dynamischer Speicher

Teil 5: Zeiger, Felder, Zeichenketten Gliederung

3. Arrays und Pointer

F Zeiger, Felder und Strukturen in C

Grundlagen der Programmiersprache C für Studierende der Naturwissenschaften

Dynamische Speicherverwaltung

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

Dynamische Speicherverwaltung

Arrays. Einleitung. Deklarieren einer Array Variablen

einlesen n > 0? Ausgabe Negative Zahl

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

Dynamisches Speichermanagement

Zeichendarstellung. Zeichen sind Zahlen (in C) Zeichen und switch

Einführung in die Programmiersprache C

Dynamischer Speicher

Arrays (Felder/Vektoren)

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

Arrays,Strings&Pointer in C/C++

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

C++ Teil 6. Sven Groß. 27. Mai Sven Groß (IGPM, RWTH Aachen) C++ Teil Mai / 14

Vorlesung Programmieren

Zeiger und dynamischer Speicher

Übungspaket 23 Mehrdimensionale Arrays

Globale Variablen Diverses. Globale Variablen. Globale Variablen

Das folgende Programm demonstriert, wie man Speicheradressen von Variablen ermittelt.

Übungspaket 23 Mehrdimensionale Arrays

Klausur. 2. Aufgabe (3 Punkte) Ergänzen Sie die leeren Zellen derart, dass sich in einer Zeile die selben Zahlenwerte ergeben.

Inhalt. 1 Einstieg in die Welt von C Erste Schritte in C 31. Vorwort... 15

C++ Notnagel. Ziel, Inhalt. Programmieren in C++

Dr. Monika Meiler. Inhalt

C-Kurs 2010 Pointer. 16. September v2.7.3

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

U3 3. Übung U3 3. Übung. Systemnahe Programmierung in C Übungen Moritz Strübe Universität Erlangen-Nürnberg Informatik 4, 2009 U3.fm

Einführung in die Programmiersprache C

2. Programmierung in C

Felder, Zeiger und Adreßrechnung

C/C++-Programmierung

U4-1 Aufgabe 3: einfache malloc-implementierung

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

Felder (1) Allgemeines

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

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

7. Organisation von Informationen

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

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

Grundlagen der Informatik 11. Zeiger

2. Aufgabe (3 Punkte) Ergänzen Sie die leeren Zellen derart, dass sich in einer Zeile die selben Zahlenwerte ergeben.

Arrays 115. array-qualifier static restrict const volatile array-size-expression assignment-expression * simple-declarator identifier

U8 7. Übung U8 7. Übung

Arrays 120. array-qualifier static restrict const volatile array-size-expression assignment-expression * simple-declarator identifier

Programmierung mit C Zeiger

Programmierung und Angewandte Mathematik

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

Zeiger, Arrays und Strings in C und C++

+ C - Array (Vektoren, Felder)

FH Ravensburg-Weingarten Schriftlich Prüfung Programmieren

Speicherverwaltung in C

C# - Einführung in die Programmiersprache Arrays, Enumeration und Collections. Leibniz Universität IT Services Anja Aue

Nachname:... Vorname:... MatrNr.:... Klausur PR2. int main() { char Text[] = "Sehr geehrte Damen und Herren!"; char *tmp=text;

Programmierkurs C++ Datenstrukturen Seite 1

Nachname:... Vorname:... MatrNr.:... Klausur PR2. Erstellen Sie eine Struktur für eine Komplexe Zahl mit den Elementen real und imag vom Typ double.

int i=1; //Integerzahl i anlegen und mit 1 initialisieren float wert; //Floatzahl deklarieren scanf( %f,&wert); //Wert über Tastatur eingeben

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

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

Praxis der Programmierung

Speicherklassen (1) Lokale Variablen

Programmieren in Java

Tag 4 Repetitorium Informatik (Java)

Grundlagen der Programmierung in C++ Arrays und Strings, Teil 1

Pointer. Variablen. Pointer. Ein elementares Beispiel. Pointer in C

5.1 Mehr Basistypen. (Wie viele Werte kann man mit n Bit darstellen?)

Auswahlen (Selektionen)

Algorithmen und Datenstrukturen

Lesen Sie alle Aufgabenstellungen sorgfältig durch, bevor Sie mit der Bearbeitung der ersten Aufgabe beginnen.

Crashkurs C++ - Teil 1

RO-Tutorien 3 / 6 / 12

9. Vektoren. (auch Felder/array)

Vektoren 105. array-qualifier static restrict const volatile array-size-expression assignment-expression * simple-declarator identifier

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

Programmieren in C/C++ und MATLAB

float *point(float a, float b); // Funktionsdeklaration Zeiger als Funktionswert // point liefert als Wert die Adresse seines Ergebnisses

JAVA BASICS. 2. Primitive Datentypen. 1. Warum Java? a) Boolean (logische Werte wahr & falsch)

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

5.4 Arrays. Oft müssen viele Werte gleichen Typs gespeichert werden. Idee: Lege sie konsekutiv ab! Greife auf einzelne Werte über ihren Index zu!

Einführung in die Programmiersprache C

C- Kurs 07 Höhere Datentypen

Zeiger: Der Adressoperator &

Einführung in die Programmierung

Programmieren in C. Eine Einführung in die Programmiersprache C. Prof. Dr. Nikolaus Wulff

Programmieren in C. Rekursive Strukturen. Prof. Dr. Nikolaus Wulff

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

Inhalt. Peter Sobe 63. Felder in C

Arrays. Theorieteil. Inhaltsverzeichnis. Begriffe. Programmieren mit Java Modul 3. 1 Modulübersicht 3

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

Transkript:

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

Speicherorganisation in C 2 von 48

Speicherorganisation Anlegen eines Arrays: double messwerte[100]; Grösse der Arrays ist fest im Programm codiert Ein Ändern der Grösse erfordert neues Kompilieren des Programms 3 von 48

Speicherorganisation Oft ist aber nicht im voraus bekannt, wie viel Daten von einem Programm verarbeitet werden Es braucht daher eine Möglichkeit, zur Laufzeit des Programmes Speicher vom Betriebssystem anzufordern Wenn der Speicher nicht mehr benötigt wird, kann er wieder freigegeben werden 4 von 48

Speicherbereiche Code Statische Daten Stack Speicher eines laufenden Programms (Prozess) Speicher für globale und statische Variablen wird im (statischen) Datenbereich alloziert Speicher für lokale Variablen wird auf dem Stack alloziert Auf dem Heap kann Speicher dynamisch alloziert werden Heap Heap 5 von 48

Statische Daten Code Statische Daten Stack Globale Variablen und static int i; void foo(void) { static int j;...... Heap 6 von 48

Stack Daten Code Statische Daten Stack Lokale Variablen und Übergabeparameter Automatischen Variablen: Beim Funktionsaufruf automatisch erzeugt und dann wieder gelöscht (Speicher freigegeben) void foo(int i) { int j;...... Heap Nach Verlassen der Funktion gehen Stack Daten verloren 7 von 48

Aufbau des Stacks Stack Variablen werden in sog "Stack Frames" organisiert Ein Stack Frame enthält: Variablen, Parameter und Rücksprungadresse www.drdobbs.com 8 von 48

Heap Daten Code Statische Daten Stack Während der Laufzeit nach Bedarf dynamisch (d.h. zur Laufzeit) alloziert (kreiert) Genau so viel Speicherplatz alloziert, wie benötigt wird Wenn man zur Entwicklungszeit nicht weiss, wie viel Speicher benötigt wird void foo(void) { int* i = (int*) malloc(sizeof(int));...... Heap Werden explizit angelegt und sind so lange gültig, bis sie (explizit) wieder freigegeben werden 9 von 48

Dynamischer Speicher in C 10 von 48

Speicher dynamisch allozieren void * malloc(int size); Alloziert Speicher der Grösse size Bytes auf dem Heap Gibt die Adresse (also einen Pointer) dieses Speicherplatz zurück (void *) Der Pointer muss noch in den gewünschten Datentyp konvertiert werden Benötigt Bibliothek stdlib.h 11 von 48

Speicher dynamisch allozieren size gibt den Speicherplatzbedarf (in Bytes) an da der Platformabhängig ist, verwendet man sizeof(<daten Typ>) malloc(sizeof(int)); malloc(siezeof(double)); Zurückgegeben wird ein void* den man zum gewünschten Typ umwandeln (casten) muss int* pi = (int*)malloc(sizeof(int)); Nach malloc() sollte man testen, ob der Rückgabewert NULL ist. wird aber eher selten wirklich gemach: "man hat ja genug Speicher". Ist dies der Fall, ist malloc() gescheitert, und das System konnte nicht mehr genügend Speicher reservieren 12 von 48

Speicher freigeben void free(void * ptr); Gibt den dynamisch zugewiesenen Speicher wieder frei Der Zeiger ptr zeigt danach auf einen nicht mehr gültigen Speicherbereich und darf nicht mehr verwendet werden 13 von 48

Beispiel 1 (einfache Variable) int *pi; pi = (int *) malloc(sizeof(int)); *pi = 5;... free(pi); /* Speicher wird freigegeben */ double *pd; pd = (double *) malloc(sizeof(double)); *pd = 5.0;... free(pd); /* Speicher wird freigegeben */ 14 von 48

Beispiel 2 (Array von int) int *pwerte; n = 250; pwerte = (int *) malloc(n * sizeof(int)); /* und so erfolgt der Zugriff: */ pwerte[95] = 12; /* oder mit Zeigernotation: */ printf("%i\n", *(pwerte+95));... free(pwerte); /* Speicher wird freigegeben */ 15 von 48

Array vergrössern Nun ist es auch kein Problem mehr, wenn sich zur Laufzeit des Programms herausstellt, dass ein Array zu klein ist Es wird dynamisch einfach ein grösseres Array angelegt Die bestehenden Werte müssen aber in das grössere Array umkopiert werden, z.b. mittels folgender Schleife newarray = (int*)malloc(newsize*sizeof(int)); for (i = 0; i < OLDSIZE; i++) { newarray[i] = oldarray[i]; Danach kann der Speicher des alten Arrays freigegeben werden free(oldarray) 16 von 48

Beispiel: statischer Array #include <stdio.h> int main (void) { int n, i, numbers[100]; printf("anzahl Zahlen: "); scanf("%d", &n); for (i = 0; i < n; i++) { printf("%d. Zahl: ", (i + 1)); scanf("%d", &numbers[i]); printf("die Zahlen sind:"); for (i = 0; i < n; i++) { printf(" %d", numbers[i]); printf("\n"); 17 von 48

Beispiel: dynamischer Array #include <stdio.h> #include <stdlib.h> int main (void) { int n, i, *numbers; printf("anzahl Zahlen: "); scanf("%d", &n); numbers = (int *) malloc(n*sizeof(int)); for (i = 0; i < n; i++) { printf("%d. Zahl: ", (i + 1)); scanf("%d", &numbers[i]); printf("die Zahlen sind:"); for (i = 0; i < n; i++) { printf(" %d", numbers[i]); printf("\n"); // eigentlich nicht mehr nötig, da Ende Programm free(numbers); 18 von 48

Struct Auch Structs können zur Laufzeit alloziert werden typedef stuct { int h,min, sec; Zeit Zeit *pzeit; pzeit = (Zeit*) malloc(sizeof(zeit)); pzeit->h = 4;... free(pzeit); /* Speicher wird freigegeben */ 19 von 48

Verkettete Strukturen (Wiederholung) mw1 mw2 pnext struct Datum { int tag; int monat; int jahr; struct Datum *pnext; ; struct Datum mw1, mw2; mw1.pnext = &mw2; /* Strukturen verketten */ 20 von 48

Verkettete Strukturen Deklaration besser/lesbarer mittels typedef für die Pointer innerhalb des Structs muss aber trotzdem die "struct" Version gearbeitet werden (weil Typ noch nicht bekannt) typedef struct Datum { int tag; int monat; int jahr; struct Datum *pnext; Datum; Nachher kann aber das Stuct einfach wiefolgt alloziert werden. Datum* pdatum = (Datum*)malloc(sizeof(Datum)); 21 von 48

"Unendlich" lange Liste von Strukturen proot pnext NULL Es wird ein Pointer auf den Anfang der Liste names "root" definiert Datum* proot = NULL; // globale Variable // neues Element erzeugen und am Anfang einfügen Datum* newandadd() { Datum* pnew = (Datum*)malloc(sizeof(Datum)); // Zeiger von pnext und neues proot setzen pnew->pnext = proot; proot = pnew; return pnew; 22 von 48

Ausgeben von Listen Diese Listen können einfach traversiert werden proot pnext pnext NULL p Datum* p = proot; while (p!= NULL) { printf("%d:%d:%d\n", p->h,p->min,p->sec); p = p -> pnext; 23 von 48

Löschen der Liste Zum löschen muss ein zweiter Zeiger (z.b. q) eingeführt werden, da sonst auf die schon freigegebene struct zugegriffen würde proot pnext pnext NULL q p Datum* p = proot; q = NULL; while (p!= NULL) { free(q); // free NULL ab c99 erlaubt sonst Test q = p; p = p -> pnext; free(q); 24 von 48

Zu früh freigegeben Der Speicher wird dann wieder verwenden (bei einem der nächsten Speicheranforderungen). Lesen (oder gar Schreiben) über einen diesen Pointer führt zu "Dangling Pointer" Fehler Trick: Nach dem free den Pointer zu NULL zu setzen (kontrollierter Absturz bei Fehlern) free(ptr); *ptr = 6; 25 von 48

Falsche Grösse angegeben Bei einem Array wird die Bereichsüberschreitung nicht überprüft int *pwerte; n = 90; pwerte = (int *) malloc(n * sizeof(int)); /* und so erfolgt der Zugriff: */ pwerte[95] = 12; Statt Grösse des Structs wird Grösse des Pointers auf das Struct angegeben Datum* pdatum = (Datum*)malloc(sizeof(Datum*)); 26 von 48

Zwei und mehrdimensionale Arrays 27 von 48

Einführung Wöchentliche Umsatzzahlen eines Geschäftes der Filialen Zürich, Bern und Basel Als Tabelle darstellen: Jede Zeile entspricht den Umsatzzahlen einer Filiale pro Woche Jede Spalte entspricht den Umsatzzahlen für einen Tag in den verschiedenen Filialen Gemeinsames Merkmal der Zahlen dieser Tabelle: Alle Einträge sind vom gleichen Datentyp. 2-Dimensionale Arrays werden häufig gebraucht für: Tabellen allgemein, Matrizenrechnung, Darstellung von Bildern, Schachbrett, Kinoreservation, etc. 28 von 48

2D Array in C 2D Array für die Umsatzzahlen Zeilen: n = 3 Spalten: m = 7 int umsatz[3][7]; 29 von 48

Deklaration und Erzeugung, Aufbau 30 von 48

Deklaration und Erzeugung von 2D Arrays Deklaration: allgemein: Datentyp Arrayname [3][7]; double umsatz[3][7]; Datentyp: Datentyp der einzelnen Elemente Statische Erzeugung des Arrays (Grösse bestimmt): Arrayname = Datentyp [AnzahlZeilen][AnzahlSpalten]; Dynamisch Erzeugung des Arrays Datentyp Arrayname feld[][7] = (datentyp*) malloc(<size>); double umsatz[][7] = (double*)malloc(3 * 7 * sizeof(double)); 31 von 48

2D Array, Konstanten Beispiel 1: Tagesumsätze einer Woche in 7 verschiedenen Filialen // Deklaration der Konstanten mit final const int ANZTAGE = 7; const int ANZFILIALEN = 3 int umsatz[anzfilialen][anztage]; Tipp: Verwenden Sie Konstanten für Arraygrössen, nicht direkt Zahlen Das Schlüsselwort "const" bei Deklarationen bezeichnet Konstanten Konvention: Konstanten werden gross geschrieben Konstanten statt Zahlenwerte, weil Bedeutung der Dimension klar 32 von 48

Zweidimensionale Arrays int buffer[2][10] = { {1,2,3,4,5,6,7,8,9,10, {11,12,13,14,15,16,17,18,19,20 ; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Das erste Element buffer[0] ist ein Array von 10 int Im Speicher sind die Zahlen aber einfach sequentiell angeordnet 33 von 48

Zweidimensionale Arrays int buffer[2][10] = { {1,2,3,4,5,6,7,8,9,10, {11,12,13,14,15,16,17,18,19,20 ; int size = ((sizeof(buffer)) / (sizeof(int))); int cols = ((sizeof(buffer[0])) / (sizeof(int))); int rows = size/cols; int row, col; for (row=0; row<rows; row++) { for (col=0; col<cols; col++) { printf("%8d",buffer[row][col]); printf("\n"); 34 von 48

Zweidimensionale Arrays #define ROWS 2 #define COLS 10... int buffer[rows][cols] = { {1,2,3,4,5,6,7,8,9,10, {11,12,13,14,15,16,17,18,19,20 ; for (row=0; row<rows; row++) { for (col=0; col<cols; col++) { printf("%8d",buffer[row][col]); printf("\n"); mittelwert = berechnemittelwert(buffer, ROWS, COLS); 35 von 48

Zweidimensionale Arrays mittelwert = berechnemittelwert (buffer, ROWS, COLS);... double berechnemittelwert (int feld[][10], int rows, int cols) { int r, c, summe=0; for(r=0; r<rows; r++) { for(c=0; c<cols; c++) { summe = summe + feld[r][c]; return (double)summe/(rows * cols); Erste Dimension wird weggelassen 36 von 48

Zweidimensionale Arrays mittelwert = berechnemittelwert (buffer, ROWS, COLS);... double berechnemittelwert (int *feld[10], int rows, int cols) { int r, c, summe=0; for(r=0; r<rows; r++) { for(c=0; c<cols; c++) { summe = summe + feld[r][c]; return (double)summe/(rows * cols); Parameter in Zeiger-Schreibweise: Zeiger auf ein Array mit 10 int 37 von 48

Zweidimensionale Arrays mittelwert = berechnemittelwert ((int *)buffer, ROWS * COLS);... double berechnemittelwert (int *feld, int anz) { int n, summe=0; for(n=0; n<anz; n++) { summe = summe + feld[n]; return (double)summe/anz; In eindimensionales Array konvertiert (type cast) 38 von 48

Initialisierung von Arrays int x[3] = { 1, 2, 3 ; Hier kann die Dimension auch weggelassen werden: int x[] = { 1, 2, 3 ; Mehrdimensionale Arrays: int a[2][3][4] = { {{ 0, 1, 2, 3, { 10, 11, 12, 13, { 20, 21, 22, 23, {{100,101,102,103, {110,111,112,113, {120,121,122,123 ; Auch hier könnte die erste Dimension weggelassen werden 39 von 48

Array von Strings int main (void) { char * pmonth[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"; int i=0; for(i=0; i < 12; i++) { printf("%s \n", pmonth[i]); // oder printf("%s \n", *(pmonth + i)); printf("\n"); 40 von 48

Unterschied? int main (void) { char pmonth[12][10] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"; int i=0; for (i=0; i < 12; i++) { printf("%s \n", pmonth[i]); // oder printf("%s \n", *(pmonth + i)); printf("\n"); 41 von 48

Beispiel: Matrixmultiplikation int main (void) { int a[3][4] = { 1, 2, 3, 4, 2, 3, 4, 6, 3, 4, 5, 8 ; int b[4][5] = { 1, 2, 3, 4, 5, 2, 3, 4, 5, 7, 3, 4, 5, 6, 9, 4, 5, 6, 7, 11 ; int c[3][5]; matrmult((int*)c, (int*)a, (int*)b, 3, 4, 5 ); printmatr((int*)c, 3, 5 ); return 0; 42 von 48

Beispiel: Matrixmultiplikation void matrmult (int c[], const int a[], const int b[], const int m, const int l, const int n) { // Zugriff auf zweidimensionale Arrays als eindimensionale // Arrays mit expliziter Index-Arithmetik int i, j, k; for (i=0; i<m; i++) for (j=0; j<n; j++) { c[i*n+j] = 0; for (k=0; k<l; k++) c[i*n+j] += a[i*l+k]*b[k*n+j]; 43 von 48

Beispiel: Matrixmultiplikation Hier wurde das zweidimensionale Array in ein eindimensionales Array umgeformt Die Indexarithmetik, also Umwandlung von a[i][j] in a[k], muss dann explizit durchgeführt werden Eine andere Variante ist es, ein Array von Pointern zu verwenden dies muss aber erst hergestellt werden 44 von 48

Beispiel: Matrixmultiplikation int main (void) { int a[3][4] = { 1, 2, 3, 4, 2, 3, 4, 6, 3, 4, 5, 8 ; int b[4][5] = { 1, 2, 3, 4, 5, 2, 3, 4, 5, 7, 3, 4, 5, 6, 9, 4, 5, 6, 7, 11 ; int c[3][5]; int *ap[3], *bp[4], *cp[3], i; for (i=0; i<3; i++) ap[i] = a[i]; for (i=0; i<4; i++) bp[i] = b[i]; for (i=0; i<3; i++) cp[i] = c[i]; matrmult2(cp, ap, bp, 3, 4, 5 ); printmatr((int*)c, 3, 5 ); return 0; 45 von 48

Beispiel: Matrixmultiplikation void matrmult2 (int **c, int **a, int **b, const int m, const int l, const int n) { // Zugriff auf zweidimensionale Arrays ueber Pointer // auf Pointer int i, j, k; for (i=0; i<kmax; i++) { for (j=0; j<mmax; j++) { c[i][j]=0; for (k=0; k<lmax; k++) c[i][j] = c[i][j] + a[i][k] * b[k][j]; 46 von 48

Dreidimensionale Arrays double c[4][5][6]; c ist ein Array mit 4 Elementen vom Typ Array mit 5 Elementen vom Typ Array mit 6 Elementen vom Typ double 47 von 48

Noch Fragen? 48 von 48