Zum Inhalt springen
Topos Uranos

Zusammenfassung

Diese Lektion eröffnet die erste Einheit des Kurses, die den ersten Schritten im Programmieren mit C++ gewidmet ist. Sie erklärt, wozu die Einheit dient: jemanden, der nie programmiert hat, von einem in der Alltagssprache formulierten Problem zu einem Programm zu führen, das kompiliert, läuft, Daten liest und Ergebnisse schreibt, und dabei zu wissen, was jedes Werkzeug unterwegs getan hat; sie stellt ihre sechs Lektionen vor und den Faden, der sie verbindet, vom auf Deutsch geschriebenen Algorithmus bis zur Einteilung der Fehler; sie bestimmt das Wenige, was vorausgesetzt wird, nämlich die Schularithmetik, die Gewohnheit, schriftlichen Anweisungen zu folgen, und den Umgang mit Dateien und Ordnern; sie formuliert das Problem, das die Einheit löst, nämlich eine Rechnung, die man von Hand auszuführen weiß, in ein Verfahren umzuwandeln, das eine Maschine ausführt, ohne sich zu irren und ohne zu ermüden; und sie zeigt, wohin sie führt, in den folgenden Einheiten und im Kurs Programmieren in C++ II.

Lernziele

  1. Die Abfolge der Inhalte der Einheit beschreiben und erklären, was jede Lektion zur nächsten beiträgt.
  2. Die Vorkenntnisse erkennen, die der Kurs voraussetzt (mit ganzen Zahlen und Dezimalzahlen rechnen, einen Quotienten und einen Rest berechnen, schriftlichen Anweisungen folgen, eine Datei in einem bestimmten Ordner speichern), und sie bei Bedarf wiederholen.
  3. An einem Beispiel den Weg erklären, den die Einheit zurückzulegen lehrt: von der Aufgabenstellung zur Spezifikation, von der Spezifikation zum Algorithmus und vom Algorithmus zum Programm, das kompiliert und ausgeführt wird.
  4. Erkennen, was man am Ende der Einheit können soll, und es von dem unterscheiden, was in den folgenden Einheiten gelernt wird.

Eingangstest

Bevor man die Einheit durcharbeitet, lohnt es sich, den Ausgangspunkt zu bestimmen. Dieser Test ist eine Selbstüberprüfung: Er wird nicht benotet, und sein einziger Zweck ist es, das Lernen zu leiten. Da dies die erste Einheit des Kurses ist, gibt es keine Fragen zu früheren Einheiten; stattdessen prüfen die ersten drei, was der Kurs voraussetzt: den Quotienten und den Rest einer ganzzahligen Division, die Reihenfolge der Schritte eines Verfahrens sowie den Namen, die Endung und den Ordner einer Datei. Die sieben folgenden behandeln der Reihe nach die zentralen Ideen der sechs Lektionen der Einheit. Wer nie programmiert hat, sollte nicht erwarten, sie richtig zu beantworten, und das macht nichts: Jede Antwort, ob richtig oder nicht, erklärt den Punkt und nennt die Lektion, die ihn behandelt. Dieselben Fertigkeiten werden am Ende erneut gemessen, in der Synthese-Lektion.

Eingangstest

