370 likes | 509 Views
Einführung in die Programmiersprache C 4.Tag Institut für Mathematische Optimierung - Technische Universität Braunschweig. Zeiger bei Matrizen. Es kann nötig sein, eine Matrix zu kopieren, um bei Veränderungen noch auf die Originaldaten zurückgreifen zu können. Das geht nicht so:
E N D
Einführung in die Programmiersprache C4.TagInstitut für Mathematische Optimierung -Technische Universität Braunschweig
Zeiger bei Matrizen Es kann nötig sein, eine Matrix zu kopieren, um bei Veränderungen noch auf die Originaldaten zurückgreifen zu können. Das geht nicht so: double **mat,**copy; ... copy=mat; Hier werden nicht die Inhalte der Matrix kopiert, sondern nur der Zeiger auf den Beginn des Speicherbereichs. Veränderungen von Einträgen von mat führen auch zur Veränderung der Einträge von copy. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Zeiger bei Matrizen Institut für Mathematische Optimierung – Technische Universität Braunschweig
Andere Operationen Sollen hingegen zwei Matrizen oder Zeilen von Matrizen getauscht werden, so können auch nur die Zeiger getauscht werden: double **mat; **copy, **temp1, *temp2; ... temp1 = mat; mat = copy; copy = temp1; ... temp2 = mat[17]; mat[17] = mat[43]; mat[43] = temp2;
Lösung Die Inhalte müssen elementweise kopiert werden. Dabei müssen die Matrixdimensionen jeweils gleich sein und Speicher für beide Matrizen besorgt werden: double **mat, **copy; mat=alloc_matrix(zeilen,spalten); copy=alloc_matrix(zeilen,spalten); for... for... copy[i][j]=mat[i][j]; Institut für Mathematische Optimierung – Technische Universität Braunschweig
Speicher für Matrizen freigeben Der für Matrizen besorgte Speicher muss iterativ wieder freigegeben werden: voidfreeintmatrix(int **matrix, intzeile) { int i; for(i=0;i<zeile;i++) free(matrix[i]); free(matrix); } Institut für Mathematische Optimierung – Technische Universität Braunschweig
Aufgabe Schreiben Sie zwei Funktionen, die dynamisch Speicher reservieren und diesen zurückgeben. Eine Funktion soll dabei Speicher für ein eindimensionales Feld (array) freigeben und die andere Speicher für ein mehrdimensionales Feld (Typ Matrix). Implementieren Sie außerdem eine Funktion, die den für mehrdimensionale Felder besorgten Speicher wieder freigibt. Überlegen Sie hierbei welche Parameter Sie den Funktionen übergeben müssen. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Zeigerarithmetik Eine weitere Möglichkeit mit Zeigern zu arbeiten ist die Zeigerarithmetik. Zur Verdeutlichung hier ein kleines Beispiel. Bei dem Feld: inta[]={1,2,3}; zeigt a auf a[0] und a+1 zeigt auf a[1]. Statt scanf(" %d",&a[1]); kann man also scanf(" %d",a+1); schreiben, um den zweiten Wert des arrays zu ändern. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Zeigerarithmetik Konsequenterweise gibt es auch a++, ++a, a-- und --a. Die Anweisungen: int*p; int a[]={1,2,3,4}; for (p=a; *p != 4; p++) printf(" %d", *p); sind äquivalent zu: inti; int a[]={1,2,3,4}; for (i=0; a[i] != 4; i++) printf(" %d", a[i]); Institut für Mathematische Optimierung – Technische Universität Braunschweig
Zeigerarithmetik bei Matrizen Bei Matrizen sieht das noch etwas komplizierter aus: double **mat; mat=alloc_matrix(2,2); mat[0][0]=1.0; mat[0][1]=2.0; mat[1][0]=3.0; mat[1][1]=4.0; Institut für Mathematische Optimierung – Technische Universität Braunschweig
Zeigerarithmetik bei Matrizen printf("mat[0][0] = %f\n",mat[0][0]); printf("mat[1][1] = %f\n",mat[1][1]); printf("**mat = %f\n",**mat); printf("*(*mat+1) = %f\n",*(*mat+1)); printf("*(*(mat+1) ) = %f\n",*(*(mat+1))); printf("*(*(mat+1)+1) = %f\n",*(*(mat+1)+1)); Institut für Mathematische Optimierung – Technische Universität Braunschweig
Aufgabe Schreiben Sie eine 3x3 Matrix sukzessive mit den Werten 1,2,3,… voll. D.h. Zeile 1 enthält die Einträge 1,2,3, Zeile 2 die Einträge 4,5,6 und Zeile 3 die Einträge 7,8,9. Geben Sie darauf per Zeigerarithmetik die komplette Matrix am Bildschirm aus. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Strukturen Objekte verschiedenen Datentyps können zu einem neuen Datentyp kombiniert werden. Beispiel: structstudent { char[100] vorname; char[100] nachname; intmatrikelnummer; char[100] studienfach; }; Definiert den Datentyp structstudent. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Aufbau einer Struktur struct Name { Deklaration1; Deklaration2; ... DeklarationN; }; Institut für Mathematische Optimierung – Technische Universität Braunschweig
Zugriff auf Strukturelemente /* Definition von "Koordinaten": */ struct Koordinaten { double x; double y; double z; }; /* Deklaration einer Variable dieses Typs: */ struct Koordinaten p; p.x=3.0; p.y=p.x; /* Zugriff auf die Elemente: */ p.z=0; Institut für Mathematische Optimierung – Technische Universität Braunschweig
Zuweisungen und Vergleiche Man kann Strukturen als Ganzes zuweisen, aber Vergleiche sind nicht als Ganzes erlaubt. struct Koordinaten p1, p2; p1 = p2; /* Zuweisung */ if (p1==p2) ... /* <-- Fehler */ Die if-Bedingung ist in dieser Form nicht erlaubt, sondern es müssten alle Komponenten der Struktur gesondert auf Gleichheit überprüft werden. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Strukturen und Zeiger Eine Struktur darf sich nicht selbst als Element enthalten, aber sie darf einen Zeiger auf eine Variable vom Typ der eigenen Struktur enthalten. structknoten { int wert; struct knoten *naechster; }; Die Struktur knoten enthält einen Zeiger auf eine Struktur vom Typ knoten. Darüberhinaus können in jeder Struktur andere Strukturen verwendet werden. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Zugriff auf Strukturzeigerinhalte Auf die einzelnen Datenelemente einer Struktur zuzugreifen, deren Adresse man durch eine Zeigervariable kennt, kann auf verschiedene Arten geschehen: struct knoten *p; (*p).wert=0; /* 1. Art */ p[0].wert=0; /* 2. Art */ p->wert=0; /* 3. Art */ Institut für Mathematische Optimierung – Technische Universität Braunschweig
Strukturen als Parameter Strukturen können als Parameter verwendet werden: struct knoten { int wert; struct knoten *naechster; }; void ausgabewert(struct knoten p) { printf("%i\n",p.wert); } Dabei werden sie als Kopie übergeben (call-by-value). Institut für Mathematische Optimierung – Technische Universität Braunschweig
Besser … struct knoten *p; p->wert=0; // p[0].wert=0; oder (*p).wert=0; ausgabewert(p); … void ausgabewert(struct knoten *p) { printf("%i\n",p->wert); } Verwendung von einem Zeiger (call-by-reference). Institut für Mathematische Optimierung – Technische Universität Braunschweig
Strukturen als Rückgabewert Strukturen können auch als Rückgabewert verwendet werden: struct knoten { int wert; struct knoten *naechster; }; struct knoten generate() { struct knoten result; ... returnresult; } Institut für Mathematische Optimierung – Technische Universität Braunschweig
Eigene Datentypen Mit dem Schlüsselwort typedef kann man Datentypen mit einem eigenen Namen versehen. Mit: structknoten_s { int wert; structknoten_s *naechster; }; typedefstructknoten_s knoten; kann man eine Variable vom Typ structknoten_s jetzt durch knoten p; deklarieren und das mitunter lästige struct weglassen. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Verkürzte Schreibweise • Verkürzte Schreibweise durch Kombination der Deklarationen: typedefstructknoten_s { int wert; structknoten_s *naechster; } knoten; • Andere Anwendungsbeispiele für typedef: typedefunsignedintuint; typedef double real; /* typedeffloat real; */ (leichter Wechsel zwischen float und double) Institut für Mathematische Optimierung – Technische Universität Braunschweig
Einfach verkettete Listen Mit Hilfe von Strukturen lassen sich Listen erzeugen. Jedes Element (Knoten) der Liste hat einen Zeiger auf seinen Nachfolger. Das erste Element wird Kopf genannt, das letzte Element hat NULL als Nachfolger: Institut für Mathematische Optimierung – Technische Universität Braunschweig
Elemente einfügen Um ein neues Element nach einem Listenelement einzufügen, müssen die Nachfolgezeiger geändert werden: Institut für Mathematische Optimierung – Technische Universität Braunschweig
Elemente einfügen Die Anweisungen dazu sind: knoten *kopf, *vorgaenger, *neuer_knoten; neuer_knoten->naechster=vorgaenger->naechster; vorgaenger->naechster=neuer_knoten; Institut für Mathematische Optimierung – Technische Universität Braunschweig
Elemente am Kopf einfügen Folgende Anweisungen hängen ein neues Element am Kopf an die Liste an: knoten *kopf, *neuer_knoten; neuer_knoten->naechster = kopf; kopf = neuer_knoten; Institut für Mathematische Optimierung – Technische Universität Braunschweig
Elemente entfernen Beim Entfernen eines Elementes muss wiederum der Zeiger des Vorgängerelementes geändert werden. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Elemente entfernen Die Anweisungen dazu sind: knoten *kopf, *vorgaenger, *zu_loeschen; vorgaenger->naechster = zu_loeschen->naechster; free(zu_loeschen); oder beim Entfernen des ersten Elements: kopf = zu_loeschen->naechster; free(zu_loeschen); Institut für Mathematische Optimierung – Technische Universität Braunschweig
Durchlaufen einer Liste Listen können z.B. mittels For-Schleife durchlaufen werden: knoten *p; intmax_wert; ... max_wert = head->wert; for (p=head; p!=NULL; p=p->naechster) { if (p->wert > max_wert) max_wert = p->wert; } Institut für Mathematische Optimierung – Technische Universität Braunschweig
Rekursion Ruft eine Funktion sich selbst auf, so wird das Rekursion genannt. Diese muss immer eine Abbruchbedingung haben. Beispiel: #include <stdio.h> voidprintnumbers(int a) { printf("%d ",a); if (a > 0) printnumbers(a-1); } intmain() { printnumbers(10); return 0; }
Schlechtes Beispiel für eine Rekursion Berechnung der Fakultät einer Zahl: unsignedintfakultaet(unsignedint); intmain() { printf("%u\n",fakultaet(5)); return 0; } Institut für Mathematische Optimierung – Technische Universität Braunschweig
Schlechtes Beispiel für eine Rekursion unsigned int fakultaet(unsigned int n) { if(n>0) return n*fakultaet(n-1); /* n!=n*(n-1)!*/ else return 1; /* 0!=1 */ } Institut für Mathematische Optimierung – Technische Universität Braunschweig
Besser: Iterative Lösung intmain() { int n=5,i,fakultaet=1; for(i=2;i<=n;i++) fakultaet*=i; /* fakultaet=fakultaet*i; */ printf("%d\n",fakultaet); return 0; } Institut für Mathematische Optimierung – Technische Universität Braunschweig
Bäume Analog zu Listen lassen sich auch baumartige Daten- strukturen erzeugen: Institut für Mathematische Optimierung – Technische Universität Braunschweig
Traversierung von Bäumen Sollen alle Knoten eines Baumes abgearbeitet werden, wird oft Rekursion verwendet. Beispiel: double maxwert; // globale Variable void traverse(knoten* r) { if (r->wert > maxwert) maxwert = r->wert; if (r->rechts!=NULL) traverse(r->rechts); if (r->links!=NULL) traverse(r->links); }
Nochmal ohne globale Variable int traverse(knoten* r) { double h; double maxwert; maxwert = r->wert; if (r->rechts!=NULL) { h = traverse(r->rechts); if (h > maxwert) h = maxwert; } if (r->links!=NULL) { h = traverse(r->links); if (h > maxwert) h = maxwert; } }