Wintersemester 2025/26 (2)
Wintersemester 2025/26, zweiter Termin. 9 ECTS: alle Aufgaben, 180 Minuten, 120 Punkte. 6 ECTS: nur A1 bis A6, 120 Minuten, 80 Punkte.
A1: Grundlagen (19 Punkte)
A1a (4 Punkte)
In der Programmierung und im Umgang mit Computersystemen begegnen Sie verschiedenen Zahlensystemen, Datenformaten und Werkzeugen.
0x2A?make hello aus. Es gibt keine Fehler. Wie führen Sie die erzeugte Datei aus?A1b (5 Punkte)
Identifizieren Sie in folgendem C-Programmcode jeweils ein passendes Beispiel für jeden der aufgelisteten Begriffe. Geben Sie das exakte Zeichen oder die Zeichenfolge aus dem Code an, nicht die Zeilennummer. Falls für einen Begriff kein Beispiel im Programm vorhanden ist, tragen Sie FEHLT ein.
#include <stdio.h>
#include <string.h>
typedef struct {
char name[50];
int punkte;
} Spieler;
int main(void)
{
Spieler s;
strcpy(s.name, "Alice");
s.punkte = 42;
printf("Name: %s, Punkte: %d\n", s.name, s.punkte);
return 0;
}A1c (6 Punkte)
Betrachten Sie folgenden C-Codeausschnitt:
int summe = 0;
for (int i = 1; i <= 10; i++)
{
if (i % 3 == 0)
{
continue;
}
summe += i;
}summe nach Ausführung des Codes?i werden nicht zur Summe addiert? (Komma- oder leerzeichengetrennte Liste von Zahlen)Nennen Sie die Linux-Kommandozeilenbefehle mit Parametern (sofern erforderlich) für folgende Aufgaben.
A1d (4 Punkte)
Analysieren Sie folgendes C-Programm:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *datei = fopen("daten.csv", "r");
if (datei == NULL)
{
return 1;
}
char zeile[256];
fgets(zeile, 256, datei);
while (fgets(zeile, 256, datei) != NULL)
{
zeile[strlen(zeile) - 1] = '\0';
int k = 0;
while (zeile[k] != ',' && zeile[k] != '\0')
{
k++;
}
zeile[k] = '\0';
int wert = atoi(&zeile[k + 1]);
if (wert > 100)
{
printf("%s: %d\n", zeile, wert);
}
}
fclose(datei);
return 0;
}A2: Grundlagen der C-Programmierung (12 Punkte)
A2a (4 Punkte)
Analysieren Sie folgenden Ausschnitt aus einem C-Programm. Die Funktion run soll die Werte zweier Integer-Variablen vertauschen. Gehen Sie davon aus, dass im Ausschnitt fehlende, jedoch benötigte #include-Zeilen und Funktionsprototypen vorhanden sind.
int main(void)
{
int x = 10;
int y = 25;
run(&x, &y);
printf("x = %d, y = %d\n", x, y);
return 0;
}
void run(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}Schreiben Sie nun eine Funktion run2, die drei Werte zyklisch rotiert. Nach dem Aufruf run2(&x, &y, &z) mit x=1, y=2, z=3 soll gelten: x=3, y=1, z=2.
void run2(int *a, int *b, int *c)
{
___
}run2 (4 Zeilen, ohne geschweifte Klammern):A2b (3 Punkte)
Das folgende Programm soll einen String zeichenweise rückwärts ausgeben, enthält aber drei Fehler:
#include <stdio.h>
#include <string.h>
void reverse_print(char text)
{
int len = strlen(text);
for (int i = len; i >= 0; i--)
{
printf("%c", text[i]);
}
printf("\n");
}
int main(void)
{
char *wort = "Hallo"
reverse_print(wort);
return 0;
}A2c (5 Punkte)
Das folgende Programm soll das Maximum in einem Integer-Array sowie dessen Index im Array ausgeben.
Erwartete Ausgabe:
Maximum: 42
Position: 3#include <stdio.h>
int main(void)
{
int werte[] = {17, 8, 23, 42, 5, 31};
int max = <1>;
int pos = 0;
for (int i = <2>; i < 6; i++)
{
if (werte[i] <3> max)
{
max = <4>;
pos = i;
}
}
printf("Maximum: %d\n", max);
printf("Position: <5>\n", pos);
return 0;
}A3: Pizza-Preisvergleich (15 Punkte)
Die Pizzeria Ihrer Wahl bietet Pizza in zwei unterschiedlichen Varianten an: runde Pizzen werden über ihren Durchmesser angegeben, rechteckige Party-Pizzen haben eine feste Größe von 60 × 40 cm. Doch welche Variante bietet mehr Pizza fürs Geld?
Sie schreiben ein Programm, das diese Frage beantwortet. Das Programm soll drei Kommandozeilenparameter haben:
- Den Durchmesser der runden Pizza (in cm)
- Den Preis der runden Pizza (in Euro)
- Den Preis der Party-Pizza (in Euro)
Die Dateien für diese Aufgabe finden Sie im Verzeichnis exam-files/pizza in Ihrem Home-Verzeichnis. Für diese Aufgabe steht Ihnen check50 zur Verfügung. Um check50 zu verwenden, führen Sie folgenden Befehl in dem Verzeichnis aus, in dem sich die Datei pizza.c befindet:
check50 checks/pizza
Zuvor sollten Sie Ihr Programm kompilieren.
A3a (5 Punkte)
Vervollständigen Sie das Programm pizza.c. Prüfen Sie die Eingaben des Nutzers:
- Gibt der Nutzer nicht genau drei Kommandozeilenparameter an, geben Sie aus:
Usage: ./pizza <durchmesser> <preis_rund> <preis_party> - Wandeln Sie die drei Parameter in Fließkommazahlen um.
- Wenn einer der Werte nicht positiv ist (also ≤ 0), geben Sie aus:
Alle Werte muessen positiv sein
Fügen Sie jeweils ein Newline-Escapezeichen hinzu. Falls einer der zwei Fehler ausgegeben wird, soll das Programm mit Rückgabewert 1 beendet werden.
Hinweis: Wenn Sie nicht wissen, wie Fließkommazahlen eingelesen werden, können Sie Teilpunkte erhalten, wenn Sie die Parameter als Ganzzahlen einlesen.
A3b (5 Punkte)
Erweitern Sie Ihr Programm pizza.c um folgende Funktionalität:
- Definieren Sie vor der
main-Funktion einen struct-TypPizzamit folgenden Feldern:name(char *)preis(float)flaeche(float)preis_pro_cm2(float)
- Erstellen Sie in
maineine Variable vom TypPizzafür die runde Pizza. Setzen Sie den Namen auf"Runde Pizza"und den Preis auf den entsprechenden Kommandozeilenparameter. Berechnen Sie die Fläche. - Erstellen Sie eine zweite
Pizza-Variable für die Party Pizza (60 × 40 cm). Setzen Sie den Namen auf"Party Pizza"und den Preis auf den entsprechenden Kommandozeilenparameter. Berechnen Sie die Fläche.
Hinweis: Falls Sie A3a nicht lösen konnten, verwenden Sie folgende fest kodierte Werte: Durchmesser 28.0, Preis runde Pizza 8.99, Preis Party-Pizza 12.99. Die check50-Tests werden dann fehlschlagen, aber es sind Teilpunkte möglich, wenn Sie ab hier korrekt weiterarbeiten.
Hinweis: Falls Sie die Formel für die Kreisfläche nicht kennen, nehmen Sie ersatzweise eine quadratische Fläche mit einer Kantenlänge an, die dem Durchmesser entspricht.
A3c (5 Punkte)
Erweitern Sie Ihr Programm pizza.c um die Ausgabe und den Preisvergleich:
Berechnen Sie den Preis pro cm² für beide Pizzen und speichern Sie das Ergebnis im jeweiligen Struct-Feld
preis_pro_cm2.Geben Sie für beide Pizzen die Informationen in folgendem Format aus:
Runde Pizza: 8.99 Euro, 615.75 cm2, 0.0146 Euro/cm2 Party Pizza: 12.99 Euro, 2400.00 cm2, 0.0054 Euro/cm2Verwenden Sie den Formatstring:
"%s: %.2f Euro, %.2f cm2, %.4f Euro/cm2\n"Vergleichen Sie die Preise pro cm² und geben Sie aus, welche Pizza günstiger ist. Bei Gleichstand geben Sie die Party Pizza aus.
Die Party Pizza ist guenstiger pro cm2.Verwenden Sie den Formatstring:
"Die %s ist guenstiger pro cm2.\n"
Hinweis: Falls Sie A3b nicht lösen konnten, lösen Sie diese Aufgabe ersatzweise ohne Struct – verwenden Sie stattdessen einzelne Variablen für die Werte. Teilpunkte sind möglich, wenn Sie ab hier korrekt weiterarbeiten.
A4: PGM Bilddatei (13 Punkte)
Das PGM-Format (Portable Graymap) ist ein sehr einfaches Bildformat. Es speichert Graustufenbilder und wurde in den 1980er Jahren als Teil der Netpbm-Bibliothek entwickelt. In der Variante P5 (binär) besteht eine PGM-Datei aus einem kurzen Text-Header, gefolgt von den Pixeldaten als Binärdaten.
Der Header einer P5-PGM-Datei ist folgendermaßen aufgebaut:
P5
Breite Höhe
Maximalwert
[Pixeldaten: Breite x Höhe Bytes]Jedes Pixel wird als ein Byte (0–255) gespeichert, wobei 0 für Schwarz und 255 für Weiß steht. Die Pixeldaten sind zeilenweise von oben nach unten angeordnet.
Die Dateien für diese Aufgabe finden Sie im Verzeichnis exam-files/pgm in Ihrem Home-Verzeichnis. Der Datentyp Pixel ist in der Quelldatei bereits definiert als:typedef unsigned char Pixel;
Das Öffnen der Datei und Einlesen des Headers ist ebenfalls bereits im Code vorhanden.
A4a (7 Punkte)
Vervollständigen Sie das Programm pgm.c, um die Bilddatei bild.pgm einzulesen und zu analysieren.
Ergänzen Sie den vorhandenen Code, sodass das Programm:
- Speicher für die Pixeldaten mit
mallocreserviert (Breite × Höhe Bytes). - Die Pixeldaten mit
freadeinliest. - Die durchschnittliche Helligkeit aller Pixel berechnet und als Fließkommazahl mit zwei Nachkommastellen ausgibt. Achten Sie darauf, dass die Division als Fließkommadivision ausgeführt wird, z.B. indem Sie einen der Operanden zu float casten.
Die Ausgabe soll folgendem Format entsprechen:
Breite: 120
Hoehe: 160
Durchschnittliche Helligkeit: 127.50Ein Kommilitone schlägt vor, statt malloc einfach ein lokales Array zu verwenden:Pixel pixel[breite * hoehe];
A4b (6 Punkte)
Beim Betrachten der Datei bild.pgm in einem Bildbetrachter fällt auf, dass das Bild wie ein Fotonegativ aussieht und zusätzlich um 180° gedreht ist.
Erweitern Sie Ihr Programm pgm.c so, dass es ein neues Bild ergebnis.pgm erzeugt, das zwei Aktionen durchführt:
- Invertierung: Jeder Pixelwert p wird durch
maximalwert - persetzt. - 180°-Drehung: Die Reihenfolge aller Pixel wird umgekehrt (das erste Pixel wird zum letzten und umgekehrt).
Die neue Datei muss eine gültige P5-PGM-Datei sein. Schreiben Sie also zunächst den Header (mit fprintf) und anschließend die bearbeiteten Pixeldaten. Vergessen Sie nicht, den reservierten Speicher mit free freizugeben und alle geöffneten Dateien zu schließen.
Öffnen Sie die erzeugte Datei ergebnis.pgm anschließend in einem Bildbetrachter durch Doppelklick auf die Datei.
Hinweis: Falls Sie A4a nicht vollständig lösen konnten, schreiben Sie den Code für Invertierung und Drehung so, als ob die Pixeldaten bereits in einem Array pixel eingelesen wären.
A5: Datenstrukturen und Algorithmen (14 Punkte)
A5a (3 Punkte)
Ein Array mit n Elementen ist bereits vollständig sortiert. Sie haben die Wahl zwischen drei Sortieralgorithmen (wie in der Vorlesung gezeigt): Bubble Sort, Selection Sort und Merge Sort.
Welcher der drei Algorithmen ist in diesem Fall am schnellsten? Begründen Sie Ihre Antwort und erklären Sie, warum die anderen beiden Algorithmen langsamer sind.
A5b (6 Punkte)
Eine Hash-Tabelle der Größe 5 (Indizes 0-4) verwendet folgende Hash-Funktion:
int hash(char *key)
{
return strlen(key) % 5;
}Kollisionen werden durch Verkettung (Chaining) aufgelöst, d.h. an jedem Index hängt eine verkettete Liste. Neue Elemente werden jeweils am Anfang der Liste eingefügt.
Die folgenden Schlüssel werden in dieser Reihenfolge eingefügt (ohne Anführungszeichen): "cat", "do", "int", "for", "float", "if", "char"
0: …
1: …
2: … etc.
Beispielformat:
hund=hamster=hase katze=katerA5c (5 Punkte)
Das folgende Programm baut eine einfach verkettete Liste aus den Werten 1, 2, 3 auf und gibt anschließend alle Elemente aus. Vervollständigen Sie die vier Lücken (1) bis (4) so, dass sich ein korrektes und ausführbares Programm ergibt, also mit dem jeweils fehlenden C-Code.
Erwartete Ausgabe:
3
2
1#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int val;
struct node *next;
} node;
int main(void)
{
int werte[] = {1, 2, 3};
node *head = NULL;
for (int i = 0; i < 3; i++)
{
node *n = malloc(<1>);
n->val = werte[i];
n->next = <2>;
<3> = n;
}
node *curr = head;
while (curr != NULL)
{
printf("%d\n", curr->val);
curr = <4>;
}
return 0;
}A6: Zeiger und Datenstrukturen (7 Punkte)
A6a (4 Punkte)
Betrachten Sie folgenden C-Code:
int a = 5;
int b = 10;
int *p = &a;
int *q = &b;
*p = *q + 3;
q = p;
*q = *q + 1;Füllen Sie die folgende Tabelle mit den Werten nach Ausführung aller drei Anweisungen aus. Verwenden Sie für die Werte, die in den Pointern p und q gespeichert sind, &a oder &b.
a = ___
b = ___
*p = ___
*q = ___
p = ___
q = ___A6b (3 Punkte)
Eine Programmiererin hat versucht, eine Funktion zum Einfügen eines neuen Elements am Anfang einer einfach verketteten Liste zu implementieren. Die Implementierung enthält jedoch einen Fehler, sodass die Liste nach dem Funktionsaufruf unverändert bleibt.
#include <stdlib.h>
typedef struct sllnode {
int value;
struct sllnode *next;
} sllnode;
void prepend(sllnode *head, int value) {
sllnode *new_node = malloc(sizeof(sllnode));
new_node->value = value;
new_node->next = head;
head = new_node;
}sllnode**) verwenden. Fügen Sie den Code der korrigierten Funktion prepend hier ein:B1: Python und OOP (20 Punkte)
B1a (4 Punkte)
In Sheep World, einer fiktiven Welt, in der Schafe fliegen können, besitzt jedes Schaf eine bestimmte Menge Flugenergie. Fliegen kostet Energie. Wenn die Energie aufgebraucht ist, landet das Schaf auf dem Rücken. Erst ein beherzter Schubs (flip) dreht es wieder um und setzt seine Energie auf den übergebenen Wert.
Die Klasse FlyingSheep (Datei flying_sheep.py im Verzeichnis exam-files/sheep_world) dient als Vorlage für fliegende Schafe. Der Code unten zeigt die Datei mit zwei Lücken. Füllen Sie diese aus.
class FlyingSheep:
def __init__(self, name, color, energy):
self.name = name
self.color = color
self.energy = energy
self.on_back = False
def __str__(self):
if self.on_back:
return f"{self.name} liegt auf dem Rücken (Energie: {self.energy})"
return f"{self.name} ({self.color}, Energie: {self.energy})"
___Lücke_1___
def flip(self, energy):
if not self.on_back:
return None
self.on_back = False
self.energy = energy
___Lücke_2___Lücke 1 ist eine Methode fly(self, distance). Wenn das Schaf bereits auf dem Rücken liegt oder distance größer als die Energie des Schafs ist, soll die Methode einen ValueError auslösen. Andernfalls wird die Energie des Schafs um distance reduziert. Wenn die Energie danach 0 ist, landet das Schaf auf dem Rücken. Die Methode gibt distance zurück.
fly(self, distance):In Lücke 2 erstellen Sie ein Objekt mit den folgenden Attributwerten. Geben Sie das Objekt aus, rufen Sie darauf fly(42) auf, geben Sie es erneut aus, rufen Sie dann darauf flip(10) auf und geben Sie es ein letztes Mal aus:
name = "Dolly"
color = "pink"
energy = 42Die Ausgabe soll so aussehen:
Dolly (pink, Energie: 42)
Dolly liegt auf dem Rücken (Energie: 0)
Dolly (pink, Energie: 10)B1b (6 Punkte)
Erstellen Sie nun eine Klasse Squadron (Datei squadron.py im Verzeichnis exam-files/sheep_world), die einen Schwarm fliegender Schafe verwaltet. Der Code unten zeigt die Klasse mit drei Lücken. Füllen Sie diese aus.
- Lücke 1 enthält den Konstruktor (
__init__). Dieser nimmt einen Parametername(Name des Schwarms) entgegen, speichert ihn inself.nameund erstellt zusätzlich eine leere Listeself.sheep. - Lücke 2 enthält eine Methode
add(self, sheep), die ein FlyingSheep-Objekt zur Liste hinzufügt. - Lücke 3 enthält eine Methode
fly_all(self). Alle Schafe sollen zu einem Ziel fliegen, das 50 Einheiten entfernt ist. Für jedes Schaf, das mindestens 50 Energie hat, und nicht auf dem Rücken liegt, wirdfly(50)aufgerufen. Die Methode gibt die Anzahl der Schafe zurück, die am Ziel angekommen sind.
class Squadron:
___Lücke_1___
___Lücke_2___
___Lücke_3_____init__ (Lücke 1):add(self, sheep) (Lücke 2):fly_all(self) (Lücke 3):B1c (4 Punkte)
Betrachten Sie folgende Methode für die Klasse Squadron, die alle startklaren Schafe zurückgibt (also alle, die nicht auf dem Rücken liegen):
def get_ready(self):
result = []
for sheep in self.sheep:
if not sheep.on_back:
result.append(sheep)
return resultSchreiben Sie eine äquivalente Version von get_ready, die statt der for-Schleife eine List Comprehension verwendet.
get_ready mit List Comprehension:Schreiben Sie eine Methode sort_by_energy(self) für die Klasse Squadron, die eine nach energy sortierte neue Liste aller Schafe zurückgibt.
sort_by_energy(self):B1d (6 Punkte)
Betrachten Sie die folgenden pytest-Testfunktionen für die Klasse FlyingSheep. Beantworten Sie die Fragen nur durch Lesen des Codes, ohne ihn auszuführen. Gehen Sie davon aus, dass die Klasse FlyingSheep wie in B1a beschrieben funktioniert.
Hinweis: pytest ist auf den Klausurrechnern nicht installiert. Ein Test gilt als bestanden, wenn die Testfunktion ohne Fehler durchläuft und alle assert-Statements wahr sind.
Test 1:
def test_str():
s = FlyingSheep("Bella", "pink", 50)
assert str(s) == "Bella (pink, 50)"Test 2:
def test_double_fly():
s = FlyingSheep("Bella", "pink", 50)
s.fly(50)
result = s.fly(10)
assert result == 10Test 3:
def test_flip_and_fly():
s = FlyingSheep("Bella", "pink", 25)
s.fly(25)
s.flip(10)
result = s.fly(5)
assert result == 5B2: 7-Segment-Anzeige und Web-Technologien (20 Punkte)
Im Verzeichnis exam-files/segments finden Sie die Datei segments.html. Diese enthält eine 7-Segment-Anzeige. Dabei handelt es sich um eine Anzeige, wie sie z.B. in Digitaluhren und Taschenrechnern verwendet wird. Öffnen Sie die Datei in einem Browser, um das Layout zu sehen.
Die Anzeige besteht aus sieben Segmenten, die mit den Buchstaben a bis g bezeichnet sind. Jedes Segment ist als <div>-Element mit einer eigenen CSS-Klasse realisiert (z.B. class="segment a").
— a —
| |
f b
| |
— g —
| |
e c
| |
— d —Für jede Ziffer müssen bestimmte Segmente leuchten (sichtbar) und andere aus sein (unsichtbar).
B2a (3 Punkte)
Im JavaScript-Code von segments.html finden Sie das Array SEGMENTE. Für jede Ziffer (0-9) enthält es ein Array mit 7 Einträgen: 1 bedeutet, dass das Segment leuchtet, 0 bedeutet, dass das Segment nicht aktiv ist. Die Reihenfolge ist a, b, c, d, e, f, g.
Die Einträge für die Ziffern 0 bis 6 sind bereits im Source Code angegeben. Leiten Sie die Werte für die Ziffern 7, 8 und 9 selbst aus dem Segmentdiagramm ab und vervollständigen Sie das Array.
B2b (4 Punkte)
Schreiben Sie die JavaScript-Funktion zeigeZiffer(ziffer). Die Funktion soll die Anzeige so schalten, dass die übergebene Ziffer dargestellt wird.
Gehen Sie dabei wie folgt vor:
- Lesen Sie aus dem Array
SEGMENTEdas passende Array für die übergebene Ziffer. - Gehen Sie in einer Schleife alle 7 Segmente durch (Index 0 bis 6).
- Ermitteln Sie den Namen des Segments über das Array
NAMEN(z.B.NAMEN[0]ergibt"a"). - Suchen Sie das HTML-Element mit
document.querySelector(".anzeige ." + name). - Setzen Sie
element.style.visibilityauf"visible", wenn das Segment leuchten soll (Wert 1), oder auf"hidden", wenn es aus sein soll (Wert 0).
zeigeZiffer(ziffer) hier ein:B2c (5 Punkte)
Die Buttons 0-9 in segments.html rufen bereits zeigeZiffer() auf. Erweitern Sie nun die HTML-Datei, sodass der Nutzer eine Ziffer auch über ein Eingabefeld eingeben kann:
- Fügen Sie unterhalb der Buttons ein
<input>-Element vom Typnumberhinzu (mitid="eingabe",min="0",max="9"). - Fügen Sie einen Button mit dem Text Anzeigen hinzu.
- Schreiben Sie eine JavaScript-Funktion
zeigeEingabe(), die:- den Wert aus dem Eingabefeld liest (mit
document.querySelector("#eingabe").value) - den Wert in eine Ganzzahl umwandelt (mit
Number(...)) - die Funktion
zeigeZiffer()mit diesem Wert aufruft
- den Wert aus dem Eingabefeld liest (mit
- Verknüpfen Sie den Button mit der Funktion, sodass ein Klick
zeigeEingabe()aufruft.
zeigeEingabe() ein:B2d (4 Punkte)
Beantworten Sie folgende Fragen zu HTTP und Formularen:
200?404?GET und POST.B2e (4 Punkte)
Beantworten Sie folgende Fragen zu DNS und Browser-Werkzeugen:
Diese Seite als Markdown: ansehen herunterladen