Wintersemester 2025/26
Wintersemester 2025/26. 9 ECTS: alle Aufgaben, 180 Minuten, 120 Punkte. 6 ECTS: nur A1 bis A6, 120 Minuten, 80 Punkte.
A1: Grundlagen (17 Punkte)
A1a (3 Punkte)
In der Programmierung und im Umgang mit Computersystemen begegnen Sie verschiedenen Dateiformaten, Zahlensystemen und Werkzeugen.
make kompiliert. Es gab keine Fehler. Sie führen das Programm durch Eingabe von calc.c im Terminal aus. Es wird ein Fehler ausgegeben. Was müssen Sie im Terminal stattdessen eingeben, um das Programm auszuführen?A1b (4 Punkte)
Identifizieren Sie in folgendem C-Programmcode jeweils das am besten passende 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>
int main(void)
{
int anzahl = 10;
float preis = 12.99;
char kategorie = 'A';
printf("Artikel: %d Stueck, Preis: %.2f Euro, Kategorie: %c\n",
anzahl, preis, kategorie);
return 0;
}A1c (2 Punkte)
Betrachten Sie folgenden C-Codeausschnitt:
int n = 4;
int x = 1;
do
{
x += x;
n--;
}
while (n > 0);x nach Ausführung des Codes?n nach Ausführung des Codes?A1d (4 Punkte)
Nennen Sie die Linux-Kommandozeilenbefehle für folgende Aufgaben. Geben Sie nur den Befehlsnamen an (ohne Parameter).
A1e (4 Punkte)
Analysieren Sie folgendes C-Programm:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *datei = fopen("personen.dat", "r");
if (datei == NULL)
{
return 1;
}
char zeile[256];
fgets(zeile, 256, datei);
zeile[strlen(zeile) - 1] = '\0';
int k = 0;
while (zeile[k] != ',' && zeile[k] != '\0')
{
k++;
}
zeile[k] = '\0';
if (strcmp(zeile, "Name") != 0 || strcmp(&zeile[k + 1], "Info") != 0)
{
fclose(datei);
return 1;
}
while (fgets(zeile, 256, datei) != NULL)
{
k = 0;
while (zeile[k] != ',' && zeile[k] != '\0')
{
k++;
}
zeile[k] = '\0';
int info = atoi(&zeile[k + 1]);
if (info > 0)
{
printf("%s: %d\n", zeile, info);
}
}
fclose(datei);
return 0;
}A2: Grundlagen der C-Programmierung (14 Punkte)
A2a (2 Punkte)
Analysieren Sie folgende Situation: Ein Programm verwendet eine globale Variable namens counter mit dem Startwert 50. Es gibt eine Funktion berechnung, die zwei Parameter a und b entgegennimmt.
Die Funktion berechnung enthält folgende Anweisungen:
- Erhöht die Variable counter um 1.
- Legt eine Variable sum auf dem Stack an.
- Weist sum den Wert
a + b + counterzu. - Gibt sum zurück.
Die Hauptfunktion des Programms arbeitet wie folgt (Pseudocode):
HAUPTFUNKTION:
x = 8
y = 12
ergebnis = AUFRUF berechnung(x, y)
AUSGABE "Ergebnis: " + ergebnis
AUSGABE "Counter: " + counterA2b (2 Punkte)
Beantworten Sie folgende Fragen zu C-Bibliotheksfunktionen:
A2c (3 Punkte)
Das folgende Programm soll die Summe aller Zahlen von 1 bis n (einschließlich) berechnen, enthält aber drei Fehler:
#include <cs50.h>
int calculate_sum(int n)
{
int sum = 0;
for (int i = 1; i < n; i++)
{
sum += i;
}
return sum;
}
int main(void)
{
int number = get_int("Geben Sie eine Zahl ein: ");
int result = calc_sum(number);
printf("Die Summe von 1 bis %d ist %d\n"; number, result);
return 0;
}A2d (7 Punkte)
Das Programm statistik.c verarbeitet ein Integer-Array zahlen mit den Werten und gibt Minimum, Maximum und Durchschnitt aus.
Erwartete Ausgabe:
Min: 3
Max: 31
Avg: 13.75Unten stehen 15 nummerierte Codezeilen. Elf davon ergeben zusammen das korrekte Programm – die restlichen vier gehören nicht dazu. Geben Sie die Nummern der korrekten Zeilen in der richtigen Reihenfolge an.
1: sum += zahlen[i]; }
2: printf("Min: %d\n", min);
3: int min = zahlen[0], max = zahlen[0]; float sum = 0;
4: for (int i = 1; i <= 8; i++) {
5: int main(void) {
6: printf("Avg: %.2f\n", sum / 8);
7: for (int i = 0; i < 8; i++) {
8: return 0; }
9: printf("Avg: %d\n", sum / 8);
10: #include <stdio.h>
11: if (zahlen[i] < min) min = zahlen[i]; if (zahlen[i] > max) max = zahlen[i];
12: int zahlen[] = {14, 7, 23, 3, 18, 9, 31, 5};
13: printf("Max: %d\n", max);
14: int sum = 0; int min = 0, max = 0;
15: int *zahlen; zahlen = [14, 7, 23, 3, 18, 9, 31, 5];A3: IBAN validieren (15 Punkte)
Beim Bezahlen Ihrer Semestergebühren haben Sie eine sogenannte IBAN (International Bank Account Number) verwendet. Dabei handelt es sich um eine standardisierte Notation für Kontonummern.
Diese ist für Deutsche Konten folgendermaßen aufgebaut:
- 2-stelliger Ländercode bestehend aus Großbuchstaben (in Deutschland “DE”)
- 2-stellige Prüfziffer
- Eine 18 stellige Kontoidentifikation, bestehend aus Bankleitzahl und Kontonummer
Ihre Aufgabe ist es nun, ein Programm zu schreiben, das eine solche IBAN als Kommandozeilenparameter entgegennimmt und auf Gültigkeit prüft. Um die Komplexität der Aufgabe überschaubar zu halten, berücksichtigen wir ausschließlich deutsche Kontonummern.
Den unvollständigen Quellcode des Programms finden Sie im Verzeichnis exam-files/iban 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 iban.c befindet:
check50 checks/iban
Zuvor sollten Sie Ihr Programm kompilieren.
A3a (5 Punkte)
Prüfen Sie zunächst die Eingaben des Nutzers auf Vollständigkeit:
- Gibt der Nutzer keinen oder mehr als einen Kommandozeilenparameter an, geben Sie die Nachricht:
Usage: ./iban <iban>aus. - Wenn die IBAN zu kurz oder zu lang ist, geben Sie die Nachricht:
IBAN too long or too shortaus.
Fügen Sie jeweils ein Newline-Escapezeichen hinzu und beenden Sie das Programm mit dem Rückgabewert 1.
A3b (5 Punkte)
Prüfen Sie nun die Syntax der eingegebenen IBAN.
- Wenn die ersten 2 Stellen nicht dem Ländercode
DEentsprechen, geben Sie die Nachricht:Not a german IBANaus. - Wenn die IBAN ab der dritten Stelle (index 2) andere Zeichen als Ziffern (
0-9) enthält, geben Sie die Nachricht:IBAN contains invalid digitsaus.
Fügen Sie jeweils ein Newline-Escapezeichen hinzu und beenden Sie das Programm mit dem Rückgabewert 1.
A3c (5 Punkte)
Ermitteln Sie nun im letzten Schritt, ob die eingegebene IBAN gültig ist. Vervollständigen Sie dazu die Funktion validate_iban. Diese nimmt eine IBAN als String entgegen, berechnet die Prüfsumme und gibt 1 im Fall einer gültigen IBAN und 0 im Fall einer ungültigen IBAN zurück.
Geben Sie anschließend im Fall einer gültigen IBAN den String IBAN is valid aus, ansonsten IBAN is invalid und beenden Sie das Programm mit dem Rückgabewert 0.
Eine IBAN wird folgendermaßen berechnet:
Zunächst wird das Länderkennzeichen “DE” als Zahlenwert (D=13, E=14) an die Ziffern der Kontoidentifikation angehängt. Dadurch entsteht eine 22 Ziffern lange Zahl. An diese Zahl werden dann die Prüfziffern angehängt, wodurch eine insgesamt 24 Ziffern lange Zahl entsteht. Anschließend wird diese Zahl dann mit Rest durch 97 geteilt. Wenn das Ergebnis 1 ist, ist die IBAN gültig, andernfalls nicht.
Hinweise: Sie benötigen zum Teilen mit Rest den Modulo-Operator (% auf der Tastatur). Die gesamte Zahl ist zu groß für einen Integer in C. Gehen Sie daher folgendermaßen vor: Starten Sie mit rest = 0. Gehen Sie dann Ziffer für Ziffer vor, indem sie den Rest mit 10 multiplizieren, die nächste Ziffer addieren und anschließend Modulo 97 rechnen, um den Rest neu zu berechnen. Oder um es noch kompakter darzustellen: neuer_rest = (alter_rest * 10 + ziffer) % 97
A4: ID3 Tags (13 Punkte)
Das Audioformat MP3 verfügte anfangs über keine Möglichkeit, Informationen über den Inhalt einer Datei zu speichern. Im Jahr 1997 erfand Eric Kemp mit ID3 ein einfaches Metadatenformat, das aus einem 128 Byte langen Tag (also einer Datenstruktur mit einem definiertem Format) besteht, der am Ende einer Audiodatei angehängt wird. In diesem Tag werden Informationen wie Interpret, Album und Songname gespeichert.
Die Dateien für diese Aufgabe finden Sie im Verzeichnis exam-files/id3 in Ihrem Home-Verzeichnis.
A4a (7 Punkte)
Vervollständigen Sie das Programm id3v1.c, um den ID3-Tag aus dem Song file.mp3 zu extrahieren. Berücksichtigen Sie dazu die folgenden Informationen.
In der ursprünglichen ID3-Version 1.0 war ein ID3-Tag wie folgt spezifiziert:
MP3 ID3 Tag 1.0 -- 128 bytes
(c) 1996, 1997 NamkraD (Eric Kemp)
Seek end of file, then -128, if first 3 bytes='TAG' then it has info layed
out as follows...
0..2 == 'TAG' (3 Bytes)
3..32 == Song Name (30 bytes)
33..62 == Artist (30 Bytes)
63..92 == Album Name (30 Bytes)
93..96 == Year (4 Bytes)
97..126 == Comment (30 Bytes)
127 == 1 Byte Song Genre Identifier
(get the listing of song Genre Types to know what byte = what)Definieren Sie in id3v1.c eine struct, die dem obigen Schema entspricht, lesen Sie die Informationen aus der Datei file.mp3 in die struct ein und geben Sie die struct-Attribute mit den bereits vorhandenen printf-Anweisungen aus.
Hinweis: Für das Genre-Byte können Sie den Datentyp uint8_t verwenden. Für die restlichen Felder eignet sich char.
Ein Freund hat die Aufgabe mit den vorgegebenen printf-Anweisungen gelöst, beobachtet jedoch folgende Ausgabe:
...
Year: 1987:)
Comment: :)
...A4b (6 Punkte)
ID3 wurde von M. Nilsson zu ID3v2 weiterentwickelt. In ID3v2 können komplexere Daten abgelegt werden, unter anderem auch ein Album-Cover-Bild. Ihre Aufgabe ist es im Folgenden, das Album-Cover-Bild des Songs zu extrahieren.
Ein ID3v2-Tag befindet sich am Anfang einer Datei und besteht aus einem ID3v2-Header-Tag, in dem einer oder mehrere ID3v2-Frames eingebettet sind. Diese ID3v2-Frames enthalten jeweils einen Header, der die Art der Metadaten beschreibt, sowie die Metadaten selbst.
Im vorliegenden Fall (Datei: id3v2.c) ist bereits Code vorhanden, der den ID3v2-Header und den Attached-Picture (APIC) Frame einliest. Der APIC-Frame wird hierbei in den Heap eingelesen und über den Pointer frame_data referenziert. Ihre Aufgabe ist es nun, die Metadaten des APIC-Headers zu überspringen und anschließend das Album-Cover-Bild in der Datei cover.png abzuspeichern.
Ein APIC-Frame sieht folgendermaßen aus:
Text encoding $xx (1 Byte)
MIME type <text string>'\0' (String, terminiert durch Nullbyte)
Picture type $xx (1 Byte)
Description <text string>'\0' (String, terminiert durch Nullbyte)
Picture data <binary data>Hinweis: Sollte es Ihnen nicht gelingen, den korrekten Offset zu ermitteln, können Sie stattdessen den Wert 42 verwenden.
A5: Datenstrukturen und Algorithmen (14 Punkte)
A5a (3 Punkte)
Ein unsortiertes Array enthält folgende Elemente . Sie beobachten die ersten zwei Durchläufe der äußeren Schleife eines Sortieralgorithmus, der auf dieses Array angewendet wird.
Nach Durchlauf 1: [4, 2, 1, 3, 5]
Nach Durchlauf 2: [2, 1, 3, 4, 5]Welcher der beiden Algorithmen – Bubble Sort oder Selection Sort – hat diese Zustände produziert? Auf welche Beobachtung stützen Sie Ihre Entscheidung?
A5b (6 Punkte)
Zur Erinnerung: Ein Trie kann platzsparend mit folgender Datenstruktur implementiert werden:
struct trie_node {
char buchstabe;
char* wort; // Zeiger auf das gespeicherte Wort (falls vorhanden; sonst NULL)
struct trie_node* nachbar;
struct trie_node* kind;
};Mit dieser Datenstruktur wurde ein Trie für Abkürzungen aufgebaut, der bereits folgende Einträge enthält:
- HTML: Hypertext Markup Language
- HTTP: Hypertext Transfer Protocol
Die Speicherrepräsentation sieht wie folgt aus (Adressen sind vierstellig):
// Root-Knoten (zeigt auf den ersten Buchstaben)
struct trie_node* root = 0x1000;
0x1000: ['H', NULL, NULL, 0x2000]
0x2000: ['T', NULL, NULL, 0x3000]
0x3000: ['T', NULL, 0x7000, 0x5000]
0x5000: ['P', Zeiger auf "Hypertext Transfer Protocol", NULL, NULL]
0x7000: ['M', NULL, NULL, 0x8000]
0x8000: ['L', Zeiger auf "Hypertext Markup Language", NULL, NULL]Als nächstes soll der Eintrag HTTPS: Hypertext Transfer Protocol Secure in den Trie eingefügt werden. Eine Kollegin sagt: Moment mal, der aktuelle Trie enthält nur 4-Buchstaben-Abkürzungen, aber jetzt fügen wir eine 5-Buchstaben-Abkürzung ein. Das bedeutet, wir müssen die vorherigen Inhalte aktualisieren und ein spezielles End-of-Entry-Zeichen anhängen, sonst wird der Trie den String „Hypertext Transfer Protocol“ zurückgeben, wenn wir später die neue Abkürzung „HTTPS“ nachschlagen.
Erweitern Sie nun die Trie-Struktur um den neuen Eintrag HTTPS: Hypertext Transfer Protocol Secure. Verwenden Sie die Adresse 0x9000 für den neuen Knoten. Vervollständigen Sie die Felder der betroffenen Knoten in der Notation [buchstabe, wort, nachbar, kind]:
Geänderter Knoten:
0x5000: [___, ___, ___, ___]
Neuer Knoten:
0x9000: [___, ___, ___, ___]Erweitern Sie die Trie-Struktur zusätzlich um den Eintrag JSON: JavaScript Object Notation. Verwenden Sie die Adressen 0xA000 bis 0xD000 für die neuen Knoten. Orientieren Sie sich dabei am vorgegebenen Antwortschema und ändern Sie nur die dort angegebenen Knoten.
Geänderter Knoten:
0x1000: [___, ___, ___, ___]
Neue Knoten:
0xA000: [___, ___, ___, ___]
0xB000: [___, ___, ___, ___]
0xC000: [___, ___, ___, ___]
0xD000: [___, ___, ___, ___]A5c (5 Punkte)
Unten stehen 11 nummerierte Codezeilen für ein C-Programm, das mit malloc Speicher für vier Ganzzahlen allokiert, die Werte 40, 30, 20, 10 zuweist und sie in umgekehrter Reihenfolge ausgibt. Acht Zeilen ergeben das korrekte Programm – die restlichen drei gehören nicht dazu. Zwei Zeilen enthalten Lücken (LUECKE_1 und LUECKE_2), die jeweils das Argument für malloc darstellen. Ziffer 8 fügt die zwei angegebenen Zeilen hintereinander ein.
Beide Lücken enthalten denselben Ausdruck; relevant ist nur die korrekte malloc-Zeile.
Erwartete Ausgabe:
Wert 0: 10
Wert 1: 20
Wert 2: 30
Wert 3: 40 1: return 0; }
2: printf("Wert %d: %d\n", i, arr[i]); }
3: free(arr);
4: int *arr = malloc(LUECKE_1);
5: for (int i = 0; i < 4; i++) {
6: arr[0] = 40; arr[1] = 30; arr[2] = 20; arr[3] = 10;
7: int main(void) {
8: #include <stdio.h>
#include <stdlib.h>
9: printf("Wert %d: %d\n", 3 - i, arr[i]); }
10: for (int i = 3; i >= 0; i--) {
11: int arr[4] = malloc(LUECKE_2);A6: Zeiger und Datenstrukturen (7 Punkte)
A6a (4 Punkte)
Ein C-Programm soll die Werte zweier Variablen mithilfe einer Funktion vertauschen. Unten stehen 16 nummerierte Codezeilen. Zehn davon ergeben das korrekte Programm – die restlichen sechs gehören nicht dazu. Zwei Zeilen enthalten Lücken: LUECKE_1 hat die Struktur ??? = ??? und LUECKE_2 besteht aus den Argumenten des Funktionsaufrufs.
1: int temp = a;
2: #include <stdio.h>
3: void vertausche(int *a, int *b) {
4: return a; }
5: int x = 15; int y = 25;
6: LUECKE_1;
7: vertausche(x, y);
8: int main(void) {
9: *b = temp; }
10: int temp = *a;
11: a = b;
12: printf("Nach dem Tausch: x = %d, y = %d\n", x, y);
13: b = temp;
14: int vertausche(int a, int b) {
15: vertausche(LUECKE_2);
16: return 0; }A6b (3 Punkte)
Eine Programmiererin oder ein Programmierer hat versucht, eine Funktion zum Löschen eines Elements aus einer einfach verketteten Liste zu implementieren. Die Implementierung enthält jedoch einen Fehler, der dazu führt, dass das Löschen des ersten Elements nicht korrekt funktioniert.
Hier ist die fehlerhafte Implementierung:
#include <stdbool.h>
#include <stdlib.h>
typedef struct sllnode {
int value;
struct sllnode *next;
} sllnode;
// TODO: Fehler beim Löschen des ersten Elements beheben
bool delete_element(sllnode* head, int value) {
if (head == NULL) {
return false; // Liste ist leer
}
// Erstes Element löschen
if (head->value == value) {
sllnode* temp = head;
head = head->next;
free(temp);
return true;
}
// Anderes Element löschen
sllnode* current = head;
while (current->next != NULL) {
if (current->next->value == value) {
sllnode* temp = current->next;
current->next = temp->next;
free(temp);
return true;
}
current = current->next;
}
return false; // Element nicht gefunden
}sllnode**) verwenden. Sie müssen dazu auch die Signatur der Funktion delete_element verändern. Fügen Sie den Code der korrigierten Funktion delete_element hier ein:B1: Python und OOP (20 Punkte)
B1a (4 Punkte)
Für ein Projekt haben Sie einen Mikrocontroller mit verschiedenen Sensoren ausgestattet, um deren Werte zu erfassen. Die gesammelten Messdaten sollen in Python ausgewertet werden.
Die Klasse Measurement (Datei oop.py im Verzeichnis exam-files/python_oop) dient als allgemeine Vorlage für Sensormessungen. Der Code unten zeigt die Klasse mit zwei Lücken. Füllen Sie diese aus.
class Measurement:
def __init__(self, sensor_id, value, time):
self.sensor_id = sensor_id
self.value = value
self.time = time
def __str__(self):
___Lücke_1___
___Lücke_2___Lücke 1 ist die Implementierung der __str__-Methode (eine Zeile genügt). In Lücke 2 erstellen Sie ein Objekt mit den folgenden Attributwerten und geben es mit print() aus:
value = 22.3
time = "2025-07-17T08:15:00"
sensor_id = "T1"Die Ausgabe von print(obj) soll so aussehen:
2025-07-17 08:15:00 Sensor T1: 22.3__str__ (eine Zeile):print() ausgeben:B1b (6 Punkte)
Nutzen Sie die erweiterte Klasse Measurement aus der Datei subclasses.py (Verzeichnis exam-files/python_oop) als Basisklasse. Der Code unten zeigt eine Subklasse mit drei Lücken.
- Lücke 1 enthält die Klassendefinitionszeile mit Vererbung für die Klasse
TemperatureMeasurement. - Lücke 2 enthält eine Methode is_valid(). Diese gibt True zurück, wenn der Messwert im gültigen Bereich liegt (Temperatur: –20 bis +60), sonst False.
- Lücke 3 ist eine Property unit. Diese gibt die passende Einheit zurück (bei Temperatur: “°C”).
___Lücke_1___
measurement_type = "temperature"
___Lücke_2___
___Lücke_3___B1c (6 Punkte)
Für diese Aufgabe benötigen Sie die Dateien read_measurements.py und measurements.json. Beide Dateien befinden sich ebenfalls im Verzeichnis exam-files/python_oop.
Implementieren Sie die Funktion load_measurements_from_json, die die JSON-Datei einliest und für jeden Eintrag in der JSON-Datei das passende Messobjekt erstellt. Das heißt, es soll je nach Typ (“temperature” oder “co2”) eine Instanz der Klasse TemperatureMeasurement oder CarbonDioxideMeasurement erzeugt werden. Sie können davon ausgehen, dass die Werte in der JSON-Datei in °C (Grad Celsius) bzw. ppm (parts per million) vorliegen.
In main() geben Sie die erzeugten Objekte anschließend sortiert nach ihrem Zeitstempel aus. Zur Erinnerung: sorted() akzeptiert einen key-Parameter, der bestimmt, wonach sortiert wird:
sorted(["Hund", "Katze", "Maus"], key=lambda x: len(x))Die Zeitstempel in der JSON-Datei sind bereits so formatiert, dass eine Sortierung als String ausreicht.
Dabei sollen die Attributwerte in folgender Reihenfolge ausgeben werden: time, sensor_id, value, unit.
Rufen Sie zudem – abhängig vom Typ des Messobjekts – die passende Methode auf: bei Temperaturmessungen convert_celsius_to_fahrenheit() und bei CO₂-Messungen get_air_status(). Hängen Sie den Rückgabewert dieser Methoden jeweils ans Ende der Zeile an.
B1d (4 Punkte)
Betrachten Sie die folgende Python-Interpreter-Sitzung:
>>> import random
>>> import string
>>> string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> random.choice(string.ascii_letters)
'k'
>>> random.choice(string.ascii_letters)
'T'
>>> "".join([random.choice(string.ascii_letters) for _ in range(6)])
'SRTGlv'[... for ... in ...], das hier als Argument von join() verwendet wird?Schreiben Sie Python-Code, der ohne dieses Konzept einen zufälligen Code aus 6 Buchstaben erzeugt und in der Variable code speichert. Verwenden Sie stattdessen eine for-Schleife, um nach und nach zufällige Zeichen an code anzuhängen.
for-Schleife hier ein:B2: Web-Entwicklung: Link-Shortener (20 Punkte)
In den folgenden Teilaufgaben entwickeln Sie einen Link Shortener mit Flask. Sie können dort eine URL eingeben und erhalten einen kurzen Code, über den die URL später wieder aufgerufen werden kann. Die Zuordnungen von URLs und Codes werden vom Server in einer JSON-Datei gespeichert.
Das Skelett der Anwendung finden Sie im Verzeichnis exam-files/shortener. Öffnen Sie die Datei app.py und die Templates im Ordner templates/ – dort finden Sie vorbereitete Funktionen und Routen mit TODO-Kommentaren, die Sie Schritt für Schritt vervollständigen.
Damit Code-Änderungen vom Flask-Server automatisch berücksichtigt werden, müssen Sie den Server wie folgt starten:
flask --debug run
Um die Anwendung im Browser zu öffnen, klicken Sie bei gedrückter Strg-Taste auf die URL (Running on …), die Flask nach dem Start anzeigt. Um Flask zu beenden, verwenden Sie die Tastenkombination Strg-C.
B2a (4 Punkte)
Vervollständigen Sie das Template index.html. Erstellen Sie ein HTML-Formular mit:
- Methode POST, Ziel beim Submit
/shorten - Eingabefeld für die URL (Name:
url) - Eingabefeld für den optionalen Kurzcode (Name:
code) - Absende-Button mit Text Shorten!
B2b (6 Punkte)
Vervollständigen Sie in app.py die Funktion write_links(links) sowie die Route /shorten.
write_links ist das Gegenstück zu read_links() (die bereits fertig in app.py steht): Die Funktion soll das übergebene Dictionary links als JSON in die Datei schreiben.
write_links(links) ein (nicht die ganze Datei):Route /shorten: Die Route empfängt einen POST-Request. Implementieren Sie die folgenden Schritte:
- Die Formularfelder
urlundcodeaus dem Request auslesen (mitrequest.form[...]) - Falls
codeleer ist: einen zufälligen 6-Buchstaben-Code erzeugen (siehe Hilfskommentar am Ende vonapp.py) - Die bestehenden Links mit
read_links()laden, den neuen Eintragcode → urlhinzufügen und mitwrite_links()speichern - Das Template
result.htmlrendern und dabei die Variablencodeundurlübergeben
/shorten ein (nicht die ganze Datei):Tipp zum Testen: Sie können die Route auch ohne funktionierendes Formular testen. Der Befehl
curl -X POST -d "url=https://example.com&code=test1" http://...
sendet eine HTTP-POST-Anfrage mit Formulardaten an die URL am Ende des curl-Aufrufs. An welche Ziel-IP-Adresse und welchen Ziel-Port müssen Sie diese Anfrage senden, wenn Sie Flask mit flask --debug run (ohne zusätzliche Parameter) starten? Geben Sie die vollständige URL inklusive Pfad an.
B2c (5 Punkte)
Redirect-Route: Schreiben Sie eine neue Route in app.py, die unter /CODE erreichbar ist, wobei CODE ein variabler Kurzcode ist (z.B. /abc123 oder /test1). Die Route soll:
- Die gespeicherten Links mit
read_links()laden - Falls der Kurzcode im Dictionary existiert: mit
redirect()zur gespeicherten URL weiterleiten - Falls nicht:
"Link nicht gefunden"mit Statuscode 404 zurückgeben
Tipp zum Testen: Legen Sie über das Formular (oder per curl) einen Link mit dem Code infdoc an, der auf http://127.0.0.1:8080/infeinf-docs.html verweist. Wenn Ihre Redirect-Route funktioniert, sollte der Aufruf von /infdoc im Browser zur Dokumentationsseite weiterleiten.
B2d (5 Punkte)
Jinja-Template: Schreiben Sie das vollständige Template links.html, sodass alle gespeicherten Links als Tabellenzeilen angezeigt werden. Die Variable links wird als Dictionary übergeben (Kurzcode → URL). Jede Zeile soll den Code und die URL (als klickbaren Link) enthalten.
links.html ein:Diese Seite als Markdown: ansehen herunterladen