# Notes 1

Quelle: https://inf.zone/lectures/1-c/notes1/

**Aktualisiert am 20. Oktober.** Seit dem Entwurf haben wir fast jeden Abschnitt überarbeitet; die Seite entspricht jetzt der Vorlesung vom 19. Oktober.

*Sie können diese Seite ausdrucken oder mit einem PDF-Drucker in ein PDF umwandeln, um Ihre eigenen Notizen hinzuzufügen.*

*Sie können bereits C? Schauen Sie sich doch einmal die [Shorts](https://inf.zone/lectures/1-c/#shorts) zu dieser Vorlesung an. Gerade in den „Drei Extra-Minuten“ gibt es ein paar anspruchsvollere Inhalte.*

## Willkommen!

- In der ersten Sitzung haben Sie nach Scratch Ihr erstes Programm in C gesehen: `hello.c`, geschrieben, kompiliert, ausgeführt und einmal repariert. Das steht in den Notes 0: [Maschinencode und Quelltext](https://inf.zone/lectures/0-willkommen/notes0/#maschinencode-quelltext), [Hello World in C](https://inf.zone/lectures/0-willkommen/notes0/#c-hello-world), [Funktionen](https://inf.zone/lectures/0-willkommen/notes0/#c-funktionen), [Fehlermeldungen lesen und verstehen](https://inf.zone/lectures/0-willkommen/notes0/#c-fehlermeldungen) und [Variablen](https://inf.zone/lectures/0-willkommen/notes0/#c-variablen).
- In dieser Sitzung geht es mit C weiter, mit Typen, Bedingungen, Schleifen und eigenen Funktionen.
- Alle grundlegenden Programmierkonzepte, die in Scratch vorgestellt werden, können beim Erlernen einer beliebigen Programmiersprache verwendet werden.
- Heute werden Sie nicht nur lernen, wie man programmiert, sondern auch, wie man guten Code schreibt.
  - Die **Codequalität** kann nach drei Kriterien bewertet werden. Erstens, hinsichtlich der **Korrektheit**, was die Frage "Läuft der Code wie beabsichtigt?" betrifft. Zweitens kann man sich das **Design** ansehen, also sich fragen: "Wie gut ist der Code aufgebaut?". Schließlich bezieht sich die Frage nach dem **Stil** darauf, wie ästhetisch ansprechend und konsistent der Code geschrieben ist. Beim Programmieren können drei Hauptkategorien von Problemen auftreten:
  - **Syntaxfehler**: Der Code lässt sich nicht ausführen, weil er gegen die Regeln der Programmiersprache verstößt. Beispiele: fehlendes Semikolon, falsche Klammern, Tippfehler in Funktionsnamen. Diese Fehler sind am **leichtesten** zu finden, weil es Fehlermeldungen gibt (z.B. vom C-Compiler, wie wir heute noch öfter sehen werden).
  - **Logikfehler**: Der Code kompiliert, aber verhält sich zur Laufzeit nicht wie gewünscht. Beispiel: Das Programm berechnet eine falsche Summe oder beendet sich vorzeitig. Diese Fehler sind **schwieriger** zu finden, weil das Programm läuft – nur eben falsch.
  - **Designfehler**: Der Code kompiliert und funktioniert korrekt, ist aber **schlecht strukturiert**. Beispiele: unnötige Wiederholungen, redundante Prüfungen, unklare Variablennamen, fehlende Abstraktion. Diese Fehler sind am **schwierigsten** zu erkennen, weil das Programm oberflächlich betrachtet "funktioniert". Aber schlechtes Design macht Code schwer wartbar, fehleranfällig und unverständlich für andere (und für Ihr zukünftiges Ich!).

In diesem Kurs lernen Sie, alle drei Problemkategorien zu erkennen und zu vermeiden.

**Selbsttest:**

Nach welchen drei Kriterien bewertet man Codequalität?

**Antwort:**

**Korrektheit** (läuft der Code wie beabsichtigt?), **Design** (wie gut ist er aufgebaut?) und **Stil** (wie ästhetisch und konsistent ist er geschrieben?).

**Selbsttest:**

Warum sind Syntaxfehler am leichtesten zu finden?

**Antwort:**

Weil es **Fehlermeldungen** gibt, etwa vom C-Compiler.

**Selbsttest:**

Wie nennt man einen Fehler, bei dem der Code kompiliert, sich zur Laufzeit aber nicht wie gewünscht verhält?

**Antwort:**

**Logikfehler**.

**Selbsttest:**

Warum sind Designfehler am schwierigsten zu erkennen?

**Antwort:**

Weil das Programm **oberflächlich betrachtet funktioniert**: Es kompiliert und arbeitet korrekt, ist aber schlecht strukturiert.

### Anführungszeichen und Backslash: Escape-Sequenzen

In `hello.c` steht `\n` für einen Zeilenumbruch. Der Backslash (`\`) leitet eine **Escape-Sequenz** ein: Er und das Zeichen dahinter stehen zusammen für ein einziges Zeichen, das man sonst nicht in den Text schreiben könnte. Das braucht man öfter, als man denkt:

- **Ein Anführungszeichen im Text.** `printf("Heute ist aber "schönes" Wetter\n");` lässt sich nicht übersetzen: Das Anführungszeichen vor „schönes“ beendet den Text, der Compiler meldet `expected ')'`. Richtig ist `\"`: `printf("Heute ist aber \"schönes\" Wetter\n");`
- **Ein Backslash im Text**, etwa in einem Windows-Pfad. `printf("C:\Windows\n");` bricht mit `unknown escape sequence '\W'` ab, denn `\W` gibt es nicht. Richtig ist `\\`: `printf("C:\\Windows\n");` gibt `C:\Windows` aus.

| Sie schreiben | Es erscheint |
|---|---|
| `\n` | ein Zeilenumbruch |
| `\t` | ein Tabulator |
| `\"` | ein Anführungszeichen `"` |
| `\\` | ein Backslash `\` |

Tückisch wird es, wenn die Escape-Sequenz zufällig existiert. `printf("C:\neu\tabelle\n");` übersetzt ohne jede Meldung und gibt `C:` aus, dann einen Zeilenumbruch, dann `eu`, einen Tabulator und `abelle`. Der Compiler kann nicht wissen, dass Sie einen Ordner „neu“ und eine Datei „tabelle“ meinten. Das ist ein Logikfehler (siehe oben): Das Programm läuft, nur nicht so, wie gewünscht.

**Selbsttest:**

Was gibt `printf("C:\neu\tabelle\n");` aus, und wie schreiben Sie es richtig?

**Antwort:**

`C:`, dann einen **Zeilenumbruch**, dann `eu`, einen **Tabulator** und `abelle`: `\n` und `\t` sind Escape-Sequenzen. Für einen Backslash im Text schreiben Sie `\\`, also `printf("C:\\neu\\tabelle\n");`.

### Aufwärmübungen: Scratch-Programme tracen

Bevor Sie mit C weitermachen, können Sie das Wissen aus der letzten Woche mit zwei **Tracing-Übungen** in Scratch auffrischen. Beide sind freiwillig und zum Selbermachen gedacht: Überlegen Sie jeweils auf Papier, was das Programm tun wird, und klicken Sie erst danach auf die grüne Flagge.

1. **Pen Down/Pen Up**: Bauen Sie ein Programm, das in einer Schleife abwechselnd mit `pen down` ein Stück zeichnet und mit `pen up` ein Stück weitergeht (dafür brauchen Sie die **Pen-Erweiterung**, die Sie mit dem Icon links unten aktivieren). Sagen Sie vorher, was die Katze zeichnet: Es entsteht eine gestrichelte Linie, denn der „Stift“ zeichnet nur, solange er unten ist. Drehen Sie die Katze danach vor der Schleife um 45 Grad und sagen Sie wieder vorher, was herauskommt.

2. **Das 3×3-Raster-Problem**: Schreiben Sie mit zwei verschachtelten `repeat`-Schleifen ein Programm, das ein Raster aus 3 × 3 Punkten zeichnet, indem es die x- und die y-Koordinate der Katze ändert. Ein typischer Fehler dabei: Nach der inneren Schleife muss x wieder auf den Anfangswert gesetzt werden, bevor die äußere Schleife weiterläuft. Sonst steht die zweite Reihe nicht unter der ersten. Gehen Sie Ihr Programm Zeile für Zeile durch und notieren Sie nach jedem Block, wo die Katze steht.

So üben Sie **algorithmisches Denken**: Man führt Code im Kopf oder auf Papier Schritt für Schritt aus, um zu verstehen, was passiert. Diese Fähigkeit werden Sie auch in C ständig brauchen.

**Selbsttest:**

Was bedeutet es, ein Programm zu „tracen“?

**Antwort:**

Man **führt den Code mental oder auf Papier Schritt für Schritt aus** und verfolgt dabei den Zustand der Variablen mit.

## Variablen und Datentypen

- Als Nächstes schreiben wir ein Programm, das zwei Zahlen einliest und sagt, welche größer ist. Dafür brauchen wir einen Platz für jede Zahl: eine **Variable**, wie in Scratch.
- In C kann man einem `int`, also einer Variable, die ganze Zahlen aufnimmt, wie folgt einen Wert zuweisen:

  ```c
  int counter = 0;
  ```
  
- Dadurch weisen wir der Variablen `counter` vom Typ `int` den Wert `0` zu.
- Nun können wir zu `counter` eine Eins addieren

  ```c
  counter = counter + 1;
  ```

- Dadurch wird 1 zum Wert von `counter` hinzugefügt.
- Dies kann auch kürzer dargestellt werden:

    ```c
    counter += 1;
  ```

- Oder noch kürzer:

    ```c
    counter++;
  ```
   
- Beachten Sie, dass auch diese Anweisung “1” zum Wert von `counter` addiert, aber deutlich kürzer ist. 
- Sie können auch “1” subtrahieren, z.B. so:
    
    ```c
    counter--;
  ```

- Beachten Sie, dass "1" vom Wert von `counter` abgezogen wird.

- Mit **Datentypen** legen wir beim Programmieren fest, wie die Bits, die in einer Variablen gespeichert werden, interpretiert werden sollen. In der allerersten Vorlesung hatten wir gesehen, dass eine bestimmte Bitfolge sehr unterschiedlich interpretiert werden kann, je nachdem ob es eine Zahl, ein Buchstabe oder eine Farbe ist.
- Für den Anfang genügen vier Typen:
    - `int`, eine ganze Zahl wie `42` oder `-3`
    - `char`, ein einzelnes Zeichen wie `a` oder `2`
    - `string`, eine Zeichenkette wie `"Hallo"`
    - `bool`, ein Wahrheitswert: entweder wahr (`true`) oder falsch (`false`)
- Weitere Typen (`long`, `float` und `double`) lernen Sie am Ende dieser Vorlesung kennen, zusammen mit den Grenzen, an die `int` stößt (siehe [Typen](#c-typen)).

**Selbsttest:**

Was bewirkt die Anweisung `counter++;`?

**Antwort:**

Sie **addiert 1** zum Wert von `counter`, genau wie `counter = counter + 1;` oder `counter += 1;`.

**Selbsttest:**

Was legen Sie mit einem Datentyp fest?

**Antwort:**

**Wie die Bits, die in einer Variablen gespeichert sind, interpretiert werden sollen.**

## Die Manual Pages: Ihre Dokumentation beim Programmieren

Wenn Sie nicht genau wissen, wie eine Funktion funktioniert oder welche Parameter sie benötigt, hilft Ihnen die offizielle Dokumentation. Für diesen Kurs sind die [CS50 Manual Pages](https://manual.cs50.io/) besonders nützlich:

- **Speziell für Anfänger**: Diese Manual Pages sind genau für Menschen wie Sie gemacht, die gerade C lernen. Sie enthalten weniger technischen Ballast als die offizielle C-Dokumentation.

- **Der "less comfortable" Modus**: Auf jeder Seite finden Sie einen Schiebeschalter mit "less comfortable". Standardmäßig ist dieser aktiviert und blendet komplizierte technische Details aus. Später im Semester können Sie ihn ausschalten und die "volle Wahrheit" sehen.

- **Was Sie dort finden**: Für jede Funktion (wie `printf`, `get_string`, etc.) finden Sie:
  - Was die Funktion tut
  - Welche Parameter sie erwartet
  - Was sie zurückgibt
  - Beispielcode

- **Tipp**: Machen Sie sich mit den Manual Pages vertraut – professionelle Programmierer verbringen viel Zeit damit, Dokumentation zu lesen!

**Selbsttest:**

Wo schlagen Sie im Kurs nach, was eine Funktion tut, welche Parameter sie erwartet und was sie zurückgibt?

**Antwort:**

In den **CS50 Manual Pages** (manual.cs50.io).

## Formatcodes

- `printf` kennt viele Formatcodes. Für die Typen, die wir bisher kennen, sind es diese (die Codes für `long`, `float` und `double` folgen bei den [Typen](#c-typen) am Ende):

    ```
    %c    für char (einzelnes Zeichen)
    %i    für int (Ganzzahl)
    %s    für string (Zeichenkette)
    ```

- `%s` wird für String-Variablen verwendet. `%i` wird für `int` oder Integer-Variablen verwendet. Sie können mehr darüber auf den [Manual Pages](https://manual.cs50.io/) herausfinden.

### Mehrere Platzhalter verwenden

Sie können **beliebig viele** Formatcodes in einem `printf`-Aufruf verwenden. Die Werte werden in der Reihenfolge eingesetzt, in der sie nach dem Format-String angegeben werden:

```c
string name1 = get_string("Erster Name: ");
string name2 = get_string("Zweiter Name: ");
printf("Hello, %s and %s\n", name1, name2);
```

Dies würde zum Beispiel `Hello, Maria and Josef` ausgeben, wenn die entsprechenden Namen eingegeben wurden.

Sie können auch verschiedene Typen kombinieren:

```c
char initial = 'M';
int age = 25;
printf("Initial: %c, Age: %i\n", initial, age);
```

**Wichtig:** Die Anzahl der Formatcodes muss **exakt** mit der Anzahl der Argumente übereinstimmen. Geben Sie zu viele oder zu wenige Argumente an, bricht der Compiler mit einer Fehlermeldung ab.

## Bedingte Anweisungen

- Ein weiterer Baustein, den Sie in Scratch verwendet haben, waren die *Bedingten Anweisungen*. Man möchte zum Beispiel etwas tun, wenn *x* größer als *y* ist. Außerdem möchte man vielleicht etwas anderes tun, wenn diese Bedingung nicht erfüllt ist.
- Wir sehen uns ein paar Beispiele aus Scratch an.
- Mit zwei Variablen vom Typ `int`, die Sie mit `get_int` füllen, können Sie Ihre erste bedingte Anweisung programmieren.
- Geben Sie im Terminalfenster `code compare.c` ein und schreiben Sie folgenden Code:

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

  int main(void)
  {
  	int x = get_int("What's x? ");
  	int y = get_int("What's y? ");

  	if (x < y)
  	{
  		printf("x is less than y\n");
  	}
  }
  ```

- Beachten Sie, dass wir zwei Variablen erstellen, einen `int` (Ganzzahl) namens `x` und einen weiteren namens `y`. Die Werte dieser Variablen werden mit der Funktion `get_int` eingelesen.
- Sie können Ihren Code ausführen, indem Sie `make compare` im Terminalfenster ausführen, gefolgt von `./compare`. Wenn Sie eine Fehlermeldung erhalten, überprüfen Sie Ihren Code auf Fehler.

- Wir schauen uns in der Vorlesung **Flussdiagramme** an; damit kann man die Funktionsweise eines Computerprogramms zu untersuchen und prüfen, ob das **Design des Codes** gut ist.
- Wenn wir uns ein Flussdiagramm des obigen Codes ansehen, können wir zahlreiche Mängel feststellen.

- Wir können Ihr Programm verbessern, indem wir es wie folgt ändern:

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

  int main(void)
  {
      int x = get_int("What's x? ");
      int y = get_int("What's y? ");

      if (x < y)
      {
          printf("x is less than y\n");
      }
      else if (x > y)
      {
          printf("x is greater than y\n");
      }
      else
      {
          printf("x is equal to y\n");
      }
  }
  ```

- Beachten Sie, dass nun alle möglichen Ergebnisse berücksichtigt werden.
- Sie können Ihr Programm nun erneut kompilieren, ausführen und testen.
- Im Flussdiagramm sehen wir, dass der Code nun ein besseres Design hat.

**Selbsttest:**

Was ist bei `compare.c` besser an der Fassung mit `if`, `else if` und `else` als an der mit nur `if (x < y)`?

**Antwort:**

Es werden **alle möglichen Ergebnisse berücksichtigt**: kleiner, größer und gleich.

**Selbsttest:**

Wozu schauen wir uns Flussdiagramme an?

**Antwort:**

Um die **Funktionsweise** eines Programms zu untersuchen und zu prüfen, ob das **Design des Codes** gut ist.

**Selbsttest:**

Mit welcher Funktion der CS50-Bibliothek lesen Sie eine Ganzzahl (`int`) vom Benutzer ein?

**Antwort:**

**`get_int`** (aus `cs50.h`).

### Übung: Bedingungen in drei Stufen

Drei Aufgaben zum selben Thema. Wählen Sie die Stufe, die Sie schaffen; wer fertig ist, nimmt die nächste. Versuchen Sie es erst selbst und klappen Sie die Lösung danach auf.

- **Stufe 1:** Ergänzen Sie `compare.c` so, dass bei gleichen Zahlen `x is equal to y` erscheint. Übersetzen Sie das Programm und testen Sie es mit 2 und 2. Die Lösung ist das Programm oben mit `if`, `else if` und `else`.
- **Stufe 2:** Schreiben Sie ein Programm `sign.c`, das eine ganze Zahl einliest und `positiv`, `negativ` oder `null` ausgibt.
- **Stufe 3:** Schreiben Sie ein Programm `max.c`, das drei ganze Zahlen einliest und die größte ausgibt.

**Lösung zu Stufe 2**

Das Muster ist dasselbe wie in `compare.c`: zwei Fragen, der dritte Fall steht im `else`.

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

int main(void)
{
    int n = get_int("Zahl: ");

    if (n > 0)
    {
        printf("positiv\n");
    }
    else if (n < 0)
    {
        printf("negativ\n");
    }
    else
    {
        printf("null\n");
    }
}
```

**Eine Lösung zu Stufe 3**

Die Variable `max` merkt sich die größte Zahl, die das Programm bisher gesehen hat. Am Anfang ist das `a`; ist `b` oder `c` größer, wird `max` überschrieben. Es gibt andere Lösungen, etwa mit `&&`.

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

int main(void)
{
    int a = get_int("a: ");
    int b = get_int("b: ");
    int c = get_int("c: ");

    int max = a;
    if (b > max)
    {
        max = b;
    }
    if (c > max)
    {
        max = c;
    }
    printf("%i\n", max);
}
```

### Optionale geschweifte Klammern (wichtig zu wissen!)

In C können die geschweiften Klammern bei `if`, `else if`, `else`, `while` und `for` weggelassen werden, wenn nur **eine einzige Anweisung** folgt. Das bedeutet, folgender Code ist syntaktisch korrekt:

```c
if (x < y)
    printf("x is less than y\n");
else
    printf("x is not less than y\n");
```

**Aber:** In diesem Kurs werden wir **immer** geschweifte Klammern verwenden, auch bei nur einer Anweisung, weil:
- Es ist übersichtlicher und weniger fehleranfällig
- Wenn Sie später eine zweite Anweisung hinzufügen, vergessen Sie vielleicht die Klammern
- Es ist ein verbreiteter Stil in der professionellen Softwareentwicklung

Sie werden Code ohne geschweifte Klammern im Internet finden – jetzt wissen Sie, warum das funktioniert. Aber schreiben Sie Ihren eigenen Code bitte immer mit geschweiften Klammern!

- Lassen Sie uns einen anderen Datentyp namens `char` betrachten.
- Wir schreiben ein neues Programm, indem wir `code agree.c` in das Terminalfenster eingeben.
- Während ein `string` eine Reihe von Zeichen ist, ist ein `char` ein einzelnes Zeichen (engl. *character*).

- Schreiben Sie im Texteditor folgenden Code:

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

  int main(void)
  {
  	// Prompt user to agree
  	char c = get_char("Do you agree? ");

  	// Check whether agreed
  	if (c == 'Y' || c == 'y')
  	{
  		printf("Agreed.\n");
  	}
  	else if (c == 'N' || c == 'n')
  	{
  		printf("Not agreed.\n");
  	}
  }
  ```

- Beachten Sie, dass bei `char` immer **einfache (nicht doppelte) Anführungszeichen** verwendet werden. Beachten Sie außerdem, dass `==` prüft, dass etwas _gleich_ mit etwas anderem ist, während ein einzelnes **Gleichheitszeichen** in C eine ganz andere Funktion hätte (nämlich die Zuweisung von Werten zu Variablen).
- Das `||` bedeutet so viel wie **"oder"**: Mindestens eine der beiden Bedingungen ist wahr. Das Gegenstück ist `&&` (**"und"**): Beide Bedingungen sind wahr.
- Weitere Vergleiche bestehen ebenfalls aus zwei Zeichen, das Gleichheitszeichen steht hinten: `<=` (kleiner oder gleich), `>=` (größer oder gleich) und `!=` (ungleich).
- Schreiben Sie im `if` versehentlich nur ein `=`, bricht `make` in unserer Umgebung mit einer Fehlermeldung ab und schlägt `==` vor.
- Sie können Ihren Code testen, indem Sie `make agree` in das Terminalfenster eingeben, gefolgt von `./agree`.

**Selbsttest:**

Warum setzen wir im Kurs trotzdem immer geschweifte Klammern, auch bei nur einer Anweisung?

**Antwort:**

Es ist **übersichtlicher und weniger fehleranfällig**: Fügt man später eine zweite Anweisung hinzu, vergisst man sonst leicht die Klammern.

**Selbsttest:**

Was unterscheidet einen `char` von einem `string`?

**Antwort:**

Ein `char` ist **ein einzelnes Zeichen**, ein `string` eine **Reihe von Zeichen**.

**Selbsttest:**

Welche Anführungszeichen verwenden Sie in C für einen `char`?

**Antwort:**

**Einfache** Anführungszeichen, zum Beispiel `'y'`.

**Selbsttest:**

Was ist in C der Unterschied zwischen `==` und `=`?

**Antwort:**

`==` **prüft auf Gleichheit**, `=` **weist** einer Variablen einen Wert **zu**.

**Selbsttest:**

Was bedeutet der Operator `||` in C?

**Antwort:**

**„oder“**.

### Übung: Parsons-Problem

Eine gute Methode, um Ihr Verständnis für C-Code zu testen, ist ein **Parsons-Problem** (nach Dale Parsons): Code-Zeilen sind durcheinandergeraten, und Sie bringen sie in die richtige Reihenfolge.

**Aufgabe:** Das Programm liest eine Temperatur in °C ein und gibt aus, ob es "kalt" (unter 10°), "warm" (10–25°) oder "heiß" (über 25°) ist. Der Rahmen steht schon da:

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

int main(void)
{
    // hier fehlen die Zeilen
}
```

Bringen Sie die folgenden Zeilen in die richtige Reihenfolge und notieren Sie die Lösung als Folge von Buchstaben. Die geschweiften Klammern um jedes `printf` denken Sie sich dazu. **Achtung:** Drei Zeilen sind falsch und bleiben übrig.

```text
A  if (temp < 10)
B  printf("warm\n");
C  else if (temp >= 25)
D  int temp = get_int("Temperatur: ");
E  if (temp <= 10)
F  printf("kalt\n");
G  else
H  string temp = get_int("Temperatur: ");
I  else if (temp > 25)
J  printf("heiß\n");
```

**Tipp:** Achten Sie auf die Grenzen der Bereiche (was ist bei genau 10°, was bei genau 25°?) und auf den Typ der Variable.

**Lösung:** D, A, F, I, J, G, B. Übrig bleiben E, C und H:

- E `if (temp <= 10)`: Bei genau 10° soll "warm" herauskommen, nicht "kalt".
- C `else if (temp >= 25)`: Bei genau 25° soll "warm" herauskommen, nicht "heiß".
- H `string temp = get_int("Temperatur: ");`: `get_int` gibt einen `int` zurück, keinen `string`. `make` bricht hier ab.

Fehler an den Grenzen sind die häufigsten. Die Mitte steht im `else`: Was nicht kalt und nicht heiß ist, ist warm. Das ganze Programm mit den Klammern:

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

int main(void)
{
    int temp = get_int("Temperatur: ");
    if (temp < 10)
    {
        printf("kalt\n");
    }
    else if (temp > 25)
    {
        printf("heiß\n");
    }
    else
    {
        printf("warm\n");
    }
}
```

## Schleifen

- Dem Schleifen-Baustein aus Scratch können wir auch in unseren C-Programmen verwenden.
- Wir sehen uns ein paar Beispiele aus Scratch an. Betrachten Sie den folgenden Code:

  ```c
  int counter = 3;
  while (counter > 0)
  {
  	printf("meow\n");
  	counter = counter - 1;
  }
  ```

- Beachten Sie, dass der Code der Variablen `counter` den Wert "3" zuweist. Dann wird in der **while-Schleife** "meow" ausgegeben und bei jeder *Iteration* der Wert “1” vom Zähler abgezogen. Sobald der Zähler nicht mehr größer als Null ist, endet die Schleife.
- Geben Sie in Ihrem Terminal-Fenster `code meow.c` ein und schreiben Sie folgenden Code:

  ```c
  #include <stdio.h>

  int main(void)
  {
  	printf("meow\n");
  	printf("meow\n");
  	printf("meow\n");
  }
  ```

- Beachten Sie, dass dies wie beabsichtigt funktioniert, aber es Potenzial für besseres *Design* gibt.
- Wir können unser Programm verbessern, indem wir Ihren Code wie folgt abändern:

  ```c
  #include <stdio.h>

  int main(void)
  {
  	int i = 3;
  	while (i > 0)
  	{
  		printf("meow\n");
  		i--;
  	}
  }
  ```

- Beachten Sie, dass wir einen `int` namens `i` erstellen und ihm den Wert “3” zuweisen. Dann erstellen wir eine while-Schleife, die läuft, solange `i > 0` erfüllt ist. Dann wird der Schleifenkörper durchlaufen. Jedes Mal wird “1” von `i` mit der Anweisung `i--` abgezogen.

- In ähnlicher Weise können wir es mit Hochzählen implementieren:

  ```c
  #include <stdio.h>

  int main(void)
  {
  	int i = 1;
  	while (i <= 3)
  	{
  		printf("meow\n");
  		i++;
  	}
  }
  ```

- Beachten Sie, dass unser Zähler `i` bei `1` beginnt. Jedes Mal, wenn die Schleife läuft, wird der Zähler um "1" erhöht. Sobald der Zähler größer als “3” ist, wird die Schleife angehalten.

- In der Informatik zählen wir in der Regel von Null an. Am besten überarbeiten Sie Ihren Code daher wie folgt:

  ```c
  #include <stdio.h>

  int main(void)
  {
  	int i = 0;
  	while (i < 3)
  	{
  		printf("meow\n");
  		i++;
  	}
  }
  ```

-  Beachten Sie, dass wir jetzt von Null an zählen.

- Ein weiteres Werkzeug in unserem Werkzeugkasten für Schleifen ist eine **for-Schleife**.
- Wir können das Design unseres Programms *meow.c* mit einer for-Schleife weiter verbessern. Ändern Sie Ihren Code dazu wie folgt:

  ```c
  #include <stdio.h>

  int main(void)
  {
  	for (int i = 0; i < 3; i++)
  	{
  		printf("meow\n");
  	}
  }
  ```

- Beachten Sie, dass die for-Schleife in ihren runden Klammern drei Teile enthält. Der erste Teil `int i = 0` startet unseren Zähler bei Null. Der zweite Teil `i < 3` ist die Bedingung, die überprüft wird. Schließlich weist der dritte Teil `i++` die Schleife an, bei jedem Schleifendurchlauf um eins zu erhöhen.

- Mit dem folgenden Code können wir sogar eine **Endlosschleife** erstellen:

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

  int main(void)
  {
  	while (true)
  	{
  		printf("meow\n");
  	}
  }
  ```

- Beachten Sie, dass `true` die Bedingung immer erfüllt. Daher wird der Code in der Schleife immer wieder ausgeführt. Wenn Sie dieses Programm starten, verlieren Sie die Kontrolle über Ihr Terminalfenster. Sie können das Programm abbrechen, indem Sie `Control-C` (oder `Strg-C`) auf Ihrer Tastatur drücken.

- Später werden wir es uns noch genauer ansehen, aber eine eigene **Funktion** können Sie in C auch jetzt schon wie folgt erstellen:

  ```c
  void meow(void)
  {
  	printf("meow\n");
  }
  ```

- Das anfängliche `void` bedeutet, dass die Funktion keine Werte zurückgibt. Das `(void)` bedeutet, dass der Funktion keine Werte übergeben werden.

- Diese Funktion kann in der Hauptfunktion wie folgt verwendet werden:

  ```c
  #include <stdio.h>

  void meow(void);

  int main(void)
  {
  	for (int i = 0; i < 3; i++)
  	{
  		meow();
  	}
  }

  void meow(void)
  {
  	printf("meow\n");
  }
  ```

- Beachten Sie, dass die Funktion "meow" mit der Anweisung "meow()" aufgerufen wird. Dies ist möglich, weil die "meow"-Funktion am Ende des Codes definiert ist und der **Prototyp** der Funktion am Anfang des Codes als `void meow(void)` angegeben ist.
- Warum nicht einfach `meow` über `main` schreiben? Das ginge, aber `main` soll oben stehen, denn sie ist der Einstiegspunkt, und wer den Code liest, will sie sofort sehen. Der Compiler liest den Code allerdings von oben nach unten. Ohne Prototyp kennt er `meow` noch nicht, wenn er in `main` auf den Aufruf stößt, und meldet einen Fehler.

- Ihre "meow"-Funktion kann weiter modifiziert werden, um Eingaben zu akzeptieren:

  ```c
  #include <stdio.h>

  void meow(int n);

  int main(void)
  {
  	meow(3);
  }

  // Meow some number of times
  void meow(int n)
  {
  	for (int i = 0; i < n; i++)
  	{
  		printf("meow\n");
  	}
  }
  ```

- Beachten Sie, dass der Prototyp in `void meow(int n)` geändert wurde, um den Compiler zu informieren, dass `meow` einen `int` als Eingabe akzeptiert.

**Selbsttest:**

Was bedeuten die drei Teile von `for (int i = 0; i < 3; i++)`?

**Antwort:**

- `int i = 0`: **startet** den Zähler bei 0
- `i < 3`: die **Bedingung**, die geprüft wird
- `i++`: **erhöht** den Zähler bei jedem Durchlauf um eins

**Selbsttest:**

Wie schreiben Sie in C eine Endlosschleife?

**Antwort:**

**`while (true)`**: Die Bedingung ist immer erfüllt.

**Selbsttest:**

Wie brechen Sie ein Programm ab, das im Terminal endlos läuft?

**Antwort:**

Mit **Strg-C** (Control-C).

**Selbsttest:**

Was bedeutet das erste `void` in `void meow(void)`?

**Antwort:**

Die Funktion **gibt keinen Wert zurück**.

**Selbsttest:**

Was bedeutet `(void)` in `void meow(void)`?

**Antwort:**

Der Funktion **werden keine Werte übergeben**.

**Selbsttest:**

Warum schreibt man `main` meist oben in die Datei und nicht ans Ende?

**Antwort:**

`main` ist der **Einstiegspunkt**. Wer den Code liest, will ihn **sofort sehen**. Funktionen, die darunter stehen, macht ein Prototyp dem Compiler bekannt.

**Selbsttest:**

Wozu steht `void meow(void);` oben in der Datei, wenn `meow` erst am Ende definiert wird?

**Antwort:**

Das ist der **Prototyp**: Er macht die Funktion dem Compiler bekannt, sodass `main` sie aufrufen kann, obwohl die Definition erst am Ende steht.

## Operatoren und Abstraktion

- Sie können einen Taschenrechner in C implementieren.

- Geben Sie in Ihrem Terminal `code calculator.c` ein und schreiben Sie folgenden Code:

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

  int main(void)
  {
  	// Prompt user for x
  	int x = get_int("x: ");

  	// Prompt user for y
  	int y = get_int("y: ");

  	// Perform addition
  	printf("%i\n", x + y);
  }
  ```

- Beachten Sie, wie die Funktion `get_int` verwendet wird, um zweimal eine Zahl vom Benutzer zu erhalten. Eine Ganzzahl wird in der `int`-Variablen `x` gespeichert, eine weitere in der `int`-Variablen `y`. Dann druckt die Funktion `printf` den Wert von `x + y` aus, und zwar an die Stelle, an der der Formatcode `%i` steht. Danach wird mit `\n` ein Zeilenumbruch ausgegeben.

- Das `+` ist ein **Operator**. In C gibt es insbesondere folgende arithmetische Operatoren:
	- `+` für Addition
	- `-` für Subtraktion
	- `*` für Multiplikation
	- `/` für Division
	- `%` für Modulo (Rest nach einer Division)

- `/` und `%` gehören oft zusammen. Angenommen, Sie schulden jemandem 97 Cent und wollen möglichst wenige Euro-Münzen herausgeben (50, 20, 10, 5, 2 und 1 Cent). `97 / 50` ergibt `1`: Teilt man eine ganze Zahl durch eine ganze Zahl, fallen die Nachkommastellen weg. Also ein 50er. `97 % 50` ergibt `47`: der Rest, der noch herauszugeben ist. Mit der nächsten Münze geht es genauso weiter: `47 / 20` ergibt `2`, also zwei 20er, Rest `7`; `7 / 10` ergibt `0`, also kein 10er; ein 5er, Rest 2; ein 2er. Zusammen 5 Münzen: 50, 20, 20, 5 und 2 Cent. Genauso rechnet die Aufgabe [Bargeld](https://inf.zone/exercises/01/cash/) aus Übung 1, dort mit US-Münzen zu 25, 10, 5 und 1 Cent.

**Selbsttest:**

Was ergeben `47 / 20` und `47 % 20`?

**Antwort:**

`47 / 20` ergibt **2** (ganze Zahl durch ganze Zahl, die Nachkommastellen fallen weg), `47 % 20` ergibt **7** (der Rest).

- Indem wir unser zuvor erworbenes Wissen über Funktionen anwenden, können wir die Addition in eine Funktion _abstrahieren_. Ändern Sie Ihren Code dazu wie folgt:
  - **Abstraktion** ist die Kunst, unseren Code so zu vereinfachen, dass wir Probleme schrittweise in kleinere Teile zerlegen und die Details der Lösung vor uns verbergen.
  

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

  int add(int a, int b);

  int main(void)
  {
  	// Prompt user for x
  	int x = get_int("x: ");

  	// Prompt user for y
  	int y = get_int("y: ");

  	// Perform addition
  	int z = add(x, y);
  	printf("%i\n", z);
  }

  int add(int a, int b)
  {
  	int c = a + b;
  	return c;
  }
  ```

- Beachten Sie, dass die Funktion `add` zwei Variablen als Eingabe benötigt. Diese Werte werden den Variablen `a` und `b` zugewiesen. Die Funktion führt dann die Addition durch und speichert das in der Variablen `c`. Danach gibt sie den Wert in `c` zurück dorthin, wo sie aufgerufen wurde.

**Selbsttest:**

Was berechnet der Operator `%` in C?

**Antwort:**

Den **Rest nach einer Division** (Modulo).

**Selbsttest:**

Was ist Abstraktion beim Programmieren?

**Antwort:**

Probleme **schrittweise in kleinere Teile zerlegen** und die **Details der Lösung verbergen**, etwa in einer Funktion wie `add`.

**Selbsttest:**

Was bewirkt `return c;` am Ende der Funktion `add`?

**Antwort:**

Es **gibt den Wert von `c` dorthin zurück, wo die Funktion aufgerufen wurde**.

### Scope: Variablen leben nur in ihrer Funktion

Ein wichtiges Konzept in C ist **Scope** (deutsch: Gültigkeitsbereich) – der Kontext, in dem Variablen existieren:

- **Jede Funktion ist ihre eigene "Box"**: Die Variable `x` existiert nur in `main`, die Variable `c` existiert nur in `add`. Die Funktion `add` hat keine Ahnung, dass `x` in `main` existiert.

- **Werte werden kopiert, nicht geteilt**: Wenn Sie `add(x, y)` aufrufen, werden die **Werte** von `x` und `y` kopiert und in den Parametern `a` und `b` gespeichert. Die Variablen `x` und `y` selbst werden nicht "gesendet". Es sind komplett neue Variablen mit kopierten Werten.

- **Was in der Funktion passiert, bleibt in der Funktion**: Die Variablen `a`, `b` und `c` in der Funktion `add` existieren nur, während die Funktion läuft. Sobald die Funktion endet und einen Wert zurückgibt, werden diese Variablen **zerstört** – sie existieren nicht mehr. Alles, was bleibt, ist der Rückgabewert.

- **Originalvariablen bleiben unverändert**: Die Variablen `x` und `y` in `main` behalten ihre Werte, egal was in `add` passiert. Sie haben niemals mitbekommen, dass `add` aufgerufen wurde.

- **Genauer gilt das für jeden Block**: Eine Variable lebt bis zur schließenden geschweiften Klammer des Blocks, in dem sie angelegt wurde. Das `i` einer `for`-Schleife gibt es hinter ihrer schließenden Klammer nicht mehr. Das brauchen Sie gleich bei der Eingabevalidierung.

Stellen Sie sich Funktionen wie getrennte Räume vor: Jede Funktion hat ihre eigenen Variablen und kann nicht einfach die Variablen einer anderen Funktion sehen oder ändern. Kommunikation zwischen Funktionen erfolgt nur durch Parameter (Eingabe) und Return-Werte (Ausgabe).

- Das Design dieses Programms kann wie folgt weiter verbessert werden:
    
    ```c
  #include <cs50.h>
  #include <stdio.h>
  
  int add(int a, int b);
  
  int main(void)
  {
      // Prompt user for x
      int x = get_int("x: ");
  
      // Prompt user for y
      int y = get_int("y: ");
  
      // Perform addition
      printf("%i\n", add(x, y));
  }
  
  int add(int a, int b)
  {
      return a + b;
  }
  ```
 
- Beachten Sie, dass "c" in der Funktion "add" entfernt wurde.

- Obwohl es sehr nützlich ist, zu einer "Add"-Funktion zu abstrahieren, ist es etwas umständlich. Sie könnten die Addition auch direkt im Aufruf von `printf` durchführen:

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

  int main(void)
  {
      // Benutzer zur Eingabe von x auffordern
      int x = get_int("x: ");

      // Benutzer zur Eingabe von y auffordern
      int y = get_int("y: ");

      // Addition durchführen
      printf("%i\n", x + y);
  }
  ```

- Beachten Sie, dass die Addition innerhalb des Aufrufs von `printf` durchgeführt wird.
- In ähnlicher Weise könnten auch andere Operationen, etwa eine Division durchgeführt werden:

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

  int main(void)
  {
      // Aufforderung an den Benutzer zur Eingabe von x
      int x = get_int("x: ");

      // Aufforderung an den Benutzer zur Eingabe von y
      int y = get_int("y: ");

      // Teilen Sie x durch y
      printf("%i\n", x / y);
  }
  ```   

**Selbsttest:**

Was bezeichnet der Begriff „Scope“ (Gültigkeitsbereich)?

**Antwort:**

Den **Kontext, in dem eine Variable existiert**. In C: Variablen leben nur in ihrer Funktion.

**Selbsttest:**

Was passiert beim Aufruf `add(x, y)` mit `x` und `y`?

**Antwort:**

Ihre **Werte werden kopiert** und in den Parametern `a` und `b` gespeichert. `x` und `y` selbst werden nicht „gesendet“ und bleiben unverändert.

**Selbsttest:**

Was geschieht mit den Variablen `a`, `b` und `c` der Funktion `add`, sobald die Funktion endet?

**Antwort:**

Sie werden **zerstört**. Übrig bleibt nur der **Rückgabewert**.

**Selbsttest:**

Über welche zwei Wege kommunizieren Funktionen in C miteinander?

**Antwort:**

Über **Parameter** (Eingabe) und **Rückgabewerte** (Ausgabe).

## Linux und die Kommandozeile

- Linux ist ein Betriebssystem, bei dem die Kommandozeile eine wichtige Rolle spielt. Wenn wir das Terminalfenster von VS Code im Kurs benutzen, steuern wir einen Rechner, auf dem Linux läuft – entweder in der Cloud oder in einem Container, der auf Ihrem Laptop gestartet wird, wenn Sie VS Code öffnen.
- Einige übliche **Befehlszeilenprogramme**, die wir verwenden können, sind:
    - `cd`, um unser aktuelles Verzeichnis (Ordner) zu wechseln
    - `cp`, um Dateien und Verzeichnisse zu kopieren
    - `ls`, zum Auflisten von Dateien in einem Verzeichnis
    - `mkdir`, um ein Verzeichnis zu erstellen
    - `mv`, zum Verschieben (Umbenennen) von Dateien und Verzeichnissen
    - `rm`, zum Entfernen (Löschen) von Dateien
    - `rmdir`, um Verzeichnisse zu entfernen (zu löschen)
- Das am häufigsten verwendete Programm ist `ls`, das alle Dateien im aktuellen Verzeichnis **auflistet**. Geben Sie einfach `ls` in das Terminalfenster ein und drücken Sie `Enter`. Sie werden alle Dateien im aktuellen Verzeichnis sehen.
- Ein weiterer nützlicher Befehl ist `mv`, mit dem Sie eine Datei in ein anderes Verzeichnis **verschieben** oder umbenennen können. Zum Beispiel können Sie diesen Befehl verwenden, um `Hello.c` (beachten Sie das große `H`) in `hello.c` umzubenennen, indem Sie `mv Hello.c hello.c` eingeben.
- Sie können auch **Verzeichnisse erstellen**. Sie können `mkdir pset1` eingeben, um ein Verzeichnis namens `pset1` zu erstellen.
- Sie können dann `cd pset1` benutzen, um von Ihrem aktuellen Verzeichnis in das neu angelegte Verzeichnis `pset1` zu **wechseln**.
- In welchem Verzeichnis Sie sind, sehen Sie – je nach Konfiguration – am Zeilenanfang. Wenn Sie sich unsicher sind, können Sie mit `pwd` (von engl. *print working directory*) Ihr **aktuelles Verzeichnis** ausgeben lassen.

**Selbsttest:**

Mit welchem Befehl listen Sie die Dateien im aktuellen Verzeichnis auf?

**Antwort:**

**`ls`**.

**Selbsttest:**

Mit welchem Befehl wechseln Sie in ein anderes Verzeichnis?

**Antwort:**

**`cd`**, zum Beispiel `cd pset1`.

**Selbsttest:**

Mit welchem Befehl erstellen Sie auf der Kommandozeile ein neues Verzeichnis?

**Antwort:**

**`mkdir`**, zum Beispiel `mkdir pset1`.

**Selbsttest:**

Mit welchem Befehl verschieben oder benennen Sie auf der Kommandozeile eine Datei um?

**Antwort:**

**`mv`**, zum Beispiel `mv Hello.c hello.c`.

**Selbsttest:**

Mit welchem Befehl kopieren Sie auf der Kommandozeile Dateien und Verzeichnisse?

**Antwort:**

**`cp`**.

**Selbsttest:**

Mit welchem Befehl löschen Sie auf der Kommandozeile eine Datei?

**Antwort:**

**`rm`** (für Verzeichnisse: `rmdir`).

**Selbsttest:**

Mit welchem Befehl lassen Sie sich auf der Kommandozeile Ihr aktuelles Verzeichnis ausgeben?

**Antwort:**

**`pwd`** (von engl. *print working directory*).

### Terminal-Effizienz: Die Werkzeuge der Profis

Professionelle Programmiererinnen und Programmierer verbringen viel Zeit im Terminal. Daher gibt es einige Techniken, die Ihre Arbeit deutlich effizienter machen:

- **Tab-Vervollständigung**: Wenn Sie einen Dateinamen oder Befehl eingeben, drücken Sie die **Tab-Taste**. Das Terminal vervollständigt automatisch, was Sie schreiben wollten. Wenn es mehrere Möglichkeiten gibt, zeigt ein zweites Drücken von Tab alle Optionen an. Beispiel: Tippen Sie `mv m` und drücken Sie Tab – das Terminal hilft Ihnen, den Rest zu finden.

- **Befehlshistorie mit Pfeiltasten**: Mit **Pfeil nach oben** und **Pfeil nach unten** können Sie durch zuvor eingegebene Befehle navigieren. Das erspart Ihnen, lange Befehle immer wieder neu einzutippen.

- **Terminal aufräumen mit `clear`**: Der Befehl `clear` (oder die Tastenkombination **Ctrl+L** bzw. **Strg+L**) leert den Bildschirm und gibt Ihnen wieder Übersicht. Viele Programmierer machen das regelmäßig, um ein "aufgeräumtes Terminal" zu haben.

Diese kleinen Tricks sparen enorm viel Zeit – professionelle Entwickler tippen oft nur die Hälfte ihrer Befehle selbst, den Rest erledigen Tab-Vervollständigung und die Befehlshistorie.

**Selbsttest:**

Mit welchem Befehl leeren Sie den Bildschirm des Terminals?

**Antwort:**

**`clear`** (oder die Tastenkombination **Strg+L**).

## Mario

- Alles, was wir heute besprochen haben, sind Bausteine für Ihre Arbeit als angehende Informatikerinnen und Informatiker.
- Die folgenden Ausführungen sollen Ihnen helfen, sich auf die Arbeit an einer Problemstellung für diesen Kurs im Allgemeinen einzustellen: **Wie geht man an ein Problem aus der Informatik heran?**
- Stellen Sie sich vor, wir wollten die Grafik des Spiels Super Mario Bros. nachbilden. Wie müsste ein Programm aussehen, das so etwas wie die vier horizontalen Fragezeichenblöcke ausgibt?

### Progressives Refactoring: Code Schritt für Schritt verbessern

In den folgenden Beispielen werden wir einen wichtigen Ansatz der Softwareentwicklung kennenlernen: **progressives Refactoring**. Wir beginnen mit einer einfachen, aber nicht optimalen Lösung und verbessern sie Schritt für Schritt. Bei jedem Schritt fragen wir uns: *Welches Problem behebt diese Änderung? Warum ist der Code jetzt besser?*

Sie werden sehen, wie wir den Code mehrfach überarbeiten:
1. Von **hartkodiertem Code** zu **Schleifen** (weniger Wiederholung)
2. Von **einfachen Schleifen** zu **verschachtelten Schleifen** (komplexere Muster)
3. Von **"magischen Zahlen"** zu **Variablen** (bessere Lesbarkeit)
4. Von **Variablen** zu **Konstanten** (verhindert ungewollte Änderungen)
5. Von **festen Werten** zu **Benutzereingaben** (Flexibilität)
6. Von **unvalidiertem Input** zu **Eingabeprüfung** (Robustheit)
7. Von **Code-Duplikation** zu **eleganten Lösungen** (besseres Design)

Dieser schrittweise Ansatz ist typisch für gutes Programmieren: Erst etwas zum Laufen bringen, dann systematisch verbessern.

![Mario Question Marks](https://cs50.harvard.edu/x/2024/notes/1/cs50Week1Slide123.png "Mario Question Marks")

- Geben Sie im Terminalfenster `code mario.c` ein und programmieren Sie Folgendes:

  ```c
  #include <stdio.h>

  int main(void)
  {
  	for (int i = 0; i < 4; i++)
  	{
  		printf("?");
  	}
  	printf("\n");
  }
  ```

- Beachten Sie, dass hier vier Fragezeichen in einer Schleife gedruckt werden.
- Mit der gleichen Logik können wir auch drei vertikale Blöcke erstellen.

  ![Mario Blocks](https://cs50.harvard.edu/x/2024/notes/1/cs50Week1Slide125.png "Mario Blocks")

- Ändern Sie dazu Ihren Code wie folgt:

  ```c
  #include <stdio.h>

  int main(void)
  {
  	for (int i = 0; i < 3; i++)
  	{
  		printf("#\n");
  	}
  }
  ```

- Beachten Sie, dass drei vertikale Ziegelsteine in einer Schleife gedruckt werden.
- Was wäre, wenn wir diese Ideen kombinieren wollten, um eine drei-mal-drei-Gruppe von Blöcken zu schaffen?

  ![Mario Grid](https://cs50.harvard.edu/x/2024/notes/1/cs50Week1Slide127.png "Mario Grid")

- Wir können der obigen Logik folgen, indem wir die bisherigen Ideen kombinieren. Ändern Sie Ihren Code wie folgt:

  ```c
  #include <stdio.h>

  int main(void)
  {
  	for (int i = 0; i < 3; i++)
  	{
  		for (int j = 0; j < 3; j++)
  		{
  			printf("#");
  		}
  		printf("\n");
  	}
  }
  ```

- Beachten Sie, dass eine Schleife innerhalb einer anderen liegt – man sagt: es sind **verschachtelte Schleifen**. Die erste Schleife legt fest, welche vertikale Zeile gedruckt wird. Für jede Zeile werden drei Spalten gedruckt. Nach jeder Zeile wird eine neue Zeile gedruckt.
- Was wäre, wenn wir sicherstellen wollten, dass die Anzahl der Blöcke _konstant_, d. h. unveränderlich ist? Ändern Sie Ihren Code wie folgt:

  ```c
  #include <stdio.h>

  int main(void)
  {
  	const int n = 3;
  	for (int i = 0; i < n; i++)
  	{
  		for (int j = 0; j < n; j++)
  		{
  			printf("#");
  		}
  		printf("\n");
  	}
  }
  ```

- Beachten Sie, dass "n" jetzt eine **Konstante** ist. Diese Variable kann nach ihrer Initialisierung nicht mehr geändert werden.
- Häufiger sehen Sie in C dafür eine **symbolische Konstante** mit `#define`. Sie steht oben in der Datei, unter den `#include`-Zeilen, ohne Gleichheitszeichen und ohne Semikolon:

  ```c
  #define N 3
  ```

  Vor dem Übersetzen ersetzt der Präprozessor jedes `N` im Code durch `3`. Im Programm schreiben Sie dann `i < N` statt `i < 3`. Solche Namen schreibt man in Großbuchstaben.
- Mit dem, was wir schon wissen, können wir unseren Code so umbauen, dass der Benutzer nach der Größe des Rasters gefragt wird. Ändern Sie Ihren Code wie folgt:

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

  int main(void)
  {
  	int n = get_int("Size: ");

  	for (int i = 0; i < n; i++)
  	{
  		for (int j = 0; j < n; j++)
  		{
  			printf("#");
  		}
  		printf("\n");
  	}
  }
  ```

- Beachten Sie, dass `get_int` verwendet wird, um den Benutzer aufzufordern.
- Ein allgemeiner Ratschlag bei der Programmierung lautet: **Vertraue nie darauf, dass sich die Benutzerinnen und Benutzer so verhalten wie du denkst (oder wie man es erwarten würde).** Sie werden sich wahrscheinlich falsch verhalten, entweder unabsichtlich oder absichtlich, und zum Beispiel ungültige Werte eingeben. Wir können unser Programm vor schlechtem Verhalten schützen, indem wir überprüfen, ob die Eingaben unseren Anforderungen genügen.

**Selbsttest:**

Was versteht man unter progressivem Refactoring?

**Antwort:**

Mit einer **einfachen, nicht optimalen Lösung beginnen** und sie **Schritt für Schritt verbessern**: erst zum Laufen bringen, dann systematisch verbessern.

**Selbsttest:**

Wie nennt man es, wenn eine Schleife innerhalb einer anderen liegt?

**Antwort:**

**Verschachtelte Schleifen**.

**Selbsttest:**

Warum ersetzt man „magische Zahlen“ im Code durch Variablen?

**Antwort:**

Für **bessere Lesbarkeit**.

**Selbsttest:**

Was bewirkt `const` in `const int n = 3;`?

**Antwort:**

`n` ist eine **Konstante**: Sie kann nach der Initialisierung nicht mehr geändert werden. Das verhindert ungewollte Änderungen.

**Selbsttest:**

Welcher allgemeine Ratschlag gilt beim Programmieren für Eingaben der Benutzer?

**Antwort:**

**Vertraue nie darauf, dass sich Benutzer so verhalten, wie du denkst.** Deshalb prüft man Eingaben.

### Übung: Mario in drei Stufen

Drei Aufgaben zum selben Programm. Wählen Sie die Stufe, die Sie schaffen; wer fertig ist, nimmt die nächste.

- **Stufe 1:** Ein Quadrat, dessen Größe `n` das Programm mit `get_int` einliest. Das ist das Programm oben. Tippen Sie es ab, falls Sie es noch nicht haben, und testen Sie es mit 3 und 5.
- **Stufe 2:** Ein Dreieck, linksbündig: In der ersten Zeile steht ein Stein, in der zweiten stehen zwei, in der letzten `n`. Für die Größe 4:

  ```
  #
  ##
  ###
  ####
  ```

- **Stufe 3:** Dasselbe Dreieck rechtsbündig, mit Leerzeichen vor den Steinen:

  ```
     #
    ##
   ###
  ####
  ```

  Das ist der Kern der Aufgabe [Mario](https://inf.zone/exercises/01/mario/) aus Übung 1; eine Lösung steht hier deshalb nicht. In der Übung legen Sie `mario.c` in einem eigenen Ordner `mario` an.

**Lösung zu Stufe 2**

Gegenüber dem Quadrat ändert sich eine einzige Stelle: Die innere Schleife läuft nicht mehr bis `n`, sondern bis zur Nummer der Zeile, `j <= i`. In der Zeile mit `i` gleich 0 gibt sie einen Stein aus, in der Zeile mit `i` gleich 1 zwei, und so weiter.

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

int main(void)
{
    int n = get_int("Size: ");

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j <= i; j++)
        {
            printf("#");
        }
        printf("\n");
    }
}
```

### Eingabevalidierung: Das "cat"-Problem

Ein interessanter Aspekt von `get_int`: Wenn der Benutzer einen nicht-numerischen Wert eingibt (z.B. "cat" statt einer Zahl), fragt die Funktion automatisch erneut nach, bis eine gültige Zahl eingegeben wird. **Aber**: Wenn der Benutzer `0` eingibt, gibt `get_int` diese 0 zurück – und `0` ist keine gültige Größe für unser Mario-Grid!

Das bedeutet: Wir müssen **zusätzlich** überprüfen, ob die Zahl sinnvoll ist. Wir wollen sicherstellen, dass `n` mindestens 1 ist. Daher fragen wir erneut, solange `n < 1` gilt.

Ändern Sie Ihren Code wie folgt:

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

  int main(void)
  {
  	int n;
  	do
  	{
  		n = get_int("Size: ");
  	}
  	while (n < 1);

  	for (int i = 0; i < n; i++)
  	{
  		for (int j = 0; j < n; j++)
  		{
  			printf("#");
  		}
  		printf("\n");
  	}
  }
  ```

- Beachten Sie, dass der Benutzer ständig zur Eingabe der Größe aufgefordert wird, bis die Eingabe des Benutzers 1 oder größer ist. Dazu haben wir eine **do-while-Schleife** verwendet, bei der der Schleifenkörper erst ausgeführt wird bevor die Bedingung geprüft wird.
- `int n;` steht **vor** der Schleife, im `do`-Block steht nur die Zuweisung. Legen Sie `n` dagegen im Block an (`int n = get_int("Size: ");` zwischen den geschweiften Klammern), gibt es `n` hinter der schließenden Klammer nicht mehr (Scope), und `make` bricht bei `while (n < 1)` ab: „use of undeclared identifier 'n'“. Beachten Sie außerdem das Semikolon hinter `while (n < 1)`.

**Selbsttest:**

Was tut `get_int`, wenn jemand „cat“ statt einer Zahl eingibt?

**Antwort:**

Es **fragt automatisch erneut nach**, bis eine gültige Zahl eingegeben wird.

**Selbsttest:**

Warum muss man im Mario-Programm die Eingabe von `get_int` zusätzlich prüfen?

**Antwort:**

`get_int` gibt auch **0 zurück**, und 0 ist **keine gültige Größe** für das Raster.

**Selbsttest:**

Wann prüft eine do-while-Schleife ihre Bedingung?

**Antwort:**

**Erst nachdem der Schleifenkörper ausgeführt wurde.** Der Körper läuft also mindestens einmal.

## Kommentare

- Kommentare sind grundlegende Bestandteile von Computerprogrammen. Damit hinterlassen Sie sich selbst und anderen, mit denen Sie zusammenarbeiten, Erklärungen zu Ihrem Code.
- **Code, den Sie in diesem Kurs erstellen und abgeben (insbesondere im Abschlussprojekt und in der Prüfung), muss immer sinnvolle und aussagekräftige Kommentare enthalten.**
- Normalerweise besteht ein Kommentar aus einigen Wörtern oder ein paar Sätzen, die dabei helfen, zu verstehen, was in einem bestimmten Code-Block passiert. Außerdem dienen solche Kommentare als Gedächtnisstütze für Sie, wenn Sie Ihren Code später überarbeiten müssen.
- Kommentare stehen im Code immer hinter `//`. Ändern Sie Ihren Code wie folgt, um Kommentare zu integrieren:

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

  int main(void)
  {
  	// Prompt user for positive integer
  	int n;
  	do
  	{
  		n = get_int("Size: ");
  	}
  	while (n < 1);

  	// Print an n-by-n grid of bricks
  	for (int i = 0; i < n; i++)
  	{
  		for (int j = 0; j < n; j++)
  		{
  			printf("#");
  		}
  		printf("\n");
  	}
  }
  ```

- Beachten Sie, dass jeder Kommentar mit einem `//` beginnt.

**Selbsttest:**

Womit beginnt ein Kommentar in C?

**Antwort:**

Mit **`//`**.

**Selbsttest:**

Wozu dienen Kommentare im Code?

**Antwort:**

Sie **erklären** Ihnen selbst und anderen, **was in einem Code-Block passiert**, und sind eine Gedächtnisstütze, wenn Sie den Code später überarbeiten.

## Fehlersuche

- Jeder macht beim Programmieren Fehler.
- Fehler in Programmen heißen „Bugs“ (Käfer). Das Wort war unter Ingenieuren schon lange üblich, als 1947 das Team um Grace Hopper in einem Relais des Rechners Mark II in Harvard eine echte Motte fand und ins Logbuch klebte, mit dem Vermerk „First actual case of bug being found“.
- Betrachten Sie das folgende Bild aus der Aufgabe Mario:

    ![mario](https://cs50.harvard.edu/x/2024/notes/2/cs50Week2Slide061.png "mario")

- Betrachten Sie außerdem den folgenden Code, in den absichtlich ein Fehler eingefügt wurde:

```c
#include <stdio.h>

int main(void)
{
    for (int i = 0; i <= 3; i++)
    {
        printf("#\n");
    }
}
```

- Geben Sie `code buggy0.c` in das Terminalfenster ein und schreiben Sie den obigen Code.
- Wenn Sie diesen Code ausführen, erscheinen vier Steine statt der geplanten drei.
- Wir sehen uns nun vier Methoden zum **Debugging** an.
- `printf` ist eine sehr einfache und nützliche Methode, um Code zu debuggen. Wir könnten den Code dazu wie folgt abändern:
    ```c
    #include <stdio.h>

    int main(void)
    {
        for (int i = 0; i <= 3; i++)
        {
            printf("i is %i\n", i);
            printf("#\n");
        }
    }
    ```

- Wenn Sie diesen Code ausführen, werden Sie zahlreiche Ausgaben sehen, darunter `i is 0`, `i is 1`, `i is 2` und `i is 3`. Wenn Sie das sehen, werden Sie vielleicht erkennen, dass der Code wie folgt korrigiert werden muss:
    ```c
    #include <stdio.h>

    int main(void)
    {
        for (int i = 0; i < 3; i++)
        {
            printf("#\n");
        }
    }
    ```

    Beachten Sie, dass das "<=" durch "<" ersetzt wurde.

- Dieser Code kann wie folgt weiter verbessert werden:

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

    void print_column(int height);

    int main(void)
    {
        int h = get_int("Height: ");
        print_column(h);
    }

    void print_column(int height)
    {
        for (int i = 0; i <= height; i++)
        {
            printf("#\n");
        }
    }
    ```

    Beachten Sie, dass das Kompilieren und Ausführen dieses Codes immer noch zu einem Fehler führt.

- Um diesen Fehler zu beheben, werden wir ein neues Werkzeug einsetzen, das uns zur Verfügung steht.
- Dieses Werkzeug zur Fehlersuche ist der sogenannte **Debugger**, ein Softwaretool, das verwendet wird, um Fehler im Code aufzuspüren.
- In VS Code wird Ihnen ein vorkonfigurierter Debugger zur Verfügung gestellt. Auf Rechnern mit ARM-Prozessor, etwa Macs mit Apple-Chip, läuft er im Dev Container nur, wenn der Container in der ARM-Fassung läuft. Einen Container, der vor dem 18. Oktober 2026 eingerichtet wurde, stellen Sie dafür einmal um ([Dev Container auf ARM-Rechnern umstellen](https://inf.zone/extras/setup/devcontainer-arm/)).
- Um diesen Debugger zu verwenden, setzen Sie als erstes einen *Breakpoint* (_Haltepunkt_), indem Sie links neben eine Zeile Ihres Codes klicken – direkt links neben die Zeilennummer. Wenn Sie dort klicken, wird ein roter Punkt erscheinen. Stellen Sie sich dies als ein Stoppschild vor, das den Rechner auffordert, eine Pause einzulegen, damit Sie sich ansehen können, was in diesem Teil Ihres Codes passiert.

    ![Haltepunkt](https://cs50.harvard.edu/x/2024/notes/2/cs50Week2Debugging.png "Haltepunkt")

- Zweitens: Führen Sie `debug50 ./buggy0` aus. Sie werden feststellen, dass, nachdem der Debugger aktiviert worden ist, eine Zeile Ihres Codes farbig markiert wird. Der Debugger hat den Rechner an dieser Codezeile _angehalten_. Beachten Sie in der oberen linken Ecke des Fensters, dass alle lokalen Variablen angezeigt werden, einschließlich `i`, das aktuell noch keinen Wert hat. Am oberen Rand des Fensters können Sie auf die mit einem Pfeil dargestellte Schaltfläche `step over` klicken (achten Sie auf den Tooltip beim Überfahren mit der Maus), und der Code wird weiter durchlaufen. Beachten Sie, wie sich der Wert von `i` ändert.
- Dieses Werkzeug zeigt Ihnen zwar nicht, wo Ihr Fehler liegt, aber es hilft Ihnen, zu sehen, wie Ihr Code Schritt für Schritt abläuft. Sie können die Schaltfläche `step into` benutzen, um bei der Schritt-für-Schritt-Ausführung in eine Funktionen hineinzuschauen, anstatt diese mit *step over* zu überspringen.
- Eine weitere Form der Fehlersuche wird **Rubber Duck Debugging** genannt. Wenn Sie Probleme mit Ihrem Code haben, überlegen Sie sich, wie Sie mit einer Gummiente laut über das Codeproblem sprechen können. Wenn Sie lieber nicht mit einer kleinen Plastikente sprechen möchten, können Sie gerne mit einem Menschen in Ihrer Nähe sprechen! Diese Person muss nicht wissen, wie man programmiert: Es ist einfach so, dass man oft merkt, wo das Problem ist, wenn man seine Gedanken in Worte fasst. Probieren Sie es aus, *Rubber Duck Debugging* funktioniert wirklich!
- Schließlich gibt es die Möglichkeit, sich von KI-Werkzeugen beim Debugging helfen zu lassen. Auf der Kursseite ist das Susi: Lassen Sie sich eine Fehlermeldung erklären oder einen Hinweis geben, und beheben Sie den Fehler dann selbst.

**Selbsttest:**

Die vier Methoden zur Fehlersuche aus der Vorlesung: `printf`, Debugger, ???, KI-Werkzeuge.

**Antwort:**

**Rubber Duck Debugging**.

**Selbsttest:**

Warum gibt `for (int i = 0; i <= 3; i++)` vier statt der geplanten drei Steine aus?

**Antwort:**

Wegen **`<=` statt `<`**: Die Schleife läuft für `i` gleich 0, 1, 2 und 3.

**Selbsttest:**

Was ist ein Debugger?

**Antwort:**

Ein **Softwaretool, um Fehler im Code aufzuspüren**. Es zeigt, wie Ihr Code Schritt für Schritt abläuft.

**Selbsttest:**

Wozu setzt man im Debugger einen Breakpoint (Haltepunkt)?

**Antwort:**

Damit der Rechner **an dieser Zeile anhält** und Sie sich ansehen können, was dort im Code passiert.

**Selbsttest:**

Mit welchem Befehl starten Sie in VS Code den Debugger für das Programm `buggy0`?

**Antwort:**

**`debug50 ./buggy0`**

**Selbsttest:**

Was tut im Debugger `step into` bei einem Funktionsaufruf, anders als `step over`?

**Antwort:**

Es **geht in die Funktion hinein** und führt sie Schritt für Schritt aus. `step over` überspringt sie.

**Selbsttest:**

Warum hilft Rubber Duck Debugging?

**Antwort:**

Wenn man **seine Gedanken in Worte fasst**, merkt man oft selbst, wo das Problem ist.

## Typen

- Eine der Schwächen von C ist, dass es sich von Haus aus nur in geringem Maß um die Speicherverwaltung kümmert. Zwar bietet C eine enorme Kontrolle über die Nutzung des Speichers, doch müssen Sie sich aller möglichen **Fallstricke der Speicherverwaltung** bewusst sein, um keine Fehler zu machen.
- Typen sind sehr wichtig, da jeder Typ bestimmte Grenzen hat und Regeln unterworfen ist. Zum Beispiel kann man in einem `int` wegen der Grenzen des Speichers nur maximal 4294967296 verschiedene Werte ablegen (int-Werte belegen 32 Bit).
- Die Anzahl der Bits begrenzt, wie hoch und niedrig wir zählen können.
- Wenn Sie aber versuchen, mit einem `int` höher als 2147483647 zu zählen, kommt es zu einem **Integer Overflow**, bei dem ein falscher Wert (typischerweise `-2147483648`) in der Variablen gespeichert wird. Der `int` ist nämlich eine Ganzzahl mit Vorzeichen (`signed`) und eines der 32 Bit wird für das Vorzeichen benutzt. Daher können wir – anders als man erwarten würde – nur bis 2<sup>31</sup> – 1 zählen.

- Zu den vier Typen vom Anfang ([Variablen und Datentypen](#c-variablen-datentypen)) kommen drei weitere:
    - `long`, Ganzzahlen mit mehr Bits (meist 64), die also viel höher zählen können als ein `int`. Eingabe mit `get_long`, Ausgabe mit `%li`.
    - `float`, eine Fließkommazahl, also eine Zahl mit Nachkommastellen. Eingabe mit `get_float`, Ausgabe mit `%f`.
    - `double`, eine Fließkommazahl mit mehr Bits und damit mehr genauen Stellen als ein `float`. Eingabe mit `get_double`, Ausgabe ebenfalls mit `%f`.

- Auch feste Werte im Quelltext haben einen Typ. Solche Werte wie `42`, `3.14`, `'a'` oder `"Hallo"` heißen **Literale**. Eine ganze Zahl ohne Punkt wie `3` ist ein `int`, eine Zahl mit Punkt wie `3.0` eine Fließkommazahl. Deshalb ergibt `4 / 3` den Wert `1` und `4 / 3.0` den Wert `1.333333` (mehr bei der [Ganzzahldivision](#ganzzahldivision-nachkommastellen-werden-abgeschnitten)).

**Selbsttest:**

Wie nennt man es, wenn ein `int` über 2147483647 hinaus zählen soll und dabei ein falscher Wert entsteht?

**Antwort:**

**Integer Overflow**.

**Selbsttest:**

Warum kann ein `int` nur bis 2 hoch 31 minus 1 zählen, obwohl er 32 Bit hat?

**Antwort:**

Er ist **vorzeichenbehaftet** (`signed`): **Eines der 32 Bit wird für das Vorzeichen** benutzt.

**Selbsttest:**

Was unterscheidet `long` von `int`?

**Antwort:**

Ein `long` hat **mehr Bits** und kann also höher zählen.

### Ganzzahldivision: Nachkommastellen werden abgeschnitten

Ersetzen Sie im Taschenrechner `x + y` durch `x / y` und geben Sie 1 und 3 ein, erhalten Sie `0` und nicht 0,333…. Teilt man in C eine Ganzzahl durch eine Ganzzahl, ist auch das Ergebnis eine Ganzzahl: C **schneidet die Nachkommastellen ab** (englisch *truncation*). Gerundet wird nicht. `7 / 2` ergibt `3`, `2 / 3` ergibt `0` und `-7 / 2` ergibt `-3`.

Es hilft auch nicht, das Ergebnis in einer `float`-Variablen zu speichern: `float z = x / y;` ergibt `0.000000`, denn die Nachkommastellen sind schon bei der Division verloren. Sie müssen die Werte vorher in `float` umwandeln (englisch *cast*): `(float) x / (float) y` ergibt `0.333333`.

Es genügt, dass **ein Operand** eine Fließkommazahl ist: Dann rechnet C mit Nachkommastellen. Auch `(float) x / y` ergibt `0.333333`. Stehen die Zahlen fest im Quelltext, schreiben Sie eine davon mit Nachkommastelle: `4 / 3` ergibt `1`, `4 / 3.0` ergibt `1.333333`. Denn eine Zahl ohne Punkt wie `3` ist für C ein `int`, eine mit Punkt wie `3.0` eine Fließkommazahl.

**Selbsttest:**

Was gibt `printf("%i\n", 7 / 2);` aus?

**Antwort:**

**`3`**. Bei der Division zweier Ganzzahlen **schneidet C die Nachkommastellen ab** (Truncation). Gerundet wird nicht.

**Selbsttest:**

`x` und `y` sind `int`-Variablen mit den Werten 1 und 3. Warum ergibt `float z = x / y;` trotzdem 0?

**Antwort:**

`x / y` ist eine **Ganzzahldivision**: Die Nachkommastellen sind schon abgeschnitten, bevor das Ergebnis in `z` landet. Abhilfe: die Werte vorher umwandeln, `(float) x / (float) y`.

**Selbsttest:**

Was gibt `printf("%f\n", 4 / 3);` aus, und wie ändern Sie die Rechnung, damit `1.333333` herauskommt?

**Antwort:**

`4 / 3` teilt zwei `int`-Werte, das Ergebnis ist `1`, und `%f` passt nicht zu einem `int`: `make` bricht ab. Es genügt, **einen Operanden** als Fließkommazahl zu schreiben: `4 / 3.0` (oder `4.0 / 3`) ergibt `1.333333`.

### Fließkomma-Ungenauigkeit: Die Messbecher-Analogie

Ein besonderes Problem bei der Programmierung betrifft Fließkommazahlen (`float` und `double`). Diese können manche Zahlen nicht präzise darstellen. Ein gutes Beispiel ist der Bruch 1/3:

Stellen Sie sich einen Messbecher vor: Er hat Markierungen für 1/4, 1/2 und 3/4. Aber wo ist die Markierung für 1/3? Sie existiert nicht! Wenn Sie 1/3 Liter abmessen sollen, müssen Sie **schätzen** – irgendwo zwischen der 1/4- und 1/2-Markierung.

Genauso funktionieren `float`-Variablen: Sie haben eine **begrenzte Präzision**. Sie können viele Zahlen darstellen, aber nicht alle exakt. Ein `float` ist wie ein Messbecher mit wenigen Markierungen, ein `double` hat mehr Markierungen (also bessere Genauigkeit), aber auch ein `double` ist nicht perfekt.

Daher sehen Sie manchmal statt 0,333333... plötzlich 0,33333334 – der Computer musste schätzen, weil die exakte Darstellung von 1/3 mit endlich vielen Bits unmöglich ist.

Deshalb vergleichen Sie Fließkommazahlen nicht mit `==`. Schon `0.1 + 0.2 == 0.3` ist in C falsch, weil keine der drei Zahlen exakt dargestellt wird.

**Praktischer Tipp:** Verwenden Sie niemals `float` oder `double` für Geldbeträge! Nutzen Sie stattdessen Ganzzahlen (z.B. Cent-Beträge als `int`), um Rundungsfehler zu vermeiden.

- Achten Sie beim Programmieren besonders auf die Arten von Variablen, die Sie verwenden, um Probleme in Ihrem Code zu vermeiden.
- Wir haben uns in der Vorlesung einige Beispiele für Katastrophen angesehen, die durch speicherbezogene Fehler entstehen können (Jahr-2000-Problem, Jahr-2038-Problem, Pac Man Level 256, Donkey Kong Level 22,  Boeing 787).

**Selbsttest:**

Warum zeigt ein `float` für 1/3 nicht exakt 0,333… an?

**Antwort:**

Fließkommazahlen haben eine **begrenzte Präzision**: 1/3 lässt sich mit endlich vielen Bits nicht exakt darstellen, der Computer muss schätzen.

**Selbsttest:**

Welchen Typ sollten Sie für Geldbeträge verwenden?

**Antwort:**

**Ganzzahlen**, etwa Cent-Beträge als `int`, niemals `float` oder `double`. So vermeiden Sie Rundungsfehler.

## Was davon zur Basis gehört

Die Shorts zu diesem Abschnitt sagen auf ihren Seiten, welche Folien wozu gehören.

- **Basis-Code** (Programmieren können):
    - Variablen, Datentypen, Operatoren, Bedingungen, Schleifen, Ausgabe mit printf (Formatcodes, Escape-Sequenzen)
    - Funktionen, Parameter, Rückgabewerte, Scope
    - Integer Overflow (erkennen und umgehen)
    - Ganzzahldivision umgehen (ein Operand als Fließkommazahl: Cast oder Literal wie 3.0), Float-Ungenauigkeit umgehen (größerer Typ; Geldbeträge in Cent als int)
    - Kommentare, Codestil (Einrückung, Klammersetzung, sprechende Namen)
    - Eingabevalidierung (Schleife bis zur gültigen Eingabe)
    - Symbolische Konstante mit #define anlegen
    - Einfache Shell-Befehle (cd, ls, cp, mv, mkdir, rm, cat, pwd)

- **Basis-Konzept** (Erklären und von Hand durchspielen):
    - switch lesen, auch das Durchfallen ohne break
    - Compiler-Fehlermeldungen lesen; Syntax-, Logik- und Designfehler unterscheiden
    - Magic Numbers erkennen

- **Kür-Code** (Anwenden und schreiben):
    - const-Variablen
    - Progressives Refactoring
    - Pipes, Umleitungen, Wildcards, Textfilter (sort, uniq, cut), komplexere Shell-Konstruktionen

- **Hintergrund** (Einordnung):
    - Manual Pages (man)

Was die Labels bedeuten und die ganze Liste: [Basis und Kür](https://inf.zone/extras/basis/).

## Zusammenfassung

In dieser Vorlesung haben Sie gesehen, wie Sie die Bausteine, die Sie in Scratch kennengelernt haben, auf die Programmiersprache C anwenden können. Sie haben gelernt:

- wie Sie Funktionen aus Bibliotheken benutzen und Ihre eigenen Funktionen schreiben;
- wie Sie Variablen, Bedingte Anweisungen und Schleifen verwenden;
- wie man Abstraktion einsetzt, um seinen Code zu vereinfachen und zu verbessern;
- wie man bei der Lösung eines Informatikproblems vorgeht;
- wie man die Linux-Kommandozeile benutzt;
- wie man Kommentare in seinen Code einbaut;
- wie man Typen und Operatoren verwendet.

Außerdem haben Sie gesehen, wie Sie Fehler finden: erklären (Rubber Duck), mit `printf` nachsehen und mit dem Debugger anhalten.

Dies war Inf-Einf-B. Bis zum nächsten Mal!

*Die Fragen zum Selbsttest helfen beim aktiven Lesen. Sie sind kein Vorgeschmack auf die Prüfung: Fragen und Antworten auswendig zu lernen reicht nicht zum Bestehen und ist vermutlich auch keine sinnvolle Vorbereitung. Was hilft: [Wie Sie Inf-Einf-B bewältigen](https://inf.zone/extras/lernen/#was-funktioniert--und-was-nicht-funktioniert).*