Miss vor Beginn der Einheit deinen Ausgangspunkt. Es ist eine kurze Selbsteinschätzung: Sie wird nicht benotet, und das Ergebnis wird nur in deinem Browser gespeichert.

  1. Frage 1Aus früheren Einheiten47 Blätter werden an 6 Personen in gleichen ganzen Teilen verteilt, und die Blätter, die für eine vollständige Runde nicht reichen, werden aufbewahrt. Wie viele erhält jede Person und wie viele werden aufbewahrt?

  2. Frage 2Aus früheren EinheitenUm eine Datei als Anhang per E-Mail zu versenden, gibt es vier Schritte: A, die Adresse des Empfängers schreiben; B, auf „Senden“ klicken; C, eine neue Nachricht öffnen; D, die Datei anhängen. Welche Reihenfolge ist die richtige?

  3. Frage 3Aus früheren EinheitenEine Datei ist unter C:\Users\ana\programas\suma.cpp gespeichert. Wie lautet ihr Name, wie ihre Endung, und in welchem Ordner liegt sie?

  4. Frage 4Ein Rezept sagt: „Wenn der Teig trocken ist, einen Löffel Wasser hinzufügen und kneten; wiederholen, bis er es nicht mehr ist“. Der Teig braucht genau drei Löffel, um nicht mehr trocken zu sein. Wie oft wird gefragt, ob der Teig trocken ist?

  5. Frage 5Welche dieser Anweisungen kann jede Person, oder eine Maschine, auf genau dieselbe Weise befolgen?

  6. Frage 6Ein Programm kompiliert ohne Fehler und Warnungen, läuft mit vielen Daten gut und bricht bei einem bestimmten mit der Meldung „division by zero“ ab. Zu welchem Zeitpunkt trat der Fehler auf?

  7. Frage 7Visual Studio Code wurde mit seiner C++-Erweiterung installiert, und auf g++ --version im Terminal antwortet dieses, es erkenne g++ nicht. Was ist am wahrscheinlichsten?

  8. Frage 8Der Compiler schreibt eine Meldung, die mit warning: beginnt, und erzeugt trotzdem die ausführbare Datei. Was bedeutet das?

  9. Frage 9Wo beginnt die Ausführung eines C++-Programms?

  10. Frage 10Ein Programm deklariert int age{};, führt std::cin >> age; aus, um ein Alter zu lesen, und der Benutzer gibt abc ein. Was geschieht?

Die Inhalte der Einheit

Die Einheit hat sechs Lektionen, die der Reihe nach den Weg von einem Problem zu einem funktionierenden Programm zurücklegen. Jede setzt die vorige voraus, und die erste setzt nichts von der Sprache voraus.

  • Vom Problem zum Algorithmus. Der Kurs beginnt ohne Code, weil der Algorithmus dem Programm vorausgeht. Die Lektion lehrt, ein Problem durch seine Eingabe, seine Ausgabe und die Beziehung zwischen beiden zu spezifizieren (die Vorbedingung und die Nachbedingung); einen Algorithmus in nummerierten Schritten unzweideutig zu beschreiben; ihn mit einer Ablauftabelle von Hand nachzuvollziehen; in ihm Sequenz, Entscheidung und Wiederholung zu erkennen; und mit einer Größe, die in jedem Durchgang abnimmt, zu begründen, dass eine Wiederholung terminiert.
  • Programme, Compiler und C++. Ein für eine Maschine geschriebener Algorithmus ist ein Programm, und ein C++-Programm wird nicht so ausgeführt, wie es geschrieben ist: Der Präprozessor, der Compiler und der Linker wandeln es in eine ausführbare Datei um. Die Lektion geht diese drei Phasen durch, unterscheidet, was beim Kompilieren entdeckt wird, von dem, was sich erst beim Ausführen zeigt, vergleicht das kompilierte Modell mit dem interpretierten und ordnet die Standards der Sprache zeitlich ein, bis C++23, den der Kurs verwendet, und C++26, dessen Umsetzung in den Compilern im Gang ist.
  • Die Umgebung unter Windows, macOS und Linux installieren. Drei vollständige Anleitungen, eine pro System, um einen C++23-fähigen Compiler und den Editor Visual Studio Code mit seiner C++-Erweiterung zu installieren, mit einem Testprogramm zu prüfen, dass alles funktioniert, und die häufigen Fehler zu beheben: den Compiler, den das Terminal nicht findet, die alte Version und den Standard, der nicht angefordert wurde.
  • Kompilieren, Ausführen und Konfigurieren. Der Zyklus aus Bearbeiten, Speichern, Kompilieren, Ausführen und Lesen, im Terminal und im Editor, mit dem Kursbefehl. Die Lektion unterscheidet die Fehler, die die ausführbare Datei verhindern, von den Warnungen, die auf verdächtigen Code hinweisen; sie schaltet die Sanitizer ein (den für Speicherfehler, AddressSanitizer, und den für undefiniertes Verhalten, UndefinedBehaviorSanitizer), die das Programm überwachen, während es läuft; und sie erklärt, warum eine Ausgabe seltsame Symbole statt Akzenten und ñ zeigt.
  • Anatomie eines Programms. Das minimale Programm, Teil für Teil: die Include-Direktive und die Header, die Funktion main und der Exit-Code, der Namensraum std, die Anweisungen, die Blöcke und die Kommentare. Die Lektion lehrt, Strukturfehler zu beheben, indem man die Meldungen des Compilers von der ersten an liest, und legt die Stilrichtlinie des Kurses fest.
  • Eingabe, Ausgabe und Fehler. Das Programm verständigt sich mit der Außenwelt: Es schreibt mit std::print und std::println, mit Formatangaben für die Breite und die Nachkommastellen, und liest mit std::cin. Die Lektion zeigt, was geschieht, wenn die Eingabe nicht die erwartete Form hat, und wie man das Lesen prüft, und schließt die Einheit mit der Einteilung der Fehler nach ihrem Zeitpunkt: Kompilierfehler, Linkerfehler, Laufzeitfehler und Logikfehler.

