Algorithmen und Datenstrukturen Funktionen in C a sin( ) float a = sin(alpha); M. Herpers, Y. Jung, P. Klingebiel 1
Lernziele Formatierte Ein- und Ausgabe (vertieft) Verwendung von Funktionen in C kennen und anwenden können (inklusive Makros und Inline- Funktionen) Komplexe Parameter wie Felder, Strings und selbst definierte Datentypen kennen 2
Formatierte Ausgabe printf() Formatstring, Platzhalter, Variablenliste Typen von Platzhaltern %c char oder int (0 bis 255) %d int mit Vorzeichen %ld wie d, aber für long %i wie %d %u unsigned int %o int oder unsigned int als Oktalzahl %x int oder unsigned int als Hexadezimalzahl %f float oder double im Festkommaformat %e, %E wie %f nur im Exponentialformat long lu, lx, lf, und g, G kompaktes Exponentialformat 3
Zahlen konvertieren int main() { int wert=200; Hinweis: Der Variableninhalt ändert sich nicht! } printf("dezimale Darstellung printf("oktale Darstellung printf("hexadezimale Darstellung printf("ascii Darstellung return 0; : %d\n", wert); : %o\n", wert); : %x\n", wert); : %c\n", wert); 4
Weitere Umwandlungen Feldbreite %10d zehn Ziffern %010d zehn Ziffern mit führenden Nullen %-10d zehn Ziffern linksbündig Anzahl Nachkommastellen z.b.: %.2f 5
Steuerzeichen \a alert, akustisches Warnsignal \b backspace, setzt Cursor um eine Position nach links \t tab (horizontal) \n new line, Cursor geht zum Anfang der nächsten Zeile \, \ Gibt das Zeichen bzw. aus \? Gibt das Zeichen? aus \\ Gibt das Zeichen \ aus \0 Ende eines Strings \ddd Ausgabe eines oktalen Wertes \xhh Ausgabe eines hexadezimalen Wertes 6
Probleme mit scanf() Tastaturpuffer wird nicht immer gelöscht (systemabhängig) /*Formatiertes Einlesen*/ char a,b,c; Löscht den Tastaturpuffer printf("erstes Zeichen: "); scanf("%c",&a); fflush(stdin); printf("zweites Zeichen: "); scanf("%c",&b); fflush(stdin); printf("drittes Zeichen: "); scanf("%c",&c); fflush(stdin); printf("liste der Zeichen: %c %c %c\n", a,b,c); /*falls das immer noch Probleme macht: fflush() durch getchar() ersetzen */ 7
Definition und Deklaration Beispiel Definition: int func(int a, int b) { return (a + b) * (a + b); } Beispiel Deklaration: int func(int, int); oder: int func(int a, int b); 8
Definition und Deklaration Reihenfolge von Deklaration, Definition und Aufruf wichtig Funktion wird vor erstem Aufruf definiert Oder sie wird als Funktionsprototyp vorher deklariert (sog. forward declaration ) und später, also nach main(), definiert Funktionen können nicht geschachtelt werden, d.h. sie liegen alle auf gleicher Ebene Rekursive Funktionsaufrufe möglich 9
Definition und Deklaration Zuerst deklariert: void hilfe(void); int main(void) { hilfe(); return 0; } void hilfe(void) { bevorzugt printf("hilfsfunktion\n"); } Zuerst definiert: void hilfe(void) { printf("hilfsfunktion\n"); } int main(void) { hilfe(); return 0; } Quelle: C von A bis Z, open book, galileo 10
Die main() Funktion Hauptfunktion main() ist wie folgt definiert: (und kommt genau einmal im Programm vor) Zähler für Argumente (argv) Parameter als C-String interpretiert (Feld mit Zeigern auf C-Strings) int main(int argc, char *argv[]) { return 0; // kann nach C99 entfallen } Auch: int main(void) Hauptprogramm 11
Unterprogramme bzw. Funktionen Typischer Ablauf eines C-Programms main 12
Funktionen vs. Prozeduren Funktionen Liefern Rückgabewert Z.B. float, int, char Können deshalb in Ausdrücken stehen Prozeduren Kein Rückgabewert void Beim Aufruf behandelt wie Anweisung 13
Makros und Konstanten Direktive #define für symbolische Konstanten und Makros Ersetzen von Zeichenketten #define WERT 100 #define MAX(a,b) ((a)>(b)?(a):(b)) Liefert Maximum beider Argumente Taucht MAX(3,4) irgendwo auf, wird dies durch Präprozessor ersetzt (ist keine echte Funktion) Tradition: Großbuchstaben für symbolische Konstanten und Makros 14
Inline-Funktionen in C Zeitersparnis durch Vermeiden des Unterprogrammaufrufs Compiler muss Schlüsselwort inline nicht beachten, wenn kein Optimierungsbedarf festgestellt wird (z.b. bei Debug-Build) Stattdessen wird Code des UPs direkt eingesetzt Dadurch entfällt Sprunganweisung in Funktion und wieder zurück Unterprogramm wirkt wie Makro Mit Sicherheit statischer Typprüfung wie bei Funktionen Beispiel: inline void swap(float *p1, float *p2) { } float tmp = *p1; *p1 = *p2; *p2 = tmp; 15
Felder (Arrays), Strings, ADTs KOMPLEXE DATENFELDER 16
Felder (Arrays) Halten Elemente gleichen Typs Länge und Anzahl der Dimensionen wird bei Variablendeklaration in eckigen Klammern angegeben und an Bezeichner gehängt Länge muss konstanter Ausdruck sein Bsp. 1: char farbe[10]; Variable farbe enthält (konstante) Anfangsadresse des Feldes Felder sind Adresskonstanten Bsp. 2: int brett[8][8]; Wird Feld direkt initialisiert, muss äußerste Dimension nicht angegeben werden, da vom Compiler berechenbar 17
Felder - Speicher <ArrayType> arrayname[ numelements ] Array-Elemente liegen hintereinander im Speicher Der Name zeigt auf das erste Element Der Index des Arrays entspricht der Adresse auf das erste Element plus dem Index * Speicherwortlänge Wenn ein Array verwendet wird, muss die Größe zur Compilezeit festliegen myarray[5] myarray[4] myarray[3] myarray[2] myarray[1] myarray[0] 18
Felder - Initialisierung Felder in C haben feste Dimension; Längenangabe muss konstant sein Initialisierung: int x[] = { 1, 2, 3, 4 }; int m[2][3] = { {11, 12, 13}, {21, 22, 23} }; char t[] = { 'H', 'e', 'l', 'l', 'o', '\0' }; char s[] = "Hello"; Indizes gehen bei Länge n von 0 bis n-1 Überschreiten der Feldgrenzen kann zum Crash führen 19
Beispiel Datenerfassung Für sieben Tage soll die Höchsttemperatur in einem Array gespeichert werden. Zwei Funktionen: Einlesen der Temperaturen Abfrage nach Temperatur von Tag x (1 x 7) Nutzen Sie ein globales Array (vor main() deklariert) 20
Felder als Funktionsparameter <ReturnType> funcname( ArrayType arrname[ ] ) int sumofarray(int values[], int numvalues) Beim Aufruf wird nur der Array-Name verwendet (Call-by-reference) Warum werden Felder nicht als Kopie übergeben? 21
Beispiel Datenerfassung Verändern Sie das Programm der Temperaturerfassung. Definieren Sie das Array float tag[7] in main(). Was müssen Sie noch anpassen? 22
ZEICHENKETTEN IN C 23
Zeichenketten Zeichenketten (bzw. Strings) sind in C char-arrays (sog. C-Strings ) C kennt keine speziellen Operationen auf Zeichenketten Es gibt nur Operationen auf einzelnen Zeichen (bzw. Arrays von Zeichen) Zeichenketten werden in der Regel mit Bibliotheksfunktionen bearbeitet: #include <string.h> 24
Strings Ein String in C ist ein Array von Characters char mystring[20]; Strings werden terminiert mit Character '\0' mystring[0] = 'H'; mystring[1] = 'i'; mystring[2] = '\0'; printf("%s", mystring); Was wird hier ausgegeben? Einen String einlesen mit fgets(string, Zeichenlaenge, Quelle) 25
Beispiel Direkte Ansprache: das Programm fragt zuerst nach Vorname und Nachname und begrüßt dann mit Hallo <Vorname> <Nachname> (zuerst ohne string.h). 26
Zeichenketten Bibliotheksfunktionen Zahlreiche Bibliotheksfunktionen in <string.h>, z.b.: char* strcpy(s,ct) char* strcat(s,ct) int strcmp(cs,ct) size_t strlen(cs) Kopiert Zeichenkette aus ct in s, liefert Zeiger auf s hängt Zeichenkette aus ct an s an, liefert Zeiger auf s Vergleicht Zeichenkette in cs mit Zeichenkette in ct, liefert < 0, wenn cs kleiner ist, 0, wenn beide gleich, sonst > 0 Liefert Länge von cs ohne \0 s hat den Typ char*, cs und ct den Typ const char* (werden nicht geändert) 27
Mit Strings arbeiten Konkatenation (Hintereinanderhängen von Strings): quell_string wird an ziel_string angehängt: strcat(ziel_string, quell_string); 28
Beispiel Direkte Ansprache: das Programm fragt zuerst nach Vorname und Nachname und begrüßt dann mit Hallo <Vorname> <Nachname> (hier mit string.h und strcat()) 29
Zeichenketten Beispiele für strcmp() bzw. strncmp() strcmp("a", "A") ist 0 strcmp("a", "B") ist -1 strcmp("b", "A") ist 1 Auf 4 erste Zeichen beschränkt: strncmp("fassade", "Fass", 4) ist 0 Achtung: strcmp("z", "a") liefert -1, da ASCII-Werte verglichen werden (genaue Rückgabewerte compilerabhängig) Stringlänge ermitteln mit strlen() char str[8] = "Hello"; Was gibt strlen(str) zurück? 5, 6 oder 8??? 30
Anwendungsspezifische Datenstrukturen Abstrakter Datentyp (ADT) Bsp.: ADT für Vektoren mit Operationen Erinnerung: Vektoren sind n-dimensional (z.b. n = 2), alle Komponenten (z.b. Ԧv = x y ) haben gleichen Typ #define NDIM 2 typedef float Vektor[NDIM]; void einlesen(vektor v) {...} void add(vektor erg, Vektor a, Vektor b) { for (int i=0; i<ndim; i++) erg[i] = a[i] + b[i]; } 31
Anwendungsspezifische Datentypen Datentypen mit verschiedenen Basistypen werden als Strukturen (struct) definiert struct Strukturtyp{ Datentyp1; Datentyp2; Datentyp3; }; Aufruf einzelner Elemente mit Punktoperator 32
Beispiel: Patientendaten #include <stdio.h> #include <string.h> struct patient{ long pnummer; char pname[80]; int alter; int geschlecht; }; Eine Variable vom Typ patient! int main() { Achtung: Direkte Zuweisung ist nicht möglich struct patient p1; p1.pnummer = 124; strcpy(p1.pname, "Hartmut Huang"); p1.alter = 24; p1.geschlecht = 1; // 1 - weiblich, 2 - maennlich return 0; } 33
Beispiel Patientendaten (siehe oben) int count =0; Ein Array vom Typ patient! int main() { struct patient pdatenbank[100]; pdatenbank[count].pnummer= 124; strcpy(pdatenbank[count].pname, "Hartmut Huang"); pdatenbank[count].alter = 24; pdatenbank[count].geschlecht = 1; // 1 - weiblich, 2 - maennlich return 0; } 34
Abstrakter Datentyp Erlaubt Beschreibung von Datenstrukturen unabhängig von Implementierung in konkreter Programmiersprache ADT heißt abstrakt, da zunächst keine konkrete Implementierung angeben wird Spezifiziert gespeicherte Daten mit Operationen auf diesen Daten Gespeicherte Datensätze heißen auch Elemente des abstrakten Datentyps Bei Implementierung muss man sich entscheiden, wie Daten intern gespeichert werden Art der internen Datenspeicherung eines ADTs hat maßgeblichen Einfluss auf Laufzeit und Speicherverbrauch 35
Lernziele Formatierte Ein- und Ausgabe (vertieft) Verwendung von Funktionen in C kennen und anwenden können (inklusive Makros und Inline- Funktionen) Komplexe Parameter wie Felder und selbst definierte Datentypen kennen 36