# Warm-ups (freiwillig)

Quelle: https://dev.inf.zone/exercises/07/warm-ups/

**Wozu das Ganze?**

Die Warm-ups führen die neuen Sprachmittel aus der Vorlesung [4.5 Memory (Fortsetzung)](https://dev.inf.zone/lectures/4.5-morememory/) in kleinen Schritten ein. Sie sind freiwillig, zählen nicht für die Bonuspunkte und sind nicht prüfungsrelevant. Nutzen Sie sie, wenn Sie bei einer Aufgabe nicht wissen, wie Sie anfangen sollen. Wenn Sie direkt loslegen können, fangen Sie mit den Aufgaben an.

Sie müssen nicht alle Warm-ups machen. Suchen Sie sich in der Tabelle das heraus, was Ihnen für eine Aufgabe fehlt:

| | Übt | Hilft bei |
|---|---|---|
| [Warm-up 1](#warm-up-1) | In eine Datei schreiben | Lautstärke, Wiederherstellung |
| [Warm-up 2](#warm-up-2) | Aus einer Datei lesen mit `fread` | Lautstärke, Wiederherstellung |
| [Warm-up 3](#warm-up-3) | Eine Datei kopieren | Lautstärke, Wiederherstellung |
| [Warm-up 4](#warm-up-4) | Eine Datei Zeichen für Zeichen verschlüsseln | Lautstärke |

Legen Sie für die Warm-ups eine eigene Datei an, zum Beispiel `warmup_aufgaben_2.c` für Übung 2, im selben Ordner wie Ihre Übungsaufgaben. Die meisten Warm-ups bauen aufeinander auf: Sie ergänzen die Datei Schritt für Schritt. Lösungen gibt es für die Warm-ups nicht. Unter „Wo zu finden?“ steht jeweils, wo das Thema in Vorlesung und Shorts vorkommt. Mehr dazu im [FAQ zu den Warm-ups](https://dev.inf.zone/faq/uebung-warm-up/).

## Warm-up 1: In eine Datei schreiben

Kopieren Sie folgendes Code-Snippet in Ihre Warm-up-Datei:

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

int main(int argc, char *argv[])
{
    string hello = "Hello World!\n";

    char buffer;

    string file_name = "hello.txt";

    // File-Pointer `hello_file` mit `fopen` mit Dateinamen `file_name` im Modus "w";
    // EINFÜGEN (1)

    // Wichtig: Immer prüfen, ob `fopen` erfolgreich einen entsprechenden File-Pointer erstellen konnte;
    if (hello_file == NULL)
    {
        printf("ERROR accessing file: %s\n", file_name);
        return 1;
    }

        // Inhalt von `hello` mit `fwrite` in `hello_file` schreiben;
        // EINFÜGEN (2)

    // Datei schließen mit `fclose`;
    // EINFÜGEN (3)

    return 0;
}
```

**EINFÜGEN (1)**: Erstellen Sie einen File-Pointer `hello_file` mit `fopen` im Modus `"w"` (Schreiben). In diesem Modus wird eine noch nicht existierende Datei automatisch erstellt. *Eine bereits existierende Datei mit diesem Namen wird überschrieben.* Den Dateinamen `hello.txt` können Sie über die bereits initialisierte Variable `file_name` übergeben.

**EINFÜGEN (2)**: Nutzen Sie `fwrite`, um den in `hello` initialisierten String in die Datei zu schreiben. Lesen Sie ggf. noch einmal die erwarteten Argumente für `fwrite` im [Handbuch](https://manual.cs50.io/3/fwrite) nach. Die Anzahl der zu schreibenden Elemente der Größe `char` kennen wir in diesem Fall - diese erhalten wir mit `strlen(hello)`. [Erinnern Sie sich daran](https://dev.inf.zone/lectures/4-memory/notes4/#strings), dass ein *String* letztlich ein `char`-Pointer ist und daher bereits eine Adresse repräsentiert.

**EINFÜGEN (3)**: Am Ende des Programms muss eine geöffnete Datei immer mit `fclose` geschlossen werden.

Nach dem Ausführen des Programms sollten Sie eine Datei `hello.txt` mit dem Inhalt `Hello World!` im Dateibrowser finden.

**Wo zu finden?**

Bei Problemen und Unklarheiten schauen Sie sich am besten noch einmal die Notizen der Vorlesung [4.5 Memory (Fortsetzung)](https://dev.inf.zone/lectures/4.5-morememory/) zu [Datei-Eingabe und -Ausgabe](https://dev.inf.zone/lectures/4.5-morememory/notes45/#datei-eingabe-und--ausgabe-file-io), die Notizen der Vorlesung [4. Memory](https://dev.inf.zone/lectures/4-memory/) zur [File I/O](https://dev.inf.zone/lectures/4-memory/notes4/#file-io) sowie das Short zu [File Pointern](https://dev.inf.zone/lectures/4-memory/short-4-6-file-pointer/) an.

## Warm-up 2: Aus einer Datei lesen mit `fread`

Nachdem wir nun bereits eine Datei erstellt haben, können wir auch aus dieser Datei lesen.

Ändern Sie beim Aufruf von `fopen` für `hello_file` den Modus, indem Sie statt `"w"` nun `"r"` (Lesen) übergeben, da wir nun mit dem Programm aus der Datei "hello.txt" lesen wollen. Kommentieren Sie den Aufruf von `fwrite` aus [Warm-up 1](#warm-up-1) aus. Ansonsten können wir den bestehenden Code direkt weiterverwenden.

[Wissen Sie noch](https://dev.inf.zone/lectures/4-memory/short-4-6-file-pointer/), was `fread` zurückgibt? Ansonsten können Sie auch einmal einen Blick in den Abschnitt des [Handbuchs](https://manual.cs50.io/3/fread#return-value) werfen, der sich mit dem Rückgabewert von `fread` beschäftigt.

**Was gibt `fread` zurück?**

![Erster Teil des Handbucheintrags zum return-Wert von fread](https://dev.inf.zone/exercises/07/warm-ups/fread_handbuch_1.png)

**Was gibt `fread` zurück, wenn eine Datei vollständig eingelesen wurde?**

![Zweiter Teil des Handbucheintrags zum return-Wert von fread](https://dev.inf.zone/exercises/07/warm-ups/fread_handbuch_2.png)

Außerdem merkt sich die mit `fopen` geöffnete Datei, bis zu welcher Stelle schon gelesen wurde. Bei weiteren Aufrufen der Funktion `fread` auf diese Datei werden daher jeweils die Bytes nach den bereits gelesenen Bytes eingelesen.

Was geschieht, wenn `fread` direkt in der Bedingung einer `while`-Schleife aufgerufen wird, z.B. so:
```c
    while (fread(&buffer, sizeof(char), 1, hello_file))
    {

    }
```
**Erklärung**

Mit dieser `while`-Schleife lesen wir `char` für `char`, also jeweils ein Byte, aus der Datei `hello_file` aus. Der `char` wird jeweils in der Variable `buffer` zwischengespeichert. Daher hat in diesem Fall unsere Puffer-Variable auch die Größe von einem `char`, d.h. einem Byte. *Wollten wir etwa den Umfang von 8 Bytes, d.h. 8 `char`s, auf einmal "puffern", würden wir demnach etwa ein `char`-Array der Größe `8`, also `char buffer[8]`, benötigen. Natürlich müssten wir dann zusätzlich entweder die Größe (`size`) der gelesenen Daten oder die Anzahl der auf einmal zu lesenden Elemente (`nmemb`) entsprechend anpassen (siehe [Handbuch](https://manual.cs50.io/3/fread#description)).* Sind alle Bytes gelesen, gibt `fread` schließlich `0` zurück, da `0` Elemente der Größe "1 Byte" gelesen wurden. Der zurückgegebene Wert `0` wird in der Bedingung als `false` interpretiert, weshalb die Schleife dann beendet wird.

Geben Sie innerhalb der Schleife den Wert von `buffer` jeweils mit
```c
printf("%c", buffer);
```
aus. Es sollte also
```plaintext
Hello World!
```
ausgegeben werden.

**Wo zu finden?**

Bei Problemen und Unklarheiten schauen Sie sich am besten noch einmal die Notizen der Vorlesung [4.5 Memory (Fortsetzung)](https://dev.inf.zone/lectures/4.5-morememory/) zu [Datei-Eingabe und -Ausgabe](https://dev.inf.zone/lectures/4.5-morememory/notes45/#datei-eingabe-und--ausgabe-file-io), die Notizen der Vorlesung [4. Memory](https://dev.inf.zone/lectures/4-memory/) zur [File I/O](https://dev.inf.zone/lectures/4-memory/notes4/#file-io) sowie das Short zu [File Pointern](https://dev.inf.zone/lectures/4-memory/short-4-6-file-pointer/) an.

## Warm-up 3: Eine Datei kopieren

Anstatt die zwischengespeicherten Werte auf der Konsole auszugeben, können wir diese auch in eine neue Datei schreiben - also eine Kopie der gelesenen Datei erstellen.

Erstellen Sie einen **zweiten** File-Pointer `hello_file_copy`, der eine Datei mittels `fopen` im Modus `w` (Schreiben) erstellt. Übergeben Sie als Dateinamen `"hello-copy.txt"`.

Vergessen Sie nicht zu prüfen, ob der `return`-Wert von `fopen`, also `hello_file_copy`, gleich `NULL` ist. Beenden Sie in diesem Fall das Programm. Fügen Sie am Ende zudem den Aufruf von `fclose` zum Schließen der Datei ein.

Schreiben Sie in der Schleife jeweils den Inhalt von `buffer` mit `fwrite` in die Datei `hello_file_copy`.

In der neu erstellten Datei "hello-copy.txt" sollte nach dem Ausführen nun auch `Hello World!` stehen. Ergänzen Sie den Inhalt von "hello.txt" und führen Sie das Programm erneut aus. Der zusätzliche Text sollte auch in "hello-copy.txt" zu sehen sein.

In welchem Fall ist also der Ansatz mit der `while`-Schleife vorteilhaft?

**Wo zu finden?**

Bei Problemen und Unklarheiten schauen Sie sich am besten noch einmal die Notizen der Vorlesung [4.5 Memory (Fortsetzung)](https://dev.inf.zone/lectures/4.5-morememory/) zu [Datei-Eingabe und -Ausgabe](https://dev.inf.zone/lectures/4.5-morememory/notes45/#datei-eingabe-und--ausgabe-file-io), die Notizen der Vorlesung [4. Memory](https://dev.inf.zone/lectures/4-memory/) zur [File I/O](https://dev.inf.zone/lectures/4-memory/notes4/#file-io) sowie das Short zu [File Pointern](https://dev.inf.zone/lectures/4-memory/short-4-6-file-pointer/) an.

## Warm-up 4: Eine Datei Zeichen für Zeichen verschlüsseln

Wir lesen also letztlich Zeichen für Zeichen aus der Datei aus und schreiben wieder Zeichen für Zeichen in die neue Datei. Vielleicht hat es in Ihrem Kopf bereits zu rotieren begonnen: Ja, so etwas Ähnliches hatten wir bereits in einer der Aufgaben! In `Cäsar` haben wir Zeichen für Zeichen über einen String iteriert und jeweils Zeichen für Zeichen auf der Konsole ausgegeben. Mit einem Unterschied: *Zwischen* diesen Schritten haben wir das Zeichen verändert.

Natürlich können wir auch unsere Puffer-Variable `buffer` verändern, *bevor* wir sie in die Datei schreiben.

Kopieren Sie sich die `rotate()` Funktion aus `Cäsar` in Ihre Datei und rufen Sie
```c
buffer = rotate(buffer, 1);
```
auf, bevor Sie den Wert von `buffer` in die Datei schreiben. *Fügen Sie außerdem noch fehlende Header-Dateien und Konstanten zur Verwendung von `rotate()` ein.*

**Sie haben keine `rotate`-Funktion aus `Cäsar`?**

Lagern Sie zur Übung den entsprechenden Code aus Ihrer `Cäsar`-Lösung in eine entsprechende Funktion mit der Signatur `char rotate(char letter, int key)` aus. Diese Funktion nimmt einen Buchstaben und einen Schlüssel, d.h. die Zahl der Verschiebung, entgegen und gibt den verschobenen Buchstaben zurück, wobei Groß- und Kleinschreibung berücksichtigt wird und alle nicht-alphabetischen Zeichen unverändert bleiben (siehe [Cäsar](https://dev.inf.zone/exercises/04/caesar/#verwenden-des-schlüssels)).

**Alternativ hier kopieren bzw. vergleichen**

```c
// Rotates a character in the alphabet n times
char rotate(char letter, int n)
{
    // Check if the character is an uppercase or lowercase letter
    if (isupper(letter))
    {
        // Rotate the character within the uppercase alphabet range
        return 'A' + (letter - 'A' + n) % ALPHASIZE;
    }
    else if (islower(letter))
    {
        // Rotate the character within the lowercase alphabet range
        return 'a' + (letter - 'a' + n) % ALPHASIZE;
    }

    // If the character is not a letter, return it unchanged
    return letter;
}
```

In "hello-copy.txt" sollte nach Ausführung des Programms statt `Hello World!` nun `Ifmmp Xpsme!` stehen.

Damit haben wir jetzt bereits ein kleines, minimalistisches Programm erstellt, um einfache Textdateien mit der `Cäsar`-Methode zu verschlüsseln. In den Übungsaufgaben brauchen Sie nun etwas Einarbeitungszeit - lassen Sie sich davon nicht abschrecken! -, aber dafür können Sie dann sogar Audiodateien manipulieren – und schließlich sogar Daten von einem Speicherkartenabbild wiederherstellen!

<br>