Der Faden, der sie verbindet, ist der des Programms selbst. Die erste Lektion entwirft es, die zweite erklärt, worin es umgewandelt wird, die dritte installiert die Werkzeuge, die es umwandeln, die vierte lehrt, sie zu benutzen und auf das zu hören, was sie sagen, die fünfte zerlegt es, und die sechste bringt es ins Gespräch mit dem, der es benutzt. Ist dem so, dann weiß der Lernende am Ende der Einheit noch sehr wenig über C++, aber er weiß, wie man damit arbeitet, und genau das setzt der übrige Kurs voraus.

Was vorausgesetzt wird

Der Kurs setzt keinerlei Programmiererfahrung voraus. Er setzt dagegen drei Fertigkeiten voraus, die man jetzt wiederholen sollte, falls der Eingangstest Zweifel gezeigt hat.

Die erste ist die Schularithmetik: mit ganzen Zahlen und mit Dezimalzahlen rechnen, die Rangfolge der Rechenarten beachten (Multiplikation und Division vor Addition und Subtraktion, außer bei Klammern) und vor allem den Quotienten und den Rest einer ganzzahligen Division berechnen. Letzteres ist wichtiger, als es scheint. 47 Blätter auf 6 Personen zu verteilen ergibt 7 für jede, und 5 bleiben übrig, was man als 47=6⋅7+547 = 6 \cdot 7 + 5 schreibt, wobei der Rest 55 kleiner als der Divisor 66 ist. C++ hat einen Operator für den Quotienten und einen anderen für den Rest, und ein großer Teil der Rechnungen mit ganzen Zahlen (Sekunden in Stunden umrechnen, die Ziffern einer Zahl trennen, entscheiden, ob eine Zahl gerade ist) lässt sich auf sie zurückführen. Wer sie gründlich studieren will, findet sie samt Beweis im Kurs Algebra und Geometrie I: Zahlen, Funktionen und ebene Geometrie; hier genügt es, sie berechnen zu können.

Die zweite ist die Gewohnheit, schriftlichen Anweisungen buchstabengetreu zu folgen und zu erkennen, wann eine Anweisung nicht genügt, um zu wissen, was zu tun ist. Es handelt sich nicht um ein Wissen, sondern um eine Haltung: „Salz nach Geschmack hinzufügen“ zu lesen und zu bemerken, dass diese Anweisung von dem abhängt, der sie ausführt. Die erste Lektion der Einheit macht aus dieser Haltung eine Methode.

Die dritte ist der grundlegende Umgang mit einem Computer: einen Ordner anlegen, darin eine Datei unter einem gewählten Namen speichern, die Endung des Namens erkennen (.cpp, .txt, .exe) und wissen, in welchem Ordner jede Datei liegt. Es lohnt sich, das System schon jetzt so einzustellen, dass es die Endungen anzeigt, die manche Systeme, wie Windows, standardmäßig ausblenden: Der Quellcode suma.cpp und die ausführbare Datei suma.exe sind sehr verschiedene Dateien, und sie zu verwechseln ist eine Quelle absurder Fehler. Die Einheit lehrt auch den Umgang mit dem Terminal, sodass man ihn nicht vorher beherrschen muss; es genügt, bereit zu sein, Befehle einzutippen, statt Schaltflächen anzuklicken. Programme zu installieren setzt schließlich voraus, dass man es auf dem eigenen Computer tun darf; die Lektion zur Installation nennt eine Online-Alternative für alle, die es nicht können.

