# Wintersemester 2024/25

Quelle: https://inf.zone/extras/altklausuren/ws-2425/

**Wintersemester 2024/25.** 9 ECTS: alle Aufgaben, 180 Minuten, 120 Punkte. 6 ECTS: nur A1 bis A6, 120 Minuten, 80 Punkte.

**Altklausur**

Die Aufgaben einer früheren E-Prüfung, ohne Lösungen. Geprüft wurde am Laptop: Wo hier ein leerer Kasten steht, war in der Prüfung ein Eingabefeld. Zu jeder Teilaufgabe gab es außerdem das Kästchen [„Weiß ich nicht“](https://inf.zone/extras/exam-hints/#weiß-ich-nicht-kästchen).

Den Code, der in der Prüfung im Ordner `exam-files` lag, gibt es als [ws-2425.zip](https://inf.zone/download/extras/altklausuren/ws-2425.zip). Im Codespace laden und entpacken Sie ihn so:

```bash
wget https://inf.zone/download/extras/altklausuren/ws-2425.zip
unzip ws-2425.zip
```

Die Tests, die in der Prüfung mit `check50 checks/...` liefen, liegen nicht bei.

In `cat.bmp` und `crypt.bmp` steht statt der Katze aus der Prüfung ein Platzhalter. Die versteckte Nachricht, ihre Stelle im Bild und die Werte aus A4b sind dieselben wie in der Prüfung.

## A1: Grundlagen (17 Punkte)

### A1a (4 Punkte)

Geben Sie bei den folgenden Beispielen an, ob es sich eher um eine **Textdatei** oder eine **Binärdatei** handelt.

Ein kompiliertes C-Programm.

*[Antwortfeld]*

Der Quellcode eines C-Programms.

*[Antwortfeld]*

Eine Textdatei, die eine Hexadezimalzahl als String enthält: "0xff1193"

*[Antwortfeld]*

Ein JPEG-Bild.

*[Antwortfeld]*

### A1b (6 Punkte)

Identifizieren Sie in folgendem Programmcode ein konkretes 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.

```c
#include <cs50.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    string names[] = {"Barky", "Meowy"};
    string name = get_string("Name: ");
    for (int i = 0; i < 3; i++)
    {
        if (strcmp(names[i], name) == 0)
        {
            printf("Found %s\n", name);
            return 0;
        }
    }
    return 1;
}
```

Literal:

*[Antwortfeld]*

Variable:

*[Antwortfeld]*

Rückgabewert:

*[Antwortfeld]*

Escapesequenz:

*[Antwortfeld]*

Formatcode:

*[Antwortfeld]*

Einen Programmierfehler:

*[Antwortfeld]*

### A1c (3 Punkte)

Welche Farben stellen die folgenden hexadezimalen RGB-Farbcodes dar? Ordnen Sie die Farbe zu, die am ehesten zutrifft.

Es stehen zur Auswahl:

- eine rötliche Farbe
- ein kräftiges Blau
- schwarz
- grau

#808080

*[Antwortfeld]*

#000000

*[Antwortfeld]*

#cc0000

*[Antwortfeld]*

### A1d (4 Punkte)

Welches oder welche der in der Vorlesung behandelten grundlegenden informatischen Prinzipien lassen sich in folgendem Programm (Pseudocode) erkennen? Nennen Sie den oder die Fachbegriffe durch Leerzeichen getrennt.

```text
FUNKTION länge(text):
    WENN text = "" DANN
        RÜCKGABE 0
    SONST
        RÜCKGABE 1 + länge(text ohne erstes Zeichen)

Hauptprogramm:
    AUSGABE "Bitte geben Sie einen Text ein: "
    text = EINGABE

    AUSGABE "Länge des Textes:"
    AUSGABE länge(text)
```

Erkennbare Prinzipien:

*[Antwortfeld]*

Zu welchem Problem könnte es zur Laufzeit kommen, wenn der Pseudocode in C implementiert und ausgeführt wird? Bitte nennen Sie den Fachbegriff und die Bedingung unter der es zum Problem kommt.

Fachbegriff und Bedingung

*[Antwortfeld]*

## A2: Grundlagen der C-Programmierung (14 Punkte)

### A2a (3 Punkte)

Welche Werte erhalten die Variablen *s* und *t*, wenn der folgende Code-Abschnitt ausgeführt worden ist?

*Falls Sie sich nicht mehr daran erinnern, wie der verwendete Operator funktioniert, können Sie den Code kompilieren und ausführen. Falls Sie VS Code verwenden möchten, lesen Sie bitte zuerst die Hinweise, die zu Beginn dieser Aufgabe verlinkt sind.*

```c
string str = "Test";
int s = 0;
int t = 0;
s = ((t = strlen(str)) > 10) ? 1 : 0;
```

Wert von s:

*[Antwortfeld]*

Wert von t:

*[Antwortfeld]*

Die Konstruktion mit **"?"** und **":"** ist der sogenannte ... Operator. Welcher Fachausdruck gehört in die Lücke?

*[Antwortfeld]*

### A2b (7 Punkte)

Implementieren Sie ein Programm *deduplicate.c*, das Duplikate aus einem bereits sortierten Array von ganzen Zahlen entfernt. Duplikate sind Werte, die im Array mehrfach vorkommen.

Implementieren Sie die folgende Funktionalität direkt in **main()**:

- Deklarieren Sie ein Array mit den Namen **numbers**, das mindestens sieben sortierte fest kodierte Werte enthält. Zwei Werte sollen einfach vorkommen, ein Wert soll zweifach vorkommen und ein Wert soll dreifach vorkommen (z.B. 1, 2, 2, 3, 8, 8, 8).
- Schreiben Sie direkt in die main()-Funktion Ihren Deduplicate-Algorithmus. Dieser Algorithmus muss das Array *numbers* verarbeiten und das Ergebnis auf der Konsole ausgeben, wobei aufeinanderfolgende Zahlen durch Leerzeichen voneinander getrennt sein sollen. Es ist nicht erforderlich, das deduplizierte Array abzuspeichern.
- Es sollen keine Duplikate ausgegeben werden.
- Die ausgegebenen Zahlen sollen weiterhin sortiert sein.
- Nach der letzten Zahl soll ein Zeilenumbruch ausgegeben werden.
- Überflüssige Leerzeichen am Zeilenende spielen in dieser Teilaufgabe keine Rolle.

Beispiele:

Wenn *numbers* anfangs die Werte 1, 2, 2, 3, 4, 4, 4, 5 enthält, wird die Zeichenfolge **1 2 3 4 5** ausgegeben. Wenn *numbers* hingegen die Werte 3, 3, 3, 3, 3 enthält, wird die Zeichenfolge **3** ausgegeben.

*Überlegen Sie sich einen möglichst einfachen Weg, der ausnutzt, dass das Array bereits sortiert ist.*

Kopieren Sie den gesamten Code Ihres Programms in dieses Feld:

*[Antwortfeld, mehrzeilig]*

Erstellen Sie eine Kopie Ihres Programms und nennen Sie diese zum Beispiel *comma.c*. Wandeln Sie Ihren Code so ab, dass er bei der Ausgabe die Zahlen mit einem Komma und einem Leerzeichen voneinander trennt. In den oben genannten zwei Beispielen soll also **1, 2, 3, 4, 5** bzw. weiterhin **3** ausgegeben werden.

Achten Sie – anders als in der vorigen Teilaufgabe – darauf, dass nach der letzten Zahl kein Komma und kein überflüssiges Leerzeichen ausgegeben wird, sondern nur ein Zeilenumbruch.

*Sollte Ihr Programm deduplicate.c nicht lauffähig sein oder nicht korrekt funktionieren, können Sie hilfsweise in diesem Feld ein Programm abgeben, das die Werte eines Integer-Arrays mit beliebigen Werten so formatiert ausgibt, wie in der Aufgabenstellung gefordert.*

Kopieren Sie den gesamten Code Ihres Programms in dieses Feld:

*[Antwortfeld, mehrzeilig]*

### A2c (4 Punkte)

Das folgende Programm rechnet falsch, aber nur manchmal.

```c
#include <cs50.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    int scores[3];
    scores[0] = get_int("Wert 1: ");
    scores[1] = get_int("Wert 2: ");
    scores[2] = get_int("Wert 3: ");

    float result = (scores[0] + scores[1] + scores[2]) / 3;
    int okay = 1;
    for(int i = 0; i < 3; i++)
    {
        if(scores[i] < 1)
        {
            okay = 0;
        }
    }
    if(okay)
    {
        printf("Durchschnittswert: %f\n", result);
    }
    else
    {
        printf("Werte kleiner 1 sind nicht erlaubt.\n");
    }
}
```

Bei den folgenden Fragen geben Sie die Werte bitte mit Leerzeichen getrennt an.

Geben Sie ein Beispiel für drei Eingabewerte an, bei denen das Programm korrekt rechnet.

*[Antwortfeld]*

Geben Sie ein Beispiel für drei Eingabewerte an, bei denen das Programm fehlerhaft rechnet.

*[Antwortfeld]*

## A3: Palindrom-Checker (12 Punkte)

In dieser Aufgabe erstellen Sie schrittweise ein C-Programm *palindrome.c*, das prüft, ob ein als erstes Kommandozeilenargument übergebener String ein Palindrom ist. Zur Erinnerung: Ein **Palindrom** ist eine Zeichenfolge, die vorwärts und rückwärts gelesen identisch ist. Beispiele hierfür sind z.B. "anna", "radar" und "lagerregal".

Für diese Aufgabe stellen wir Ihnen Quellcode zur Verfügung, den Sie vervollständigen müssen. Wechseln Sie dazu im Terminal in das Verzeichnis **exam-files/palindrome**, das sich in Ihrem Homeverzeichnis */home/student* befindet, und führen Sie dort aus:

**code palindrome.c**

Wenn Sie diese Schritt befolgt haben, steht Ihnen *check50* zur Verfügung. Um check50 zu verwenden, führen Sie im Verzeichnis, in dem *palindrome.c* liegt, folgenden Befehl aus:

**check50 checks/palindrome**

Zuvor sollten Sie Ihr Programm kompilieren.

### A3a (5 Punkte)

In dieser Teilaufgabe sollen Sie erst einmal nur die Eingaben des Benutzers überprüfen.

Wenn der Benutzer beim Aufruf des Programms keine Kommandozeilenargumente oder mehr als ein Argument übergibt, soll das Programm mit dem Rückgaberwert 1 beendet werden und folgende Meldung auf die Konsole (Standardausgabe) schreiben:

`Usage: ./palindrome <word>`

Wenn das übergebene Argument kein String ist, der ausschließlich aus Kleinbuchstaben besteht, soll das Programm ebenfalls mit dem Rückgabewert 1 beendet werden, in diesem Fall mit folgender Ausgabe:

`The argument must be a lowercase string!`

Vervollständigen Sie dazu die vorgegebene Funktion **is\_lowercase** und rufen Sie diese in main() auf.

Kopieren Sie den gesamten Quellcode der Datei *palindrome.c* in dieses Feld.

*[Antwortfeld, mehrzeilig]*

### A3b (7 Punkte)

Vervollständigen Sie nun die Funktion **is\_palindrome**, die überprüft, ob es sich bei der übergebenen Zeichenkette um ein Palindrom handelt. Wenn die Zeichenkette ein Palindrom ist, soll das Programm folgendes ausgeben:

`The string is a palindrome`

Andernfalls soll es ausgeben:

`The string is not a palindrome`

Kopieren Sie den gesamten Quellcode der Datei *palindrome.c* in dieses Feld.

*[Antwortfeld, mehrzeilig]*

## A4: Operation Pixel Whispers (12 Punkte)

Während sich die Kryptographie mit der Geheimhaltung von Informationen beschäftigt, hat die Steganographie ein anderes Ziel: Hier geht es darum, eine Nachricht in einem Medium (z.B. einem Bild) so zu verstecken, dass Außenstehende nicht bemerken, dass diese existiert. Bei Bildern werden dazu die Farbwerte verändert.

Sie sind eine Agentin oder ein Agent des *Bureau of Steganographic Operations & Decryption*, spezialisiert auf die Wiederherstellung von steganographischen Nachrichten, die in Windows-Bitmap-Dateien (BMP-Dateien) versteckt sind. Sie haben ein verdächtiges Bild abgefangen, von dem Sie glauben, dass es eine geheime Nachricht enthält.

Für diese Aufgabe stellen wir Ihnen Bilder und Quellcode zur Verfügung, den Sie vervollständigen müssen. Wechseln Sie dazu im Terminal in das Verzeichnis **exam-files/pixels**, das sich in Ihrem Homeverzeichnis */home/student* befindet.

### A4a (2 Punkte)

Ein befreundeter Nachrichtendienst hat Ihnen mitgeteilt, dass ein äußerst primitives Steganographie-Verfahren verwendet wird, bei dem kurze Nachrichten recht offensichtlich in einem der drei Farbkanäle transportiert werden. Hat man das Originalbild und das steganographisch veränderte Bild, kann man die geheime Botschaft leicht dekodieren.

Sehen Sie sich das Originalbild (*cat.bmp*) und das geänderte Bild (*crypt.bmp*) an, etwa in VS Code mit **code cat.bmp** und **code crypt.bmp** vergleichen Sie Vergrößerungen beider Bilder visuell.

Falls es Ihnen schwer fällt, einen Unterschied zu erkennen, können sie mit dem bereits kompilierten Kommandozeilenprogramm `grayscale` arbeiten, das im gleichen Verzeichnis liegt wie die Bilder. Dieses Program liest ein Bild ein und gibt es als Graustufenbild (*grayscale.bmp*) im aktuellen Verzeichnis aus. Da ein Graustufenbild nur noch Helligkeitswerte keine Farbinformationen mehr enthält, sollte es Ihnen leichter fallen zu ermitteln, wo sich die Nachricht befindet.

In welchem Farbkanal ist die geheime Botschaft versteckt?

*[Antwortfeld]*

### A4b (4 Punkte)

Sie vermuten, dass die XOR-Operation verwendet wurde, um die Nachricht zu verstecken. Vervollständigen Sie das Programm **poc.c**, um einen *Proof of Concept (PoC)* zu entwickeln. Mit dem PoC wollen Sie zeigen, dass Sie das erste ASCII-Zeichen der steganographisch verschleierten Nachricht wiederherstellen können.

Durch manuelle Analyse der zwei Bilder haben Sie folgende Informationen ermittelt: das erste Byte, das im modifzierten Bild anders ist als im Original, hat im modifizierten Bild den Wert 210. In der Originaldatei steht an dieser Position der Wert 255. Passen Sie *poc.c* so an, dass zu sehen ist, wie man in C aus diesen Informationen das erste ASCII-Zeichen der Nachricht berechnen kann. Geben Sie das ASCII-Zeichen aus. In dieser Teilaufgabe ist es also nicht erforderlich, die Bilder einzulesen.

**Hinweise zur Bearbeitung.**  Bei XOR handelt sich um einen logischen Operator, der auf einzelne Bits oder Bitfolgen (in C z.B. auf int oder char) angewendet werden kann. Das Ergebnis der XOR-Operation ist "wahr" (bzw. 1), wenn genau eines der beiden Eingabebits wahr (bzw. 1) ist, sonst ist das Ergebnis 0. Für zwei Eingabebits ergibt sich also:

| a | b | a XOR b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |

Wird XOR auf Werte angewendet, die aus mehreren Bits bestehen, werden die Bits paarweise verarbeitet. Verknüpft man beispielsweise die Zeichen 'A' und 'a' mit XOR, so erhält man ein Leerzeichen:

```text
Binary      Hex     ASCII
0100 0001   0x41    A
0110 0001   0x61    a
---------------------------
0010 0000   0x20    <space>
```

Die XOR-Operation wird in C mit `^` kodiert. Dieses Zeichen liegt auf einer deutschen Tastatur über der <kbd>Tab</kbd>-Taste, also neben der Ziffer <kbd>1</kbd>. Abschließend noch zwei Hinweise, die Ihnen helfen können, zu verstehen, wie eine Nachricht in ein Bild eingebettet wird und wie sie wieder extrahiert werden kann, wenn zusätzlich das Originalbild vorliegt:

```text
a ^ a = 0
a ^ a ^ b = b
```

Kopieren Sie den gesamten Quellcode der Datei *poc.c* in dieses Feld.

*[Antwortfeld, mehrzeilig]*

### A4c (6 Punkte)

Nachdem Sie sich mit dem Proof of Concept davon überzeugt haben, dass Ihr Ansatz funktioniert, vervollständigen sie als nächstes **recover.c**. Dieses Programm soll die ganze verschleierte Nachricht aus den beiden vorliegenden Bild-Dateien wiederherstellen. Geben Sie die Nachricht als ASCII-Text aus. Stellen Sie bei der Umsetzung sicher, dass ihr Programm keine Speicherlecks aufweist.

*Hinweis:* Es ist keine effiziente Implementation erforderlich. Wenn man mit *printf* einen *char*-Wert ausgeben lässt, der den Wert 0x00 hat, wird nichts ausgegeben und das Programm läuft weiter.

Kopieren Sie den gesamten Quellcode der Datei *recover.c* in dieses Feld.

*[Antwortfeld, mehrzeilig]*

## A5: Sortieren und Tries (10 Punkte)

Die folgende Abbildung zeigt die aus der Vorlesung bekannte Visualisierung von Sortieralgorithmen. Sortiert wird jeweils ein Array mit zufällig angeordneten Zahlen. Die Visualisierung zeigt den aktuellen Zustand des Algorithmus und der Arrays zu einem bestimmten Zeitpunkt während des Sortiervorgangs. Beide Algorithmen haben zu Beginn das gleiche Array erhalten und wurden nach der gleichen Laufzeit angehalten.

![Zwei Momentaufnahmen von Balkendiagrammen beim Sortieren. Links: nur ganz links ein paar kurze Balken sortiert und farbig markiert, der Rest ungeordnet. Rechts: mehrere bereits aufsteigend sortierte Teilfolgen nebeneinander, die größte links](https://inf.zone/extras/altklausuren/ws-2425/bild-1.png)

### A5a (6 Punkte)

Welche der drei in der Vorlesung behandelten Sortierverfahren kommen hier zum Einsatz?

Nennen Sie den in der **Abbildung links** verwendeten Algorithmus in der ersten Zeile. Begründen Sie ab der zweiten Zeile, warum es sich gerade um diesen handeln muss.

*[Antwortfeld, mehrzeilig]*

Nennen Sie den in der **Abbildung rechts** verwendeten Algorithmus in der ersten Zeile. Begründen Sie ab der zweiten Zeile, warum es sich gerade um diesen handeln muss.

*[Antwortfeld, mehrzeilig]*

### A5b (4 Punkte)

Zur Erinnerung: Eine Speicherplatz-effiziente Umsetzung eines **Tries** ist mit folgender Datenstruktur möglich:

```c
struct trie_node {
  char letter;
  char* str; // Stringpointer (falls Eintrag existiert; sonst NULL)
  struct trie_node* nachbar;
  struct trie_node* kind;
};
```

Mit dieser Datenstruktur wurde ein Trie für ein Abkürzungsverzeichnis erzeugt, der bereits zwei Elemente enthält:

- CSS: Cascading Style Sheets
- CPU: Central Processing Unit"

Im Speicher wird dies wie folgt abgebildet (Speicheradressen sind vierstellig):

```c
// Root-Knoten (zeigt auf den ersten Buchstaben)
struct trie_node* root = 0x1000;

0x1000: ['C', NULL, NULL, 0x2000]
0x2000: ['P', NULL, 0x3000, 0x2100]
0x2100: ['U', Pointer auf "Central Processing Unit", NULL, NULL]
0x3000: ['S', NULL, NULL, 0x3100]
0x3100: ['S', Pointer auf "Cascading Style Sheets", NULL, NULL]
```

Fügen Sie den neuen Eintrag "**CSV: Comma Separated Values**" in die Trie-Struktur ein. Legen Sie dazu einen oder mehrere neue Knoten mit von Ihnen gewählten, beliebigen vierstelligen Speicheradressen an. In Ihrer Antwort geben Sie den oder die **neuen Knoten** in der gleichen Schreibweise an wie in der Aufgabenstellung, also Speicheradresse gefolgt vom Inhalt des Knotens. Sofern erforderlich, muss Ihre Antwort auch **Änderungen an bestehenden Knoten** dokumentieren (auch hier Angabe der Speicheradresse und des veränderten Inhalts).

*[Antwortfeld, mehrzeilig]*

## A6: Structs und Pointer (15 Punkte)

### A6a (6 Punkte)

Füllen Sie die mit "..." gekennzeichneten Lücken in folgendem C-Programm so, dass die Strukturen für Person 1 und Person 2 korrekt allokiert, befüllt und ausgegeben werden, ohne Zeilen des bereits vorhandenen Codes zu ändern oder zu löschen. Falls die gekennzeichneten Lücken zur Beantwortung nicht ausreichen, können Sie dem Code weitere Zeilen hinzufügen. Vermeiden Sie unnötige Speicheranforderungen.

```c
#include <stdio.h>
#include <string.h>

struct person1
{
    unsigned int *age;
    char *name;
};

struct person2
{
    unsigned int age;
    char name[100];
};

int main(void)
{
    unsigned int age1 = 23;
    unsigned int age2 = 42;
    char* name1 = "Cathy";
    char* name2 = "Clark";

    // Person 1 (Cathy, 23) anlegen

    ... p1 = ...

    // Person 1 ausgeben:
    printf("1st: %d %s\n", ..., ...);

    // Person 2 (Clark, 42) anlegen:

    ... p2 = ...

    // Person 2 ausgeben:
    printf("2nd: %d %s\n", ..., ...);
}
```

Geben Sie hier den Inhalt der main-Funktion ein.

*[Antwortfeld, mehrzeilig]*

### A6b (4 Punkte)

Als **Alias** einer Variable bezeichnet man in C einen Ausdruck, der auf dasselbe Element im Speicher zugreift wie diese Variable, aber syntaktisch anders aussieht.

Gegeben sei eine Variable `i` und ein Pointer `p`, der auf `i` zeigt. Einige der folgenden Konstruktionen sind Aliase, einige sind keine Aliase, einige sind syntaktisch ungültig:

```text
(a) *p      (c) *&p       (e) *i      (g) *&i
(b) &p      (d) &*p       (f) &i      (h) &*i
```

Beantworten Sie die folgenden Fragen, indem Sie eine durch Kommas getrennte Liste von Buchstaben der Ausdrücke angeben; beispielsweise **a, c, e**, wenn sie der Meinung sind, dass `*p`, `*&p` und `*i` Aliase sind, also auf das gleiche Objekt verweisen.

Welche Ausdrücke sind Aliase von **i**?

*[Antwortfeld]*

Welche Ausdrücke sind Aliase von **p**?

*[Antwortfeld]*

### A6c (5 Punkte)

Implementieren Sie eine Funktion `int count(sllnode* head, int value)`, die zählt, wie oft ein bestimmter Wert in einer Liste vorkommt. Eine leere Liste ist daran erkennbar, dass head NULL ist. Diesen Fall muss Ihre Funktion korrekt behandeln. Verwenden Sie dabei folgende Datenstruktur:

```c
typedef struct sllnode {
    int value;
    sllnode *next;
} sllnode;

int count(sllnode *head, int value) {
    int counter = 0;
    // ...
    return counter;
}
```

*Es ist nicht erforderlich, diese Aufgabe in VS Code zu lösen. Zum Testen Ihres Codes kann es jedoch hilfreich sein.*

Kopieren Sie die Implementierung Ihrer Funktion *count* in dieses Feld:

*[Antwortfeld, mehrzeilig]*

## B1: Python und OOP (19 Punkte)

*Sie müssen diese Aufgaben nur lösen, wenn Sie die **9-ECTS-Prüfung** schreiben. Für die Lösung ist Python zu verwenden.*

### B1a (6 Punkte)

Schreiben Sie ein Python-Programm celsius.py, das einen **Temperaturwert F in der Einheit Grad Fahrenheit** einliest, diesen in die Einheit Grad Celsius (C) umrechnet und ausgibt. Die Formel für die Konvertierung ist

**`C = (F - 32) * 5/9`**

Benutzen Sie **input()** um die Temperatur einzulesen. Der Benutzer soll mit folgender Ausgabe zur Eingabe aufgefordert werde: **"Wert: "**. Falls Sie die Eingabeaufforderung mit der Funktion print() ausgeben, müssen Sie einen geeigneten *benannten Parameter* verwenden, damit die einzugebende Zahl direkt hinter der Eingabeaufforderung eingegeben werden kann, also in der gleichen Zeile. Andere Ansätze, um das gewünschte Verhalten zu erreichen, sind auch in Ordnung. Die Nutzung der cs50-Bibliothek ist bei dieser Teilaufgabe allerdings nicht zulässig. Geben Sie das Ergebnis **auf eine Dezimalstelle** gerundet aus. Beispiel:

```text
Wert: 68
Ausgabe: 20.0
```

Kopieren Sie Ihren gesamten Quellcode in dieses Feld.

*[Antwortfeld, mehrzeilig]*

### B1b (6 Punkte)

Schreiben Sie ein Programm **fizzbuzz.py**, das folgende Anforderungen erfüllt:

- Eine Zahl **n** vom Benutzer einliest. Anders als bei der vorigen Aufgabe sollen Sie dafür nun **get\_int** aus der cs50-Bibliothek verwenden.
- Die Zahlen von **1 bis einschließlich n** ausgibt, eine pro Zeile. Dabei sind folgende Sonderfälle zu beachten:
  
  - Wenn die Zahl durch 3 teilbar ist, gib die Zahl aus, gefolgt von einem Leerzeichen und dem String "Fizz".
  - Wenn die Zahl durch 5 teilbar ist, gib die Zahl aus, gefolgt von einem Leerzeichen und dem String "Buzz".
  - Wenn die Zahl sowohl durch 3 als auch durch 5 teilbar ist, gib die Zahl aus, gefolgt von einem Leerzeichen und dem String "FizzBuzz".

Beispiel:

```text
Eingabe: 7

Ausgabe:
1
2
3 Fizz
4
5 Buzz
6 Fizz
7
```

Kopieren Sie ihren gesamten Quellcode in dieses Feld.

*[Antwortfeld, mehrzeilig]*

### B1c (3 Punkte)

Schreiben Sie ein Programm **student.py** eine Klasse **Student**, die bei der Initialisierung zwei Parameter entgegennimmt: Matrikelnummer (**mat\_num**) und Name (**name**) entgegennimmt. Die übergebenen Werte sollen als Attribute gespeichert werden. Es ist nicht erforderlich, Properties zu verwenden.

Fügen Sie am Ende der Datei Code hinzu, der ein Student-Objekt mit dem Namen **Max Mustermann** und der Matrikelnummer **123456** erstellt und die Matrikelnummer dieses Objekts auf der Standardausgabe ausgibt.

Kopieren Sie den gesamten Quellcode von **student.py** in dieses Feld.

*[Antwortfeld, mehrzeilig]*

### B1d (4 Punkte)

Erweitern Sie **student.py** wie folgt.

Fügen Sie der Klasse Student eine Methode **add\_grade(course, grade)** hinzu. add\_grade nimmt einen Kursnamen (String) und eine Note (Float) als Parameter entgegen. add\_grade speichert die Note in einem Dictionary-Attribut **grades**, wobei der Kursname als Schlüssel verwendet wird und die Note als Wert.

*grades* soll beim Initialisieren von Objekten als leeres Dictionary angelegt werden.

Fügen Sie eine weitere Methode **best()** hinzu, die die beste (also betragsmäßig kleinste) Note berechnet und zurückgibt. Falls noch keine Noten eingetragen worden sind, soll die Methode den Wert 0 zurückgeben.

Nach der bestehenden Klassen-Definition und dem bereits vorhandenen Code, der die Matrikelnummer von Max Mustermann ausgibt, fügen Sie dem bereits erstellten Student-Objekt drei Noten hinzu:

- "DM" mit Note 1.7
- "EDS" mit Note 1.3
- "Inf-Einf-B" mit Note 2.0

Rufen Sie die Methode best() auf, um die beste Note (nicht den Kursnamen) auf der Standardausgabe auszugeben.

*Bei Problemen mit der Implementierung der Student-Klasse in der vorigen Aufgabe können Sie in dieser Aufgabe Teilpunkte erhalten, indem Sie ein Dictionary als globale Variable **grades** anlegen und add\_grade(dict, course, grade) und best(dict) als eigenständige Funktionen außerhalb einer Klasse implementieren. add\_grade soll die eingetragenen Noten in **grades** speichern; best soll sie daraus auslesen.*

Kopieren Sie den gesamten Quellcode von **student.py** in dieses Feld.

*[Antwortfeld, mehrzeilig]*

## B2: Wetterdaten (21 Punkte)

*Sie müssen diese Aufgaben nur lösen, wenn Sie die **9-ECTS-Prüfung** schreiben.*

In dieser Aufgabe bearbeiten Sie eine Flask-Anwendung, die die aktuelle Temperatur in verschiedenen Städten anzeigt. Für diese Aufgabe stellen wir Ihnen Quellcode zur Verfügung, den Sie vervollständigen müssen. Wechseln Sie dazu im Terminal in das Verzeichnis **exam-files/temperature**, das sich in Ihrem Homeverzeichnis */home/student* befindet.

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 <kbd>Strg</kbd>-Taste auf die URL (*Running on ...*), die Flask nach dem Start anzeigt. Um Flask zu beenden, verwenden Sie die Tastenkombination <kbd>Strg-C</kbd>.

Die Anwendung enthält zwei Routen:

- Die Route **index**, die nur GET-Requests annimmt, alle gespeicherten Städte einliest, und diese mit Hilfe eines Jinja2-Templates in einer Tabelle ausgibt.
- Die Route **add\_city** akzeptiert sowohl GET- als auch POST-Requests. Bei einem **GET-Request** wird ein HTML-Formular generiert, das einen Namen und eine Temperatur entgegennimmt. Bei **POST-Requests** werden diese Daten aus dem Formular gelesen und an eine Datei angehängt.

Zur Datenspeicherung soll eine JSON-Datei verwendet werden, die folgenden Aufbau hat:

`[{"name": "Berlin", "temperature": 8}, {"name": "Hamburg", "temperature": 8}, ...]`

### B2a (6 Punkte)

Machen Sie sich mit dem vorhandenen Code vertraut. Vervollständigen Sie dann zunächst die **index-Route**. Rufen Sie dazu zunächst die Funktion **read\_cities** auf, um die Daten einzulesen. Anschließend müssen Sie das Template **index.html** so anpassen, dass die gelesenen Daten beim Aufruf der index-Route im Browser in der Tabelle ausgegeben werden.

Fügen Sie hier nur den Code der **Funktion index** ein.

*[Antwortfeld, mehrzeilig]*

Fügen Sie hier den gesamten Inhalt Ihres Templates **index.html** ein.

*[Antwortfeld, mehrzeilig]*

### B2b (5 Punkte)

Erstellen Sie im Template **add\_city.html** nun ein HTML-Formular, das beim Absenden einen POST-Request erzeugt (*das Rendern dieses Templates und die Behandlung des POST-Requests erfolgen erst in Teilaufgabe B2c*). Das Formular soll zwei **input-Felder** mit den *name*-Attributen **name** und **temperature** sowie einen **Button** zum Absenden des Forms enthalten. Eine clientseitige Validierung der Eingaben ist nicht erforderlich.

Fügen Sie hier den gesamten Inhalt Ihres Templates **add\_city.html** ein.

*[Antwortfeld, mehrzeilig]*

### B2c (6 Punkte)

Passen Sie die Funktion **add\_city** nun so an, dass diese **nur GET- und POST-Requests** akzeptiert.

Wenn die Funktion per **GET** aufgerufen wird, soll das Template **add\_city.html** gerendert werden (das Template soll in dieser Aufgabe nicht mehr angepasst werden).

Beim Aufruf per **POST** sollen **name** und **temperature** aus dem HTTP-Request extrahiert und der Datei **cities.json** hinzugefügt werden. Vervollständigen Sie dazu die bereits vorhandene Funktion **write\_cities** und rufen sie sie auf. Nach der Aktualisierung der Datei soll die Liste der Städte (index-Route) angezeigt werden. Eine serverseitige Validierung der Eingaben ist nicht erforderlich.

Fügen Sie hier den gesamten Inhalt der Datei **app.py** ein.

*[Antwortfeld, mehrzeilig]*

### B2d (4 Punkte)

Zum Abschluss folgen Fragen zu HTTP und CSS.

Welchen HTTP-Status-Code liefert ein Webserver zurück, wenn eine angeforderte Seite **nicht gefunden** wird?

Geben Sie die Nummer des Status-Codes ein.

*[Antwortfeld]*

Welchen HTTP-Status-Code liefert ein Webserver zurück, wenn eine Anfrage **erfolgreich** war?

Geben Sie die Nummer des Status-Codes ein.

*[Antwortfeld]*

Nehmen Sie an, für ein `p`-Tag (Klasse: "absatz", ID: "#absatz1") werden in einer Webseite an unterschiedlichen Stellen sich widersprechende CSS-Eigenschaften festgelegt, etwa verschiedene Schriftfarben (*color*). Welche Schriftfarbe wird gemäß der CSS-Spezifizitätsregelung vom Browser angezeigt?

- A. Die im Tag-Selektor definierte: `p { ... }`
- B. Die im Klassen-Selektor definierte: `.absatz { ... }`
- C. Die im ID-Selektor definierte: `#absatz1 { ... }`
- D. Die im style-Attribut des Absatzes definierte `<p style="...">`

Antworten Sie mit einem der Buchstaben A, B, C oder D.

*[Antwortfeld]*
