Zusammenfassung
Diese Lektion eröffnet die achte und letzte Einheit des Kurses, die den größeren Programmen gewidmet ist. Sie erklärt ihren Zweck: Programme zu organisieren, zu überprüfen und zu debuggen, die weder in eine Datei noch in den Kopf passen; sie stellt ihre drei Lektionen vor und den Faden, der sie verbindet und den in der ersten Lektion des Kurses geöffneten Kreis schließt (spezifizieren, bauen, überprüfen); sie ruft in Erinnerung, was die Einheit voraussetzt, nämlich den ganzen Kurs; sie formuliert das Problem, das die Einheit löst, das eines Programms aus einer einzigen Datei, das mit den Daten funktioniert, mit denen es getestet wurde, und einen Fehler an der Grenze seiner Spezifikation verschweigt; sie nimmt den Unterschied zwischen Testen und Beweisen vorweg; und sie zeigt, wohin sie führt, im Abschlussprojekt und in Programmieren in C++ II.
Lernziele
- Die Abfolge der Inhalte der Einheit beschreiben und erklären, was jede Lektion zur folgenden beiträgt.
- An einem Beispiel den Unterschied zwischen dem Deklarieren und dem Definieren einer Funktion in Erinnerung rufen, ebenso den Vertrag, der sie spezifiziert, und die Etappen (Kompilierung und Linken), die mehrere Dateien in ein Programm verwandeln.
- An einem Beispiel den Unterschied zwischen dem Testen eines Programms mit einigen Fällen und dem Beweis vorwegnehmen, dass es für alle zulässigen Fälle korrekt ist.
- Erkennen, was man am Ende der Einheit und des Kurses können soll, und es von dem unterscheiden, was man in Programmieren in C++ II lernen wird.
Eingangstest
Bevor man die Einheit durcharbeitet, lohnt es sich, den Ausgangspunkt zu bestimmen. Dieser Test wird nicht benotet: Er leitet das Lernen. Die ersten sieben Fragen prüfen, was die Einheit voraussetzt (Deklarieren und Definieren, die Vorbedingung, den Vertrag einer Funktion aus Einheit 6, die Meldungen des Linkers, die Fälle einer binären Suche, die Ablauftabelle (Trace-Tabelle) und das Lesen außerhalb eines Vektors); die drei folgenden behandeln in der Reihenfolge der Lektionen die zentralen Ideen der Einheit, und bei ihnen ist „Das weiß ich noch nicht“ eine ehrliche Antwort. Jede Antwort erklärt den Punkt und nennt die Lektion, die ihn behandelt; dieselben Fertigkeiten werden in der Synthese-Lektion erneut gemessen.
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.
Frage 1Aus früheren EinheitenWas bewirkt die Zeile
int gcd(int a, int b);, die vormainsteht?Verwechselt Deklaration und Definition: Ohne Rumpf gibt es nichts auszuführen, und keine Funktion wird ausgeführt, weil sie geschrieben steht, sondern wenn sie aufgerufen wird.Verwechselt Deklarieren mit Aufrufen: Ein Aufruf trägt nicht die Typen der Parameter.Übersieht, dass dem Compiler die Signatur genügt, um einen Aufruf zu prüfen; das Fehlen des Rumpfes entdeckt, wenn niemand ihn schreibt, der Linker, nicht der Compiler.Eine Deklaration genügt, damit der Compiler jeden Aufruf prüft; die Definition mit dem Rumpf kann weiter unten oder in einer anderen Datei stehen. Die ganze Lektion Mehrere Dateien und eigene Bibliotheken beruht auf dieser Trennung: Der Header deklariert, die Implementierungsdatei definiert.Wiederholen: Funktionen
Frage 2Aus früheren EinheitenDie Funktion
toBase(n, base)hat die Vorbedingung „n >= 0und2 <= base <= 10“. Wer muss sie garantieren?Verwechselt die Vorbedingung mit der Validierung der Eingaben: Validieren ist Aufgabe der Grenze des Programms, nicht jeder einzelnen Funktion.Glaubt, Kommentare würden überprüft; der Compiler verwirft sie.Sieht nicht, dass der Vertrag Pflichten verteilt; ohne ihn weiß niemand, wer sich geirrt hat, wenn etwas fehlschlägt.Die Vorbedingung ist der Teil des Vertrags, der den Aufrufer verpflichtet; im Gegenzug garantiert die Funktion ihre Nachbedingung. Wird die Vorbedingung verletzt, verspricht die Funktion nichts. Die Lektion Testen wird lehren, sie mitassertzu prüfen, solange das Programm entwickelt wird.Wiederholen: Funktionen
Frage 3Aus früheren EinheitenDie Funktion
binarySearch(values, target)aus Lektion 6.4 gibt eine Position vontargetzurück odervalues.size(), wenn es nicht vorkommt. Was ist ihre Vorbedingung?Mit dem leeren Vektor macht die Schleife keinen einzigen Durchlauf, und die Funktion gibt 0 zurück, wasvalues.size()ist: Der Fall ist durch die Nachbedingung abgedeckt.Die Funktion meldet das Fehlen; das Vorkommen zu verlangen, würde sie nutzlos machen.Bei Wiederholungen gibt die Funktion eine der Positionen des Wertes zurück, was die Nachbedingung zulässt.Jeder Durchlauf verwirft die Hälfte des Intervalls durch den Vergleich mit dem mittleren Element, und das ist nur gültig, wenn der Vektor sortiert ist. Mit unsortierten Daten antwortet die Funktion ohne Warnung etwas Falsches. Die Vorbedingung steht im Vertrag, wo der Aufrufer sie sieht.Wiederholen: Suchen und Sortieren
Frage 4Aus früheren EinheitenEin Programm kompiliert ohne Fehler, und beim Erzeugen der ausführbaren Datei erscheint
undefined reference to `tetrahedral(int)'. Welche Etappe ist gescheitert?Unterscheidet die Meldungen des Compilers, die eine Datei und eine Zeile nennen, nicht von denen des Linkers, die Objekte und Namen nennen.Das Programm ist nie entstanden: Ohne ausführbare Datei gibt es keine Ausführung.Ein fehlendes#includeerzeugt beim Kompilierenwas not declared in this scope, nicht diese Meldung.Der Compiler hat jeden Aufruf akzeptiert, weil er eine Deklaration sah; der Linker hat die Definition in allen Objekten und in den Bibliotheken gesucht und nicht gefunden. Die Lektion Mehrere Dateien und eigene Bibliotheken erklärt die üblichen Ursachen: eine Datei, die nicht kompiliert wurde, oder eine Deklaration, die mit einem anderen Typ kopiert wurde.Wiederholen: Programme, Compiler und C++
Frage 5Aus früheren EinheitenWelche dieser Mengen von Fällen stellt eine binäre Suche am besten auf die Probe?
Verwechselt Menge mit Abdeckung: Sie testet nie das Fehlen und nie die Grenzen, an denen die Fehler gewöhnlich liegen.Ein Fall, der schon bestanden wurde, ist der, der am wenigsten wahrscheinlich etwas Neues aufdeckt.Es sind unendlich viele, oder innerhalb der Grenzen des Typs astronomisch viele: Testen verlangt Auswahl.Jeder Fall prüft eine andere Grenze des Intervalls : das von Anfang an leere Intervall, das auf ein Element schrumpfende, die Enden und die drei Arten, nicht vorzukommen. Die Fälle aus der Spezifikation zu wählen, nach Bereichen und Grenzen, ist das Thema der Lektion Testen.Wiederholen: Suchen und Sortieren
Frage 6Aus früheren EinheitenWelche Werte haben
aundbnachint a{0}; int b{1}; for (int i{0}; i < 4; ++i) { const int t{a + b}; a = b; b = t; }?Zählt einen Durchlauf zu viel: Miti < 4wird der Rumpf viermal ausgeführt, nicht fünfmal.Zählt einen Durchlauf zu wenig, der symmetrische Off-by-one-Fehler.Vergisst, dasstdie Summe aufbewahrt, die berechnet wurde, bevor sichaändert: Im letzten Durchlauf erhältadie 3 vonb, aberberhält jene Summe, 5, und nicht den neuen Wert vona.Frage 7Aus früheren EinheitenWarum hält
std::vector<int> v{1, 2}; std::println("{}", v[2]);mit den Optionen des Kurses an und kann, nur mit-O2kompiliert und ohne die Sanitizer, eine beliebige Zahl ausgeben?Glaubt, die Optimierung repariere Fehler; sie entfernt nur Prüfungen und nimmt an, dass das Programm den Standard nicht verletzt.Kehrt die Wirkung um: Die Prüfung, die das Programm anhält, ist die der Bibliothek ohne Optimierung.Das ist der Off-by-one-Fehler bei Indizes: Die eines Vektors mit zwei Elementen sind 0 und 1.Frage 8Ein Header mit Include-Guards definiert (und deklariert nicht nur)
double scale(double x), ohneinline, undmain.cppundreport.cppbinden ihn ein. Was geschieht beim Erzeugen des Programms?Glaubt, die Guards wirkten über Dateien hinweg; sie wirken innerhalb jeder Übersetzungseinheit.Verwechselt die Datei, die kompiliert wird, mit dem ganzen Programm: Innerhalb jeder Datei gibt es nur eine Definition.Das ist eine ehrliche Antwort: Lektion 8.1 zeigt es mit der echten Meldung des Linkers.Die Guards verhindern, dass ein Header zweimal in dieselbe Datei gelangt, aber jede.cppwird getrennt kompiliert und erhält ihre Kopie der Definition: Der Linker findet zwei. Das ist die One-Definition-Rule (Regel der einen Definition) aus der Lektion Mehrere Dateien und eigene Bibliotheken.Wiederholen: Mehrere Dateien und eigene Bibliotheken
Frage 9Eine Funktion besteht fünfhundert sorgfältig gewählte automatisierte Tests. Was kann man behaupten?
Verwechselt Fülle mit Beweis; ein Fehler an einer Grenze, die kein Fall berührt hat, übersteht jede Anzahl innerer Fälle.Die Fälle sind keine Zufallsstichprobe der möglichen Fehler, und die Häufigkeit der Treffer misst nicht die Wahrscheinlichkeit, dass das Programm stimmt.Das ist eine ehrliche Antwort: Lektion 8.2 beginnt mit dieser Frage.Ein Test kann die Anwesenheit eines Fehlers zeigen, nie seine Abwesenheit: Die Korrektheit für alle Fälle zu behaupten, verlangt ein Argument, wie die Invariante aus Lektion 4.3, keine Liste von Fällen. Gut gewählte Tests machen es unwahrscheinlich, dass ein häufiger Fehler durchschlüpft, und deshalb sind sie so viel wert. Die Lektion Testen entwickelt diese Unterscheidung.Wiederholen: Testen
Frage 10Ein Haltepunkt liegt auf der Zeile
total += k;innerhalb einer Schleife, und das Programm hält dort zum dritten Mal an. Was zeigt die hervorgehobene Zeile an?Verwechselt das Anhalten mit dem schon getanen Schritt.Verwechselt die Stelle, an der das Programm anhält und die die debuggende Person wählt, mit der Ursache des Fehlverhaltens.Das ist eine ehrliche Antwort: Lektion 8.3 behandelt die Haltepunkte und die Schritte.
Inhalt wird geladen…
Abgeschlossen
Melde dich an, um deinen Fortschritt zu speichern