Musterlösung der Testklausur zur Vorlesung Programmieren in C Prof. Dr. Nikolaus Wulff WS/SS 2004/05 Juni 2005
1 Der Lottogewinn #define MAX_TIPS 6 typedef struct lotto_schein *LottoSchein; typedef struct lotto_liste *LottoListe; struct lotto_schein { char* name; int tip[max_tips]; ; struct lotto_liste { LottoSchein schein; LottoListe next_element; ; Abbildung 1: Die Lotto Strukturen. Die Lottoliste enthält einen Zeiger auf einen Lottoschein und einen Zeiger auf weitere Elemente vom Type Lottoliste, so dass sich mit dieser Struktur eine rekursive Lottoliste aufbauen lässt. LottoSchein createschein(char* name, int tip[]) { int i; LottoSchein schein = (LottoSchein) malloc( sizeof(struct lotto_schein)); schein->name = name; for(i=0;i<max_tips;i++) schein->tip[i] = tip[i]; return schein; Abbildung 2: Erzeugung eines Lottoscheins. Beim Erzeugen eines Lottoscheins werden der Name und die Gewinnzahlen übergeben, die in der Struktur vermerkt werden. Das Hinzufügen eines Lottoscheins in die Tipliste geschieht entweder durch Einfügen des neuen Scheins am Anfang der Kette, wie in Lösung (3) es war nicht verlangt, dass die Einfügereihenfolge erhalten bleibt oder aber indem der neue Schein am Ende der Liste angehängt wird, wie im Beispiel (4). Diese Variante erhält die Einfügereihenfolge. SS 2005 Musterlösung Programmieren in C 1
LottoListe addschein(lottoliste liste, LottoSchein schein) { LottoListe neu = (LottoListe) malloc( sizeof(struct lotto_liste)); neu->next_element = liste; neu->schein = schein; return neu; Abbildung 3: Einfügen eines Lottoscheins am Anfang der Liste. LottoListe lastelement(lottoliste list) { while(list->next_element) { list = list->next_element; return list; LottoListe addschein(lottoliste liste, LottoSchein schein) { LottoListe ende, neu = (LottoListe) malloc( sizeof(struct lotto_liste)); neu->next_element = NULL; neu->schein = schein; if (liste == NULL) { liste = neu; else { ende = lastelement(liste); ende->next_element = neu; return liste; Abbildung 4: Einfügen eines Lottoscheins am Ende der Liste. SS 2005 Musterlösung Programmieren in C 2
2 Teile und Herrsche Wie im Tip zur Aufgabe angegeben gibt es zwei prinzipielle Lösungsmöglichkeiten, entweder inkrementell wie in Lösung (5) oder rekursiv wie in (6). typedef double (*Function)(double x); /* Function Pointer */ #define dabs(x) ( (x)<0? -(x):(x)) /* abs Makro */ double bisection(function f, double a, double b, double eps) { double x,fx; assert(f(a)*f(b)<0); do { x = (a+b)/2; fx = f(x); if (f(a)*fx < 0) b = x; else a = x; while (dabs(fx) >= eps); return x; Abbildung 5: Inkrementelles Bisektionsverfahren mit do-while Schleife. double bisection(function f, double a, double b, double eps) { double x,fx; assert(f(a)*f(b)<0); x = (a+b)/2; fx = f(x); if (dabs(fx) < eps) return x; else if (f(a)*fx < 0) return bisection(f,a,x,eps); else return bisection(f,x,b,eps); Abbildung 6: Rekursives Bisektionsverfahren. SS 2005 Musterlösung Programmieren in C 3
3 ZickZack /** Vorwaertsdeklarationen */ double F(double ); double G(double ); /** Implementierung von G */ double G(double x) { if (x>0) { return F(x-1); else { return F(x+1); /** Implementierung von F */ double F(double x) { if(0 <= x && x <1) { return x; else { return F(G(x)); Abbildung 7: Implementierung der Funktionen f und g. 1-2 -1 0 1 2 Abbildung 8: Graph der Funktion f(x). Die Implementierung (7) der Funktionen f und g ergibt sich direkt aus den angegebenen Definitionsgleichungen. f(x) beschreibt eine Sägezahnfunktion der Periode τ = 1 auf R. Dies legt die folgende optimierte Lösung nahe: double F(double x) { return x - (long) x; SS 2005 Musterlösung Programmieren in C 4
4 Geheimschrift /* Makro Definition XOR */ #define XOR ^ void encrypt(char *phrase, FILE *input, FILE *output) { int c, i, l = strlen(phrase); i = 0; while(!feof(input)) { c = fgetc(input); c = c XOR phrase[++i%l]; fputc(c,output); Abbildung 9: Implementierung des Verschlüsselungsalgorithmus. In einer Schleife wird der Eingabestrom Zeichen für Zeichen eingelesen und decodiert. Der fehlende XOR Operator wurde per #define XOR ^ definiert und dann verwendet. Anstatt des XOR Makros kann natürlich auch direkt der Ausdruck c = c ^ phrase[++i%l]; oder auch noch kürzer der ^= Operator per c ^= phrase[++i%l]; codiert werden. SS 2005 Musterlösung Programmieren in C 5
5 Die Suche im Heuhaufen #define MAXLINE 120 void grep(char *needle, int len, char *names[]) { FILE *fp; char line[maxline]; int count; while(--len >=0) { fp = fopen(names[len],"rt"); count=0; while(fgets(line,maxline,fp)!= 0) { count++; if (strstr(line,needle)!= NULL ) { printf("%s %3d: %s",names[len],count,line); fclose(fp); Abbildung 10: Implementierung der grep Routine. In einer Schleife werden zu allen übergebenen Dateinamen FILE Pointer im lesenden Textmodus geöffnet, Zeile für Zeile durchsucht und anschließend wieder geschlossen. Wird der gesuchte Ausdruck gefunden erfolgt eine Ausgabe des Dateinamen, der Zeilennummer und der betreffenden Zeile. Früher lange ist das her hatten Textdateien maximal 80 Zeichen pro Zeile. Diese Implementierung geht daher davon aus, dass ein festes Zeichenfeld von 120 chars als Puffer für die fgets Routine ausreicht. Ansonsten ist die #define MAXLINE 120 Anweisung entsprechend zu modifizieren. SS 2005 Musterlösung Programmieren in C 6