# Warm-ups (freiwillig)

Quelle: https://inf.zone/exercises/05/warm-ups/

**Wozu das Ganze?**

Die Warm-ups führen die neuen Sprachmittel aus der Vorlesung [4. Memory](https://inf.zone/lectures/4-memory/) in kleinen Schritten ein: Warm-ups 1 und 2 üben Pointer, Warm-ups 3 und 4 den Umgang mit einem Bild als zweidimensionalem Array, den Sie für Filter brauchen. Sie sind freiwillig und spielen für die [Joker-Regel](https://inf.zone/extras/exam/#joker-regel) keine Rolle. 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) | Adressen ausgeben mit `&` | Vorlesung 4 (Pointer) |
| [Warm-up 2](#warm-up-2) | Pointer: über eine Adresse lesen und schreiben | Vorlesung 4 (Pointer) |
| [Warm-up 3](#warm-up-3) | Ein Bild als zweidimensionales Array von Structs: Pixel lesen und ändern | Filter (grayscale, sepia, reflect) |
| [Warm-up 4](#warm-up-4) | Nachbarpixel finden, ohne über den Bildrand zu greifen | Filter (blur) |

Legen Sie für die Warm-ups eine eigene Datei an, zum Beispiel `warmup_aufgaben_1.c` für Übung 1, 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://inf.zone/faq/uebung-warm-up/).

## Warm-up 1: Adressen ausgeben mit `&`

Kopieren Sie das folgende Code-Snippet und ersetzen Sie den Kommentar, sodass die Adresse von `buffer` ausgegeben wird. Erinnern Sie sich, dass Sie mit `&` auf die Adresse einer Variablen zugreifen können.

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

int main(void)
{
    char buffer;

    printf("An der Adresse %p liegt der Inhalt '%c'.\n", /* Adresse des Buffers */, buffer);

    return 0;
}
```

Führen Sie das Programm mehrfach aus. Was fällt Ihnen auf?

**Wo zu finden?**

Bei Problemen und Unklarheiten schauen Sie sich am besten noch einmal die Notizen zu den Programmen `addresses.c` und `garbage.c` aus der Vorlesung 4. Memory sowie das Short zu [Pointern](https://inf.zone/lectures/4-memory/short-4-2-pointer/) an.

## Warm-up 2: Pointer: über eine Adresse lesen und schreiben

Fügen Sie zwischen `printf` und `return` folgenden Code ein:

```c
   char *pointer = &buffer;

   *pointer = 'A';

   printf("An der Adresse %p (Ausgabe `pointer`) liegt der Inhalt '%c' (Ausgabe `buffer`) / '%c' (Ausgabe `*pointer`).\n", pointer, buffer, *pointer);

   buffer = 'B';

   printf("An der Adresse %p (Ausgabe `pointer`) liegt der Inhalt '%c' (Ausgabe `buffer`) / '%c' (Ausgabe `*pointer`).\n", pointer, buffer, *pointer);
```

Führen Sie das Programm aus und vollziehen Sie die Ausgabe nach. Was passiert jeweils bei den Zuweisungen?

**Erinnerung:** Ein Pointer ist letztlich nur eine Variable, deren Inhalt eine *Adresse* ist. Der Typ des Pointers bezieht sich dabei auf den Inhalt, der an dieser *Adresse* zu finden ist. Dadurch weiß der Compiler beim Dereferenzieren, wie viele Bytes ab dieser Adresse gelesen werden müssen, um einen Wert des entsprechenden Typs zu erhalten. Bei einem `char`-Pointer wäre dies z. B. 1 Byte (8 Bit), da ein `char` in C 1 Byte groß ist.

**Visualisieren Sie sich dies am besten einmal mit einer Handzeichnung**

-   Welche Werte stehen an der jeweiligen Stelle?
-   Worauf kann mit welcher Syntax zugegriffen werden? Ordnen Sie `buffer`, `&buffer`, `pointer`, `&pointer` und `*pointer` den entsprechenden Boxen zu.
-   Nutzen Sie Pfeile, um Verbindungen zwischen den Inhalten zu visualisieren.
-   Vollziehen Sie dann den Code (d. h. die Zuweisungen und die daraus resultierenden Veränderungen) anhand Ihrer Zeichnung nach.
![Adresse, Inhalt und Pointer](https://inf.zone/exercises/05/warm-ups/pointers.png)

**Wo zu finden?**

Bei Problemen und Unklarheiten schauen Sie sich am besten noch einmal die Notizen der Vorlesung [4. Memory](https://inf.zone/lectures/4-memory/) zum Speicher und Pointern sowie das Short zu [Pointern](https://inf.zone/lectures/4-memory/short-4-2-pointer/) an.

## Warm-up 3: Ein Bild als Tabelle von Pixeln

In Filter liegt das Bild als zweidimensionales Array `image` vor: `image[i]` ist die Zeile `i`, `image[i][j]` der Pixel in Zeile `i` und Spalte `j`. Jeder Pixel ist ein `RGBTRIPLE`, ein struct mit drei Farbwerten zwischen 0 und 255. Den Zugriff darauf üben Sie hier an einem kleinen Bild mit 3 Zeilen und 4 Spalten, ganz ohne BMP-Datei.

Legen Sie für die Warm-ups 3 und 4 eine neue Datei `warmup_bild.c` an und kopieren Sie dieses Gerüst hinein. Den Typ `RGBTRIPLE` haben wir aus der Datei `bmp.h` im Filter-Gerüst übernommen:

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

// wie in bmp.h aus dem Filter-Gerüst
typedef uint8_t BYTE;

typedef struct
{
    BYTE rgbtBlue;
    BYTE rgbtGreen;
    BYTE rgbtRed;
} RGBTRIPLE;

int main(void)
{
    // 3 Zeilen (height), 4 Spalten (width)
    // Reihenfolge in den inneren Klammern wie im struct: Blau, Grün, Rot
    RGBTRIPLE image[3][4] = {
        {{0, 0, 255}, {0, 255, 0}, {255, 0, 0}, {255, 255, 255}},     // rot, grün, blau, weiß
        {{0, 0, 0}, {128, 128, 128}, {0, 255, 255}, {0, 165, 255}},    // schwarz, grau, gelb, orange
        {{0, 0, 139}, {208, 224, 64}, {128, 0, 128}, {203, 192, 255}}  // dunkelrot, türkis, lila, rosa
    };

    return 0;
}
```

Geben Sie zuerst die drei Farbwerte des Pixels `image[1][2]` aus:

```plaintext
$ ./warmup_bild
Rot: 255, Grün: 255, Blau: 0
```

Welcher Pixel aus den Kommentaren ist das? Und warum steht er im Code als `{0, 255, 255}`?

Schreiben Sie dann eine Funktion, die die Rotwerte aller Pixel als Tabelle ausgibt, eine Bildzeile pro Textzeile. Verwenden Sie dieselbe Parameterliste wie die Funktionen in `helpers.c` von Filter:

```c
void zeige_rot(int height, int width, RGBTRIPLE image[height][width])
```

Mit dem Aufruf `zeige_rot(3, 4, image);` in `main` erscheint nach der Zeile mit den Farbwerten:

```plaintext
 255   0   0 255
   0 128 255 255
 139  64 128 255
```

Schreiben Sie zum Schluss eine zweite Funktion `abdunkeln` mit derselben Parameterliste, die bei jedem Pixel alle drei Farbwerte halbiert. Ganzzahlige Division reicht, Nachkommastellen fallen weg. Rufen Sie in `main` nacheinander `zeige_rot`, `abdunkeln` und noch einmal `zeige_rot` auf. Die zweite Tabelle sieht so aus:

```plaintext
 127   0   0 127
   0  64 127 127
  69  32  64 127
```

`abdunkeln` gibt nichts zurück. Warum sieht `main` die geänderten Werte trotzdem?

**Tipp**

-   Über ein zweidimensionales Array laufen Sie mit zwei verschachtelten Schleifen: außen über die Zeilen (`i` von 0 bis `height - 1`), innen über die Spalten (`j` von 0 bis `width - 1`).
-   Der Zeilenumbruch gehört in die äußere Schleife, hinter die innere.
-   `%4i` gibt eine Zahl rechtsbündig mit vier Zeichen Breite aus. So stehen die Spalten untereinander.
-   Stehen Ihre Funktionen unterhalb von `main`, braucht der Compiler oberhalb von `main` ihre Prototypen, so wie in `helpers.h`.

**Wo zu finden?**

Zweidimensionale Arrays stehen am Anfang der Notes zur Vorlesung 4, structs und die Punktschreibweise in den [Notes zur Vorlesung 3](https://inf.zone/lectures/3-algorithmen/notes3/#structs) und im Short zu [eigenen Datentypen](https://inf.zone/lectures/4-memory/short-4-3-eigene-typen/). Wie man ein Array an eine Funktion übergibt, zeigt die Funktion `average` in den [Notes zur Vorlesung 2](https://inf.zone/lectures/2-arrays/notes2/#arrays-arrays). Zur Frage am Ende hilft der Abschnitt Swap.

## Warm-up 4: Nachbarpixel finden, ohne über den Bildrand zu greifen

Für blur brauchen Sie zu jedem Pixel alle Pixel in dem 3×3-Kasten um ihn herum. In der Mitte des Bildes sind das 9, am Rand weniger: Eine Zeile `-1` oder eine Spalte `width` gibt es nicht. C bemerkt es aber nicht, wenn Sie trotzdem `image[-1][0]` lesen. Sie bekommen dann Werte, die zufällig an dieser Stelle im Speicher liegen. Deshalb müssen Sie vor jedem Zugriff selbst prüfen, ob Zeile und Spalte im Bild liegen.

Schreiben Sie eine Funktion `void zaehle_nachbarn(int height, int width)`, die für jeden Pixel ausgibt, wie viele Pixel seines 3×3-Kastens im Bild liegen; der Pixel selbst zählt mit. Für das Bild aus Warm-up 3 ergibt der Aufruf `zaehle_nachbarn(3, 4);`:

```plaintext
   4   6   6   4
   6   9   9   6
   4   6   6   4
```

Prüfen Sie mit `zaehle_nachbarn(5, 6);`, ob Ihre Funktion auch für andere Bildgrößen stimmt:

```plaintext
   4   6   6   6   6   4
   6   9   9   9   9   6
   6   9   9   9   9   6
   6   9   9   9   9   6
   4   6   6   6   6   4
```

Die Funktion braucht nur die Maße des Bildes, nicht die Pixel selbst. Bei blur lesen Sie an dieser Stelle zusätzlich die Farbwerte der Nachbarn. Warum Sie dort außerdem eine Kopie des Bildes brauchen, steht in der Hilfestellung zu blur in der Aufgabe [Filter](https://inf.zone/exercises/05/filter/).

**Tipp**

-   Zu den beiden Schleifen über Zeilen und Spalten kommen zwei weitere für den Kasten: Zeile `i - 1` bis `i + 1`, Spalte `j - 1` bis `j + 1`.
-   Eine Zeile `zeile` liegt im Bild, wenn `zeile >= 0` und `zeile < height` gilt. Für Spalten gilt dasselbe mit `width`. Alle vier Bedingungen verbinden Sie mit `&&`.
-   Der Zähler muss für jeden Pixel wieder bei 0 anfangen.

**Wo zu finden?**

Was passiert, wenn man über die Grenzen eines Arrays hinaus liest, steht im Abschnitt [Arrays und Speichergrenzen](https://inf.zone/lectures/2-arrays/notes2/#arrays-und-speichergrenzen) der Notes zur Vorlesung 2. Das Raster mit dem 3×3-Kasten ist in der Aufgabe [Filter](https://inf.zone/exercises/05/filter/) bei blur abgebildet.
