Teil 5: Felder, Zeiger, Zeigerarithmetik Gliederung Felder (Arrays) Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Felder 5.2
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Felder (Arrays) Verbundtypen variable Anzahl von Elementen eines Datentyps sequenzielle Ablage im Speicher ein- oder mehrdimensional Anwendung: Vektoren, Matrizen, Tabellen, Zeichenketten (Strings) Definition datentyp bezeichner[anzahl]; 5.3
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Beispiele char s; /* 1 Zeichen */ char sf[20]; /* 20 Zeichen */ int i; /* 1 ganze Zahl */ int iff[100]; /* 100 ganze Zahlen (= 400 Bytes bei 32 Bit) */ double f; /* 1 Fließkommazahl */ double ff[100]; /* 100 Fließkommazahlen (= 800 Bytes) */ 5.4
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Beispielanwendung /* Feld mit der Summe der natuerlichen Zahlen bis zu diesem Feldelement belegen */ #define MAX 100 int sum[max], i, j = 0; int main() { for (i = 0; i < MAX; i++) { j = j + i + 1; sum[i] = j; } return 0; } 5.5
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Besonderheiten von Feldern Anzahl der Elemente muss eine Konstante sein: int feld[10]; Variable Feldgrenzen sind ab C99 für lokale Variablen möglich: { int x = 7;... int feld[x];... } Zugriff über Index, gültiger Bereich 0 bis anzahl-1: feld[0] = 123;... feld[9] = 456; feld[10] = 789; 5.6
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Initialisierung von Feldern Initialisierung: int felda[4] = {0}; // Auto-Initialisierung // setzt alle Elemente auf 0 int feldb[4] = {0, 1, 3, 5}; // Voll-Initialisierung int feldc[] = {0, 1, 3, 5}; // Compiler zählt selbst Vergleiche zwischen Arrays if (feld1 == feld2) sind nicht möglich! Zuweisungen der Form feld2 = feld1; sind ebenfalls nicht möglich! Lösung: 1) elementweise vergleichen/kopieren oder 2) gesamten Speicherbereich kopieren 5.7
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Speicherabbild int i, alpha[5]; alpha[0] int alpha[1] int alpha[2] int alpha[3] int alpha[4] int 1 2 3 4 5????? for (i = 0; i < 5; i++) alpha[i] = i * i; alpha[0] int alpha[1] int alpha[2] int alpha[3] int alpha[4] int 1 2 3 4 5 0 1 4 9 16 5.8
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Arbeiten mit Feldern Beispiel: Elemente des Arrays alpha ausgeben: int i; for (i = 0; i < 5; i++) { printf ("%d\n", alpha[i]); } Beispiel: Mittelwert aller Werte des Arrays berechnen 5.9
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Felder als Parameter void Ausgabe(int[], int); int main() { int i; int einfeld[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; } Ausgabe(einFeld, 10); return 0; void Ausgabe(int f[], int laenge) { int i; } for (i = 0; i < laenge; i++) printf("%d\n", f[i]); 5.12
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik call by reference void erhoeheumeins(int feld[], int laenge) { int i; } for (i = 0; i < laenge; i++) feld[i] = feld[i] + 1; int main() { int einfeld[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; Ausgabe(einFeld, 10); erhoeheumeins(einfeld, 10); Ausgabe(einFeld, 10); } return 0; 5.13
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Strings Arrays vom Typ char[] Null-Terminierung durch '\0'-Byte Initialisierung: char wochentag[] = "Samstag"; ist gleichbedeutend mit oder auch char wochentag[] = {'S','a','m','s','t','a','g','\0'}; char wochentag[8]; wochentag[0] = 'S'; wochentag[1] = 'a';... wochentag[7] = '\0'; 5.14
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Bibliotheksfunktionen in <string.h> Länge eines Strings ermitteln a = strlen(s1); // ergibt Länge, ohne '\0'-Byte String kopieren strcpy(ziel_string, quell_string); String an einen anderen String anhängen strcat(ziel_string, quell_string); Strings vergleichen int a; a = strcmp(s1, s2) -1 wenn s1 < s 0 wenn s1 == s2 1 wenn s1 > s2 5.15
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Mehrdimensionale Felder 5.16
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Mehrdimensionale Felder int alpha[3][4]; a lp h a [ 0 ] a lp h a [ 1 ] a lp h a [ 2 ] Spaltenindex Zeilenindex [0][0] [0][1] [0][2] [0][3] [1][0] [1][1] [1][2] [1][3] [2][0] [2][1] [2][2] [2][3] Allgemein kann ein n-dimensionales Array als ein eindimensionales Array, dessen Komponenten (n-1)-dimensionale Arrays sind, interpretiert werden. 5.17
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Initialisierung int alpha[3][4] = { }; {1, 3, 5, 7}, {2, 4, 6, 8}, {3, 5, 7, 9}, 1 3 5 7 2 4 6 8 3 5 7 9 5.18
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Felder (mehrdimensional) als Parameter void AusgabeMatrix( ); int main() { int i; int matrix[3][4] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; } AusgabeMatrix( matrix, 3); return 0; void AusgabeMatrix( int matrix[][4], int zeilen ) { int i, j; for ( i = 0; i < zeilen; i++ ) for ( j = 0; j < 4; j++) printf("%d ", matrix[i][j]; } 5.19
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Fallbeispiel: Matrizenmultiplikation Problemstellung: Programm zur Berechnung des Produkts zweier Matrizen Voraussetzung: A Spaltenzahl = B Zeilenzahl c a b 5.20
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik #define MAX 10 int main() { int za, sa, zb, sb; float A[MAX][MAX], B[MAX][MAX], C[MAX][MAX]; printf("\nmatrix a einlesen: \n"); printf("zahl der Zeilen : "); scanf("%d", &za); printf("zahl der Spalten: "); scanf("%d", &sa); mat_lesen(a, za, sa); printf("\nmatrix b einlesen: \n"); printf("zahl der Zeilen : "); scanf("%d", &zb); printf("zahl der Spalten: "); scanf("%d", &sb); mat_lesen(b, zb, sb); mat_mult(a, B,... ); printf("\ndie Ergebnismatrix c lautet: \n\n"); mat_drucken(c, za, sb); } return 0; 5.21
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Zeiger und Adressen 5.22
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Funktion mit mehreren Rückgabewerten? Problem: Eine Funktion swap(...) soll die Inhalte 2er Variablen vertauschen. Wie kann dieses Problem gelöst werden? int x = 1, y = 2; // tausche x und y... 5.23
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Funktion mit mehreren Rückgabewerten? Problem: Eine Funktion swap(...) soll die Inhalte 2er Variablen vertauschen. Wie kann dieses Problem gelöst werden? int x = 1, y = 2; // tausche x und y... int temp; temp = x; x = y; y = temp; 5.24
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Variablenmodell Speicheradresse Arbeitsspeicher Bezeichner Kodierung Wert Datentyp Dekodierung 5.25
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Typ-Klassifikation 5.26
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Was ist ein Zeiger? Ein Zeiger (Pointer) ist eine Variable, welche die Adresse einer im Speicher befindlichen Variablen oder Funktion aufnehmen kann. Damit verweist eine Zeigervariable mit ihrem Variablenwert auf die jeweilige Adresse. 5.27
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Deklaration / Definition eins Zeigers Zeiger sind typgebunden int *pi; // Zeiger auf int double *pd; // Zeiger auf double 5.29
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Referenzieren und Dereferenzieren Referenzieren: Adressoperator & liefert Adresse eines Objekts Dereferenzieren: Dereferenzierungsoperator * liefert Inhalt an der Adresse Referenzieren mit & Objekt Adresse des Objekts Dereferenzieren mit * Referenzieren pointer = &x int-variable x pointer enthält die Adresse von x Dereferenzieren *pointer = 5; heißt: das Objekt, auf das der Pointer pointer zeigt, erhält den Wert 5. 5.30
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Adresszuweisung an einen Zeiger I 2 5.31
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Adresszuweisung an einen Zeiger II... pointer1 = &alpha pointer2 = pointer1... Objekt alpha Objekt alpha pointer1 pointer2? Vor der Zuweisung pointer2 = pointer1 enthält pointer2 irgendeine Adresse pointer1 pointer2 Nach der Zuweisung pointer2 = pointer1 zeigen beide Pointer auf dasselbe Objekt alpha 5.32
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Beispiel 1: Zeigeroperationen Speicherzelle 1024 Nummer 1024 x y p int x, y, *p; x = -7;??? 1024 1028 1156 1024 1028 1156 p = &x; 1024 1028 1156 y = *p; 1024 1028 1156 5.33
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Beispiel 2: Zeigeroperationen Was ist an den folgenden Anweisungen a bis e falsch? float x, y, *p; a) *p = 3.14159; b) p = &3.14159; c) *x = 5.4; d) x = &y; e) p = *y; 5.37
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Funktion mit mehreren Rückgabewerten? Problem: Eine Funktion swap(...) soll die Inhalte 2er Variablen vertauschen. Wie kann dieses Problem gelöst werden? void swap( ) { } // TODO: Do the magic here! int main() { int x = 1, y = 2; // tausche die Inhalte von x und y swap( ); } return 0; 5.38
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Warum Zeiger? call by reference mehrere Rückgabewerte bei Funktionsaufrufen Beschleunigung von Funktionsaufrufen (warum?) erlauben direkte Speicher-Manipulationen dynamisch Speicher anfordern / freigeben Umgang mit Arrays und Strings Nachteil: hohe Gefahr von Fehlern 5.40
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Zeigerarithmetik 5.42
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Dualität von Zeigern und Feldern I Bezeichner eines Arrays referenziert (wie ein Zeiger) eine Adresse: Ein Zugriff wird vom Compiler als a[i] *(a + i) behandelt. Elemente eines Arrays können über Zeiger referenziert werden: Beispiel: int a[10]; int *pa; pa = a; 5.43
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Dualität von Zeigern und Feldern II als Funktionsparameter werden Arrays und Zeiger äquivalent behandelt: void strcopy(char destination[], const char source[]); void strcopy(char *destination, const char *source); sei a ein beliebiges Feld, dann ist a[i] &a[i] identisch zu *(a+i) identisch zu a+i sei pa eine beliebige Zeigervariable, dann ist pa[i] identisch zu *(pa+i) &pa[i] identisch zu pa+i 5.44
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Zeigerarithmetik Fall 1: Zeiger +/- int-wert -> Zeiger long feld[5] long *zeiger; zeiger = feld; zeiger++; zeiger += 3; *zeiger = 123; 5.45
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Zeigerarithmetik Fall 1: Zeiger +/- int-wert -> Zeiger long feld[5] long *zeiger; zeiger = feld; // Zeiger verweist auf Feld-Anfang zeiger++; // Zeiger verweist nun auf 2. Element zeiger += 3; // Zeiger verweist nun auf 5. Element *zeiger = 123; // ist identisch mit feld[4] = 123; 5.46
Felder Mehrdimensionale Felder Zeiger und Adressen Zeigerarithmetik Zeigerarithmetik Fall 1: Zeiger +/- int-wert -> Zeiger long feld[5] long *zeiger; zeiger = feld; // Zeiger verweist auf Feld-Anfang zeiger++; // Zeiger verweist nun auf 2. Element zeiger += 3; // Zeiger verweist nun auf 5. Element *zeiger = 123; // ist identisch mit feld[4] = 123; Fall 2: Zeiger +/- Zeiger -> int-wert int strlen(char zeichenkette[]) { char *anf, *end;... } 5.47