Zum Inhalt springen

Warm-ups (freiwillig)

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

ÜbtHilft bei
Warm-up 1Adressen ausgeben mit &Vorlesung 4 (Pointer)
Warm-up 2Pointer: über eine Adresse lesen und schreibenVorlesung 4 (Pointer)
Warm-up 3Ein Bild als zweidimensionales Array von Structs: Pixel lesen und ändernFilter (grayscale, sepia, reflect)
Warm-up 4Nachbarpixel finden, ohne über den Bildrand zu greifenFilter (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.

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.

#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 an.

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

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

   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
Wo zu finden?

Bei Problemen und Unklarheiten schauen Sie sich am besten noch einmal die Notizen der Vorlesung 4. Memory zum Speicher und Pointern sowie das Short zu Pointern 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:

#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:

$ ./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:

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:

 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:

 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 und im Short zu eigenen Datentypen. Wie man ein Array an eine Funktion übergibt, zeigt die Funktion average in den Notes zur Vorlesung 2. 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);:

   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:

   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.

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 der Notes zur Vorlesung 2. Das Raster mit dem 3×3-Kasten ist in der Aufgabe Filter bei blur abgebildet.

Diese Seite als Markdown: ansehen herunterladen