Englisch wird nicht vorausgesetzt. Die Meldungen des Compilers sind auf Englisch, und der Kurs lehrt, sie Feld für Feld zu lesen, sodass das Wichtige daran (die Datei, die Zeile, die Art des Defekts) verstanden wird, ohne die Sprache zu beherrschen. Ebenso wenig wird Mathematik über die Schulmathematik hinaus vorausgesetzt: Die Beispiele verwenden die Division, Mittelwerte, das Einmaleins, Daten und Uhrzeiten.

Das Problem, das die Einheit löst

Eine Rechnung, die man von Hand auszuführen weiß, ist noch kein Programm. Den Abstand zwischen beiden lehrt die Einheit zu überwinden, und ein einfaches Problem erlaubt es, ihn zu messen.

BeispielEine Dauer in Stunden, Minuten und Sekunden

Eine Stoppuhr erfasst die Dauer jeder Tätigkeit als Anzahl von Sekunden, zum Beispiel 7384, und man möchte sie in der üblichen Form aus Stunden, Minuten und Sekunden schreiben, mit den Minuten und den Sekunden stets zweistellig: 2:03:04. Von Hand ist die Rechnung eine Kette von Divisionen: 7384=3600⋅2+1847384 = 3600 \cdot 2 + 184, woraus sich 2 Stunden und 184 Sekunden ergeben; 184=60⋅3+4184 = 60 \cdot 3 + 4, woraus sich 3 Minuten und 4 Sekunden ergeben. Für eine einzige Dauer geht das in einer Minute. Für die tausend Dauern eines Protokolls dagegen ist die Rechnung von Hand lang und fehleranfällig, und die Aufgabe bietet sich dafür an, dass eine Maschine sie ausführt.

Nun kann eine Maschine die obige Erklärung nicht entgegennehmen. Sie erhält einen Text in einer Programmiersprache, und um diesen Text zu schreiben, muss man zuvor drei Fragen geklärt haben, die die Rechnung von Hand unausgesprochen ließ. Die erste ist die Spezifikation: was hineingeht (eine ganze, nicht negative Anzahl von Sekunden), was herauskommt (drei ganze Zahlen, die Stunden, die Minuten und die Sekunden) und welche Beziehung sie verbindet: Ist tt die Gesamtzahl, so gilt t=3600h+60m+st = 3600 h + 60 m + s, mit 0≤m<600 \leq m < 60 und 0≤s<600 \leq s < 60. Die zweite ist der Algorithmus: die genauen Schritte, die für jede zulässige Eingabe diese Ausgabe erzeugen.

  1. hh erhält den Wert des Quotienten von tt durch 36003600.
  2. mm erhält den Wert des Quotienten durch 6060, gebildet aus dem Rest von tt durch 36003600.
  3. ss erhält den Wert des Rests von tt durch 6060.
  4. Schreiben: hh, einen Doppelpunkt, mm zweistellig, einen Doppelpunkt und ss zweistellig.

Die dritte ist das Schreiben des Algorithmus in C++, in der genauen Form, die die Sprache verlangt, und seine Übersetzung in eine ausführbare Datei mit den geeigneten Werkzeugen. Das folgende Programm leistet das. Es enthält vieles, was noch nicht erklärt wurde: die Variablen (Lektion 2.1), die Operatoren / und %, die den Quotienten und den Rest der ganzzahligen Division liefern (Lektion 3.1), das Lesen mit std::cin und die Formatangaben (Lektion 1.6); die Formatangabe {:02} dieses Programms, die eine Zahl auf zwei Stellen schreibt und links mit Nullen auffüllt, ist eine Variante der Breite, die jene Lektion lehrt und die Lektion 3.1 verwenden wird. Vorerst genügt es, darin die vier Schritte des Algorithmus wiederzuerkennen.

C++-Programm
#include <iostream>#include <print>​int main(){    int total{};  // Variablen werden in Lektion 2.1 erklärt    std::print("Dauer in Sekunden: ");    std::cin >> total;    const int hours{total / 3600};    const int minutes{total % 3600 / 60};    const int seconds{total % 60};    std::println("{} s = {}:{:02}:{:02}", total, hours, minutes, seconds);}
Programmeingabe
7384
Ausgabe
Dauer in Sekunden: 7384 s = 2:03:04

