140 likes | 249 Views
Felder, Zeichenketten, Pointer. Felder. Allgemeine Deklaration: <Elementtyp> <Name>[dim1][dim2]...[dimn] <Elementtyp> : Type des Feldelements <Name> : Name des Feldes <dimi> : Anzahl der Feldelement in der i-ten Dimension Indizes laufen von 0 bis dimi-1 (wie in JAVA)
E N D
Felder, Zeichenketten, Pointer EDV1 - 06FelderPointer
Felder • Allgemeine Deklaration:<Elementtyp> <Name>[dim1][dim2]...[dimn] • <Elementtyp> : Type des Feldelements • <Name> : Name des Feldes • <dimi> : Anzahl der Feldelement in der i-ten Dimension • Indizes laufen von 0 bis dimi-1 (wie in JAVA) • Aufruf eines Feldelements : name[i1]...[in] (wie in JAVA) • Speicherung der Feldelemente zeilenweise ohne Unterbrechung • Unterschiede zu JAVA • Mehrdimensionale Felder sind keine Felder von Feldern. Es gibt also echte mehrdimensionale Felder. • Felder wissen nicht wie groß sie sind. Man muss sich die Länge eines Feldes also merken. EDV1 - 06FelderPointer
Beispiel für Felder • Monatsmitteltemperatur float temperatur[31]; float monatsmittel=0; int i; for (i=0;i<31;i++) monatsmittel+=temperatur[i]; monatsmittel/=31; • Jahresmitteltemperaturen float temperatur[12][31]; int tage[12]={31,28,31,30,31,30,31,31,30,31,30,31}; float jahresmittel=0.0; int t, m; for(m=0;m<12;m++) for(t=0;t<tage[m];t++) jahresmittel+=temperatur[m][t]; jahresmittel/=365; EDV1 - 06FelderPointer
Zeichenketten • Es gibt keinen extra Typ für Zeichenketten. • Zeichenketten sind Felder von char-Elementen. • Das Ende einer Zeichenkette wird durch das Zeichen '\0' gekennzeichnet. Die Länge des Feldes muss also immer um eins größer sein als die längste zu speichernde Zeichenkette. • Achtung: Alle Zeichenkettenfunktionen arbeiten immer bis zum nächsten 0-Zeichen. • Z.B.: Zeichenkette der maximalen Länge 26.char zeichenkette[27];zeichenkette="Das ist eine Zeichenkette."; • Es existieren diverse Funktionen für die Manipulation von Zeichenketten. Z.B:strcasecmp, strcat, strchr, strcmp, strcpy, strlen, strstr EDV1 - 06FelderPointer
Pointer • Für die Nutzung von dynamischen und flexiblen Datenstrukturen sind Pointer erforderlich. Pointer enthalten nicht den Wert einer Variablen sondern deren Adresse. • Die Länge von Pointern ist systemabhängig. • Pointer sind typgebunden, d.h. sie zeigen immer auf Variablen eines bestimmten Typs. • Allgemeine Form der Vereinbarung:<typ> *<name>; • <typ> ist der Typ auf den der Pointer <name> zeigt • "<typ> *" ist der Typ der Variablen <name> • Mit dem Operator "&" wird die Adresse einer Variablen berechnet. • Mit dem Operator "*" wird der Pointer dereferenziert, d.h. man erhält die Variable auf die der Pointer zeigt. • "*" und "&" sind inverse Operatoren, d.h. *&name == &*name == name EDV1 - 06FelderPointer
Beispiel: int j=77; int *i; i=&j; *i=88; • Wirkung: Variable j wird definiert bekommt den Wert 77 Variable i wird definiert als Pointer auf int i wird die Adresse von j zugewiesen j wird der Wert 88 zugewiesen EDV1 - 06FelderPointer
Beispiel int main() { int j=77; int *i; i=&j; printf("j = %i; i = %u; &i = %u; *i = %i\n",j,i,&i,*i); *i=88; printf("j = %i; i = %u; &i = %u; *i = %i\n",j,i,&i,*i); } Ausgabe: j = 77; i = 3221223940; &i = 3221223936; *i = 77; j = 88; i = 3221223940; &i = 3221223936; *i = 88; EDV1 - 06FelderPointer
Parameterübergabe • Wesentliche Anwendung von Pointern bei der Übergabe von Parametern. • Standardmäßig werden Parameter immer „by value“ übergeben, d.h. kopiert. • Ausweg:Die Prozedur erwartet Pointer auf die eigentlichen Parameter und beim Aufruf werden die Adressen der Parameter übergeben. • Beispiel: void set(int *i) { *i=77; } int main() { int k; set(&k); } EDV1 - 06FelderPointer
Beispiel void tausch(int *i, int *j) { int h=*i; *i=*j; *j=h; } int main() { int i=111, j=222; printf("i = %i; j = %i\n,i,j); tausch(&i, &j); printf("i = %i; j = %i\n,i,j); } Ausgabe: i = 111; j = 222; i = 222; j = 111; EDV1 - 06FelderPointer
Rechnen mit Pointern • Mit Pointern kann gerechnet werden. • Mögliche Operationen: +, -, ++, -- • Dabei wird immer um Längeneinheiten der Elementtypen verändert. D.h. dass der Pointer nach der Operation wieder auf ein Adresse zeigt, die ein Element vom gleichen Elementtyp enthält. • Beispiel: int i; int *p = &i; int *q = p++; q==p+sizeof(int) EDV1 - 06FelderPointer
Pointer und Felder • Die Feldvariable stellt einen Zeiger auf das erste Feldelement dar. D.h. für <Elementtyp> <name>[dim1][dim2]...[dimn] gilt: • <name>==&<name>[0][0]...[0] • *<name>==<name>[0][0]...[0] • Jahresmitteltemperaturen float temperatur[12][31]; float *tt; int tage[12]={31,28,31,30,31,30,31,31,30,31,30,31}; float jahresmittel=0.0; int t, m; for(m=0;m<12;m++) { tt=&temperatur[m][0]; for(t=0;t<tage[m];t++) jahresmittel+=*tt++; } jahresmittel/=365; EDV1 - 06FelderPointer
Dynamische Speicherverwaltung • Wenn bei der Programmierung noch nicht klar ist wie viel Speicher in einem Programm benötigt wird, muss der Speicher dynamisch verwaltet werden. • Dazu existieren folgende Funktionen: • void malloc(int AnzahlBytes) : reserviert AnzahlBytes Speicher in Bytes • void calloc(int AnzahlElement,int ElementLaenge) : reserviert AnzahlElement* ElementLaenge in Bytes • void realloc(void AlteAdresse,int AnzahlElement) : vergrößert den reservierten Speicherbereich auf AnzahlElement und kopiert die alten Daten in das neue Feld • free(void Adresse) : gibt den Speicherbereich wieder frei • Falls bei malloc, calloc oder realloc nicht genügend Speicher frei war, wird NULL als Wert ausgegeben. • Um die Pointer typgerecht zuzuweisen muss der Aufruf von malloc, calloc oder realloc „gecastet“ werden. Z.B.:intfeld = (int *)calloc(1000,sizeof(int)); EDV1 - 06FelderPointer
Beispiel int *feld1; float *feld2; feld1 = (int *)malloc(1000*sizeof(int)); if (feld1 == NULL) { printf("feld1 konnte nicht allociert werden!"); exit(1); } feld2 = (float *)malloc(1000,sizeof(float)); if (feld2 == NULL) { printf("feld2 konnte nicht allociert werden!"); exit(1); } EDV1 - 06FelderPointer
feld2 = (float *)realloc(feld2,2000); if (feld2 == NULL) { printf("feld2 konnte nicht vergroessert werden!"); exit(1); } free(feld1); free(feld2); EDV1 - 06FelderPointer