Die Zeilen 9 bis 11 sind die Schritte 1 bis 3, und die Zeile 12 ist der Schritt 4. Dass das Ergebnis mit dem von Hand berechneten übereinstimmt, ist kein Zufall, sondern die Prüfung, die jedes Programm verdient: es zuerst mit einem Datum zu testen, dessen Antwort man kennt.

Das Programm löst das Problem, aber die Einheit lehrt auch, ihm zu misstrauen. Gibt der Benutzer abc statt einer Zahl ein, so scheitert das Lesen, total bleibt null, und das Programm schreibt ohne jedes Warnsignal, die Dauer betrage 0:00:00: ein falscher Schluss mit dem Anschein eines wahren. Gibt er eine negative Dauer ein, so sagt die Spezifikation nicht, was geschehen soll, und das Ergebnis ist sinnlos. Schreibt man total / 360 statt total / 3600, so kompiliert das Programm, läuft und liefert ein falsches Ergebnis, und kein Werkzeug bemerkt es. Jeder dieser Defekte gehört zu einer anderen Art von Fehler, die zu einem anderen Zeitpunkt entdeckt und auf eine andere Weise gesucht wird; die letzte Lektion der Einheit teilt sie ein. Daraus folgt, dass das Problem, das die Einheit löst, nicht nur darin besteht, dieses Programm zu schreiben, sondern darin, zu wissen, warum es funktioniert, mit welchen Daten es nicht mehr funktioniert und welches Werkzeug vor jedem Defekt warnen wird oder nicht.

Folglich wird der Lernende am Ende der Einheit Programme dieser Art schreiben, kompilieren und ausführen können: einige Eingabedaten, einige Rechnungen nacheinander und einige formatiert geschriebene Ergebnisse. Er wird in C++ noch keine Entscheidungen treffen und keine Anweisungen wiederholen können (wohl aber in einem auf Deutsch geschriebenen Algorithmus), und er wird den Typ jedes Datums noch nicht begründet wählen können; das bringen die folgenden Einheiten.

Wohin sie führt

Die Einheit ist die Schwelle des Kurses. Was in ihr ohne Erklärung verwendet wird, wird später erklärt, und zwar in dieser Reihenfolge. Die Einheit 2, „Daten und Typen“, erklärt die Variablen und wie sie im Speicher abgelegt werden, die Grenzen der ganzen Zahlen (und warum eine korrekte Rechnung überlaufen kann), die Rundung der Dezimalzahlen und die Konvertierungen zwischen Typen. Die Einheit 3, „Ausdrücke und Operatoren“, erklärt die Arithmetik von C++, mit Quotient und Rest negativer Zahlen, die Logik der Bedingungen und das, was der Standard in einem Ausdruck undefiniert lässt. Die Einheit 4, „Kontrollfluss“, überträgt die Entscheidungen und Wiederholungen, die die erste Lektion auf Deutsch schreibt, nach C++ und lehrt zu begründen, dass eine Schleife korrekt ist und terminiert. Die Einheit 5 zerlegt die Programme in Funktionen; die 6 führt die zusammengesetzten Daten ein (Arrays, Vektoren, Tabellen und Datensätze), mit den Such- und Sortieralgorithmen und ihren Kosten; die 7 behandelt den Text, die robuste Eingabe und die Dateien; und die 8 die Programme aus mehreren Dateien, die systematischen Tests und den Debugger.

Nach dem Kurs setzt Programmieren in C++ II mit dem fort, was dieser absichtlich auslässt: den Zeigern und dem dynamischen Speicher, den Klassen mit Methoden, den eigenen Templates, den anonymen Funktionen und den Ausnahmen. Keines dieser Themen ist nötig, um die Probleme dieses Kurses zu lösen, und sie aufzuschieben erlaubt, sich auf das zu konzentrieren, was in jeder Sprache gilt: spezifizieren, den Algorithmus entwerfen, ihn klar schreiben und prüfen, dass er korrekt ist. Die Synthese-Lektion dieser Einheit wird genau diese Unterscheidung aufgreifen, zwischen dem, was C++ eigen ist, und dem, was man in jede andere Sprache mitnehmen wird.