Praktische Informatik
Programmieren: Variablen, Kontrollstrukturen, Unterprogramme
Warum man denselben Ablauf nur einmal aufschreibt: Parameter, Rückgabewert und Gültigkeitsbereich.
Benötigte Grundlagen
Dieses Vorwissen brauchst du für das Kapitel. Schau kurz nach, wenn dir etwas davon nicht mehr präsent ist, sonst leg direkt los.
Einführung
In einem Programm steht dreimal fast derselbe Abschnitt: einmal für die Deutschnote, einmal für Mathe, einmal für Englisch. Nur die Zahlen unterscheiden sich.
Dann ändert sich der Notenschlüssel. Jetzt muss man drei Stellen ändern, findet zwei davon und übersieht die dritte. Das Programm läuft weiter und rechnet in einem Fach falsch, ohne dass irgendetwas gemeldet wird.
Dagegen gibt es ein Werkzeug, und es ist das wichtigste des ganzen Kapitels: das Unterprogramm. Man schreibt den Ablauf einmal, gibt ihm einen Namen und ruft ihn dreimal auf. Ändert sich der Notenschlüssel, ändert man eine Stelle.
Das kannst du nach diesem Kapitel
ein Unterprogramm mit Parametern und Rückgabewert entwerfen und aufrufen.
begründen, warum ein Unterprogramm mehr ist als eine Abkürzung.
lokale und globale unterscheiden und den Gültigkeitsbereich erklären.
einen wiederholten Abschnitt in ein Unterprogramm herauslösen.
Unterprogramme sinnvoll schneiden, also entscheiden, was hineingehört.
Kurz aufgefrischt
Vorausgesetzt werden , Wertzuweisung und die drei Grundbausteine aus Klasse 9. Bei Unsicherheit lies Variablen, Datentypen und Wertzuweisung.
Neu ist hier der vierte Baustein, mit dem Programme über zwanzig Zeilen hinaus überhaupt erst beherrschbar werden.
Das Problem: derselbe Ablauf an drei Stellen
punkteD := 38
prozentD := punkteD / 50 * 100
WENN prozentD >= 87 DANN noteD := 1
SONST WENN prozentD >= 73 DANN noteD := 2
SONST noteD := 3
punkteM := 41
prozentM := punkteM / 50 * 100
WENN prozentM >= 87 DANN noteM := 1
SONST WENN prozentM >= 73 DANN noteM := 2
SONST noteM := 3
Drei Nachteile, die alle drei ins Gewicht fallen:
Änderungsaufwand. Eine neue Grenze bedeutet drei Änderungen. Wer eine übersieht, hat zwei verschiedene Notenschlüssel im selben Programm.
Fehleranfälligkeit. Beim Kopieren vergisst man leicht, alle Variablennamen anzupassen. Steht im zweiten Abschnitt noch , rechnet er mit den Deutschwerten weiter, und zwar völlig geräuschlos.
Unlesbarkeit. Zwanzig Zeilen sagen nur „hier werden Noten berechnet“, und dieser eine Satz geht in den Einzelheiten unter.
Die Lösung: das Unterprogramm
Ein Unterprogramm ist ein benannter, abgeschlossener Ablauf, der von außen aufgerufen wird.
UNTERPROGRAMM note(punkte, maximum)
prozent := punkte / maximum * 100
WENN prozent >= 87 DANN GIB ZURÜCK 1
WENN prozent >= 73 DANN GIB ZURÜCK 2
GIB ZURÜCK 3
ENDE UNTERPROGRAMM
Aufgerufen wird es so:
noteD := note(38, 50)
noteM := note(41, 50)
noteE := note(29, 40)
Aus zwanzig Zeilen sind sechs plus drei geworden, und der Notenschlüssel steht genau einmal da.
Drei Aufrufe, ein Unterprogramm
Zähle die Kästen: drei oben, einer unten. Genau darin liegt der Gewinn, aus zwanzig kopierten Zeilen sind sechs plus drei geworden, und der Notenschlüssel steht nur noch an einer Stelle. Eine neue Notengrenze ist damit eine Änderung statt drei, und niemand kann eine davon übersehen. Verfolge dann die beiden Pfeile: Hinunter gehen die Werte aus den Klammern, herauf kommt das Ergebnis an die Aufrufstelle zurück. Prüfe die Ergebnisse ruhig nach: und liegen beide zwischen 73 und 87, also Note 2; liegt darunter, also Note 3. Dasselbe Unterprogramm, drei verschiedene Antworten.
Die drei Bestandteile
Der Name sagt, was das Unterprogramm tut. Er sollte eine Tätigkeit oder das Ergebnis benennen: , , .
Die Parameter sind die Angaben, die es von außen bekommt. Sie stehen in Klammern hinter dem Namen. Beim Aufruf werden sie durch konkrete Werte ersetzt.
🔴 Genau hier liegt der Unterschied zwischen einer Abkürzung und einem Werkzeug: Ohne Parameter könnte immer nur eine Punktzahl umrechnen. Mit Parametern rechnet dasselbe Unterprogramm jede Punktzahl bei jeder Höchstpunktzahl um. Es löst eine ganze Klasse von Aufgaben, und das ist dieselbe Allgemeingültigkeit, die einen vom Einzelfall unterscheidet.
Der Rückgabewert ist das Ergebnis, das an die Aufrufstelle zurückgegeben wird. Nicht jedes Unterprogramm hat einen: tut etwas, ohne etwas zurückzugeben.
| mit Rückgabewert | ohne Rückgabewert | |
|---|---|---|
| beantwortet | eine Frage | erledigt eine Aufgabe |
| Beispiel | ||
| Aufruf steht | rechts einer Zuweisung | allein in einer Zeile |
Name, Parameter, Rückgabewert
Die drei farbigen Zeilen unter dem Kasten zeigen, woraus jedes Unterprogramm besteht. Am wichtigsten sind die Parameter, und die Fußnote sagt auch warum: Ohne sie könnte genau eine Punktzahl umrechnen und wäre nichts weiter als eine Abkürzung. Mit ihnen rechnet dasselbe Unterprogramm jede Punktzahl bei jeder Höchstpunktzahl um, es löst also eine ganze Klasse von Aufgaben. Das ist genau dieselbe Allgemeingültigkeit, die einen vom Einzelfall unterscheidet. Und der Rückgabewert ist nicht zwingend: beantwortet eine Frage und gibt deshalb etwas zurück, erledigt eine Aufgabe und gibt nichts zurück.
Gültigkeitsbereich: lokal und global
Eine , die innerhalb eines Unterprogramms angelegt wird, ist lokal: Sie existiert nur während des Aufrufs und ist von außen unsichtbar.
UNTERPROGRAMM note(punkte, maximum)
prozent := punkte / maximum * 100 // lokal
...
ENDE UNTERPROGRAMM
SCHREIBE prozent // FEHLER: hier gibt es kein prozent
Das wirkt zunächst wie eine Einschränkung und ist in Wirklichkeit der eigentliche Gewinn. Drei Folgen:
Keine Namenskollisionen. Zwei Unterprogramme dürfen beide eine Variable benutzen, ohne sich zu stören. Ohne lokale Variablen müsste man in einem großen Programm jeden Namen weltweit einmalig vergeben.
Nachvollziehbarkeit. Wer wissen will, warum einen bestimmten Wert hat, muss nur das Unterprogramm lesen, nicht das ganze Programm. Bei einer globalen Variablen kann jede beliebige Stelle sie verändert haben.
Wiederverwendbarkeit. Ein Unterprogramm, das nur über seine Parameter mit der Außenwelt spricht, lässt sich in ein anderes Programm übernehmen, ohne dass man dessen Variablen kennt.
Eine globale Variable ist außerhalb aller Unterprogramme angelegt und überall sichtbar. Sie ist sparsam einzusetzen, denn sie hebt genau diese drei Vorteile auf. Als Faustregel gilt: Was ein Unterprogramm braucht, bekommt es als Parameter, und was es liefert, gibt es zurück.
Innen sichtbar, außen nicht
Der gestrichelte Rahmen ist das Hauptprogramm, der Kasten darin das Unterprogramm und die Namen , und existieren nur innerhalb dieses Kastens. Deshalb scheitert die Zeile darunter: Außerhalb gibt es kein , und zwar nicht aus Bosheit, sondern weil es dort nie angelegt wurde. Das wirkt wie eine Einschränkung und ist der eigentliche Gewinn. Erstens keine Namenskollisionen: Zwei Unterprogramme dürfen beide ein benutzen. Zweitens Nachvollziehbarkeit: Wer wissen will, warum diesen Wert hat, muss nur diesen einen Kasten lesen, bei einer globalen könnte jede beliebige Stelle sie verändert haben. Drittens Wiederverwendbarkeit: Ein Kasten, der nur über seine Parameter mit der Außenwelt spricht, passt in jedes andere Programm.
Wo schneidet man?
Nicht jede Zeilenfolge sollte ein Unterprogramm werden. Drei Anhaltspunkte helfen bei der Entscheidung:
Wiederholung. Steht derselbe Ablauf mehr als einmal da, gehört er heraus. Das ist der klarste Fall.
Benennbarkeit. Kann man dem Abschnitt einen kurzen, treffenden Namen geben? Wenn ja, ist er eine eigenständige Aufgabe. Wenn man nur „macht Dinge mit Zahlen“ sagen kann, ist der Schnitt schlecht gewählt.
Eine Aufgabe. Ein Unterprogramm sollte eine Sache tun. Ein Name mit „und“ darin () ist ein zuverlässiges Zeichen dafür, dass man zwei daraus machen sollte.
Der letzte Punkt hat einen praktischen Grund: Wer später nur einlesen will, ohne zu rechnen, kann ein zusammengeschriebenes Unterprogramm nicht benutzen.
Drei Fragen, und der Schnitt steht
Nicht jede Zeilenfolge sollte ein Unterprogramm werden, diese drei Fragen entscheiden es. Die erste ist der klarste Fall: Steht derselbe Ablauf mehrfach da, gehört er heraus, ohne weitere Diskussion. Die zweite ist ein überraschend zuverlässiger Test: Wenn dir kein kurzer, treffender Name einfällt und du nur „macht Dinge mit Zahlen“ sagen kannst, ist der Schnitt an der falschen Stelle gesetzt. Die dritte hat einen ganz praktischen Grund: Ein Name mit „und“ darin, etwa , verrät, dass zwei Aufgaben zusammengeschrieben wurden. Wer später nur einlesen will, ohne zu rechnen, kann so ein Unterprogramm nicht benutzen.
Was man dabei gewinnt
Der eigentliche Gewinn ist nicht die Ersparnis an Zeilen, sondern etwas anderes: Ein Programm mit gut geschnittenen Unterprogrammen lässt sich stückweise verstehen und prüfen.
Man kann einzeln testen, mit 0 Punkten, mit voller Punktzahl, mit genau 87 Prozent. Ist es richtig, muss man es beim Lesen des Hauptprogramms nicht mehr aufklappen; der Name genügt.
Damit ist das Unterprogramm die praktische Umsetzung der Abstraktion aus dem Modellkapitel: Es verbirgt Einzelheiten, damit man auf der nächsten Ebene arbeiten kann.
Einen wiederholten Abschnitt herauslösen
Ein Programm berechnet an drei Stellen den Flächeninhalt eines Rechtecks und gibt ihn mit Einheit aus. Löse den Abschnitt heraus.
- 1
Vorher, dreimal fast gleich:
flaeche1 := 3 * 4 SCHREIBE flaeche1 + " Quadratmeter" flaeche2 := 7 * 2 SCHREIBE flaeche2 + " Quadratmeter" - 2
Was ändert sich? Nur die beiden Seitenlängen. Sie werden zu Parametern.
- 3
Was bleibt gleich? Die Rechnung und die Ausgabe. Sie kommen ins Unterprogramm.
- 4
Nachher:
UNTERPROGRAMM zeigeFlaeche(a, b) flaeche := a * b SCHREIBE flaeche + " Quadratmeter" ENDE UNTERPROGRAMM zeigeFlaeche(3, 4) zeigeFlaeche(7, 2) - 5
Kein Rückgabewert nötig, weil das Unterprogramm eine Aufgabe erledigt (ausgeben) und keine Frage beantwortet. Bräuchte man die Zahl weiter, würde man stattdessen schreiben und die Ausgabe außerhalb erledigen.
- 6
Und das wäre sogar besser: Ein Unterprogramm, das nur rechnet, lässt sich überall verwenden, auch dort, wo nichts ausgegeben werden soll. Rechnen und Ausgeben zu trennen ist die häufigste sinnvolle Verfeinerung eines Schnitts.
Was sich unterscheidet, wird Parameter; was gleich bleibt, kommt hinein. Rechnen und Ausgeben trennt man besser.
Lokal oder global? Ein Fehler und seine Ursache
Warum liefert dieses Programm ein falsches Ergebnis, und wie behebt man es?
- 1
Der Quelltext:
i := 0 // global UNTERPROGRAMM summe(n) s := 0 i := 1 // benutzt die GLOBALE i SOLANGE i <= n s := s + i i := i + 1 ENDE SOLANGE GIB ZURÜCK s ENDE UNTERPROGRAMM SOLANGE i < 3 SCHREIBE summe(4) i := i + 1 ENDE SOLANGE - 2
Erwartung: Die äußere soll dreimal laufen und dreimal 10 ausgeben.
- 3
Was passiert: Beim ersten Aufruf setzt die globale auf 1 und lässt sie am Ende bei 5 stehen. Zurück in der äußeren Schleife wird auf 6 erhöht, und ist falsch.
- 4
Ergebnis: Die äußere Schleife läuft einmal statt dreimal. Es gibt keine Fehlermeldung, das Programm rechnet nur weniger.
- 5
Ursache: Das Unterprogramm verändert eine , die ihm nicht gehört. Der Aufrufer kann das nicht wissen, denn im Aufruf steht nichts davon.
- 6
Behebung: lokal anlegen, also innerhalb des Unterprogramms. Dann hat jeder Aufruf sein eigenes , die globale bleibt unberührt, und die äußere Schleife läuft dreimal.
Eine globale Variable im Unterprogramm zu verändern erzeugt einen stillen Fehler. Lokale Variablen schließen ihn aus.
Typischer Fehler
„Ich mache alle global, dann muss ich keine Parameter übergeben.“
Das spart beim Schreiben einige Zeichen und kostet beim Suchen Stunden.
Erstens verliert der Aufruf seine Aussagekraft. Bei sieht man, womit gerechnet wird. Bei mit globalen Werten muss man erst herausfinden, welche Variablen das Unterprogramm liest und wo sie zuletzt gesetzt wurden.
Zweitens wird die Fehlersuche unbegrenzt. Steht in einer globalen Variablen ein falscher Wert, kommt jede Stelle des Programms als Ursache in Frage. Bei einer lokalen Variablen ist es genau ein Unterprogramm, meist zehn Zeilen.
Drittens ist das Unterprogramm nicht mehr übernehmbar. Wer es in ein anderes Programm kopiert, muss dort dieselben globalen Variablen anlegen und dafür sorgen, dass sie zum richtigen Zeitpunkt die richtigen Werte tragen. Damit ist der wichtigste Nutzen weg.
Viertens erzeugt es stille Fehler. Wie im Beispiel oben: Ein Unterprogramm verändert nebenbei etwas, worauf der Aufrufer sich verlässt. Es gibt keine Fehlermeldung, nur ein anderes Ergebnis.
Die Regel ist deshalb streng und lohnt sich: Was ein Unterprogramm braucht, bekommt es als Parameter; was es liefert, gibt es zurück. Globale Variablen bleiben Ausnahmefällen vorbehalten, etwa festen Einstellungen, die sich während des Laufs nicht ändern.
Übung 1
leichta) Wozu dienen Parameter? b) Was ist eine lokale ? c) Braucht ein Unterprogramm, das nur etwas ausgibt, einen Rückgabewert? d) Warum ist ein schlechter Name?
Tipp anzeigen
Zu d): Wie viele Aufgaben nennt der Name?
Lösung anzeigen
a) Sie übergeben dem Unterprogramm die Angaben, mit denen es arbeiten soll. Dadurch löst dasselbe Unterprogramm eine ganze Klasse von Aufgaben statt nur eines Einzelfalls.
b) Eine Variable, die innerhalb eines Unterprogramms angelegt wird. Sie existiert nur während des Aufrufs und ist von außen unsichtbar.
c) Nein. Es erledigt eine Aufgabe, statt eine Frage zu beantworten. Ein Rückgabewert wäre nur nötig, wenn die Aufrufstelle mit einem Ergebnis weiterarbeiten soll.
d) Weil er zwei Aufgaben nennt. Wer später nur einlesen will, ohne zu rechnen, kann das Unterprogramm nicht benutzen. Besser sind zwei: und .
Detaillierte Schritterklärung anzeigen
Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.
✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.
- 1
a) Parameter machen aus einem Einzelfall eine Aufgabenklasse
Parameter übergeben dem Unterprogramm die Angaben, mit denen es arbeiten soll. Dadurch löst dasselbe Unterprogramm eine ganze Klasse von Aufgaben statt nur eines Einzelfalls.
- 2
b) Lokale Variablen leben nur während des Aufrufs
Eine lokale Variable wird innerhalb eines Unterprogramms angelegt. Sie existiert nur während des Aufrufs und ist von außen unsichtbar.
- 3
c) Aufgabe erledigen oder Frage beantworten?
Nein. Ein Unterprogramm, das nur etwas ausgibt, erledigt eine Aufgabe, statt eine Frage zu beantworten. Ein Rückgabewert wäre nur nötig, wenn die Aufrufstelle mit einem Ergebnis weiterarbeiten soll.
- 4
d) Ein Name mit „und“ verrät zwei Aufgaben
Weil er zwei Aufgaben nennt. Wer später nur einlesen will, ohne zu rechnen, kann das Unterprogramm nicht benutzen. Besser sind zwei: und .
Übung 2
mittelEin Programm prüft an mehreren Stellen, ob ein Jahr ein Schaltjahr ist. Regel: Ein Jahr ist ein Schaltjahr, wenn es durch 4 teilbar ist, aber nicht durch 100, es sei denn, es ist durch 400 teilbar.
a) Schreibe ein Unterprogramm mit Rückgabewert. b) Prüfe es an den Jahren 2024, 1900, 2000 und 2023. c) Welche sind lokal, welche kämen von außen? d) Ein Mitschüler schlägt vor, das Unterprogramm um die Ausgabe „ist ein Schaltjahr“ zu erweitern. Bewerte den Vorschlag.
Tipp anzeigen
Zu a): Die Ausnahmen prüft man von der speziellsten zur allgemeinsten Regel.
Lösung anzeigen
a) Unterprogramm:
UNTERPROGRAMM istSchaltjahr(jahr) WENN jahr mod 400 = 0 DANN GIB ZURÜCK wahr WENN jahr mod 100 = 0 DANN GIB ZURÜCK falsch WENN jahr mod 4 = 0 DANN GIB ZURÜCK wahr GIB ZURÜCK falsch ENDE UNTERPROGRAMM
Die Reihenfolge ist entscheidend: Zuerst die speziellste Regel (durch 400), dann die Ausnahme (durch 100), dann die Grundregel (durch 4). Umgekehrt geprüft käme für 2000 ein falsches Ergebnis.
b) 2024: nicht durch 400, nicht durch 100, durch 4 → wahr. Richtig. 1900: nicht durch 400, aber durch 100 → falsch. Richtig, 1900 war kein Schaltjahr. 2000: durch 400 → wahr. Richtig. 2023: keine der drei Bedingungen → falsch. Richtig.
c) kommt als Parameter von außen. Weitere Variablen braucht das Unterprogramm nicht; es rechnet direkt mit dem Parameter. Gäbe es Zwischenwerte, wären sie lokal.
d) Schlechter Vorschlag. Das Unterprogramm beantwortet eine Frage und sollte genau das tun. Mit eingebauter Ausgabe wäre es an einer Stelle unbrauchbar, an der man nur wissen will, ob ein Jahr 366 Tage hat, etwa beim Berechnen einer Zeitspanne; dort würde bei jedem Aufruf ungewollt Text erscheinen. Die Ausgabe gehört an die Aufrufstelle:
Detaillierte Schritterklärung anzeigen
Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.
✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.
- 1
Die Regel in Bedingungen zerlegen
Der Regeltext enthält eine Grundregel und zwei Einschränkungen. Man schreibt sie zuerst einzeln auf, bevor man an die Reihenfolge denkt.
Zwischenergebnis
durch 4 → ja · durch 100 → nein · durch 400 → doch ja
Der Ausdruck „es sei denn“ im Aufgabentext ist immer ein Hinweis auf eine Ausnahme von einer Ausnahme. Solche Formulierungen legen die Prüfreihenfolge fest.
- 2
Warum die Reihenfolge über die Richtigkeit entscheidet
Geprüft wird von oben nach unten, und der erste zutreffende Zweig gewinnt. Deshalb muss die speziellste Bedingung zuerst stehen, sonst greift eine allgemeinere zu früh.
2000 \bmod 400 = 0 ;\Rightarrow; \text{wahr}
Zwischenergebnis
400 zuerst, dann 100, dann 4.
- 3
Teil b): Vier Fälle, nicht vier beliebige Jahre
Die vier Prüfjahre sind bewusst gewählt: eines je Kategorie der Regel. Vier zufällige Jahre hätten den 400er-Fall wahrscheinlich gar nicht getroffen.
Zwischenergebnis
2024 (nur durch 4), 1900 (durch 100), 2000 (durch 400), 2023 (durch nichts).
Das ist die allgemeine Testregel: je ein Fall pro Zweig. Damit ist jeder Weg durch das Unterprogramm mindestens einmal gelaufen.
- 4
Teil d): Warum Ausgabe nicht hineingehört
Ein Unterprogramm mit Rückgabewert beantwortet eine Frage. Baut man eine Ausgabe ein, tut es zwei Dinge, und der Aufrufer kann das eine nicht ohne das andere haben.
Zwischenergebnis
Die Ausgabe gehört an die Aufrufstelle, das Unterprogramm bleibt reine Auskunft.
Prüfe solche Vorschläge immer mit der Frage: Gibt es eine Verwendung, bei der ich den Zusatz nicht will? Hier ja, etwa beim Berechnen von Zeitspannen.
Übung 3
schwerEin Programm verwaltet Messreihen. Bisher steht alles in einem Block: einlesen, ungültige Werte aussortieren, Mittelwert berechnen, größten und kleinsten Wert bestimmen, Bericht ausgeben.
a) Schneide das Programm in sinnvolle Unterprogramme und begründe jeden Schnitt. b) Welche haben einen Rückgabewert, welche nicht? c) Ein Unterprogramm soll den Mittelwert berechnen. Was passiert bei einer leeren Liste, und wie behandelst du das? d) Erkläre, warum sich das aufgeteilte Programm besser prüfen lässt als der eine Block.
Tipp anzeigen
Zu a): Jedes Unterprogramm soll genau eine benennbare Aufgabe haben.
Lösung anzeigen
a) Fünf Unterprogramme, je eine benennbare Aufgabe:
leseMesswerte() liefert die Liste. Herausgelöst, weil das Einlesen unabhängig vom Rechnen ist und beim Testen durch feste Beispieldaten ersetzt werden kann. entferneUngueltige(liste) liefert eine bereinigte Liste. Eigene Aufgabe mit eigener Regel, die sich ändern kann, ohne dass die Rechnungen betroffen sind. mittelwert(liste) liefert eine Zahl. groesster(liste) und kleinster(liste) liefern je eine Zahl. Getrennt, weil man häufig nur eines von beidem braucht. zeigeBericht(mittel, max, min) gibt aus. Getrennt vom Rechnen, damit die Rechnungen auch dort verwendbar sind, wo nichts ausgegeben wird.
b) Mit Rückgabewert: leseMesswerte, entferneUngueltige, mittelwert, groesster, kleinster. Alle beantworten eine Frage oder liefern . Ohne: zeigeBericht, denn es erledigt eine Aufgabe.
c) Bei einer leeren Liste müsste durch 0 geteilt werden. Das ist ein Laufzeitfehler, der das Programm abbrechen ließe. Drei Umgangsweisen sind möglich, und man muss sich begründet entscheiden: erstens einen Sonderwert zurückgeben, was gefährlich ist, weil 0 ein gültiger Mittelwert sein kann und der Aufrufer den Unterschied nicht sieht; zweitens die Berechnung mit einer klaren Fehlermeldung abbrechen; drittens die Prüfung an die Aufrufstelle verlagern und im Unterprogramm voraussetzen, dass die Liste nicht leer ist. Am robustesten ist die zweite Variante mit einer aussagekräftigen Meldung, weil sie den Fehler dort sichtbar macht, wo er entsteht.
d) Weil jedes Unterprogramm einzeln geprüft werden kann, und zwar mit Werten, deren Ergebnis man kennt. Man testet mit [2, 4, 6] und erwartet 4, mit [5] und erwartet 5, mit der leeren Liste und erwartet die Meldung. Findet man einen Fehler, ist er in zehn Zeilen eingeschlossen statt in hundert. Beim einen Block dagegen kann man nur das Gesamtergebnis prüfen; stimmt es nicht, ist unklar, welcher Abschnitt schuld ist, und man muss von vorn einkreisen. Hinzu kommt: Ein geprüftes Unterprogramm muss man beim Lesen des Hauptprogramms nicht mehr aufklappen, sein Name genügt.
Detaillierte Schritterklärung anzeigen
Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.
✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.
- 1
a) Schneiden nach benennbaren Aufgaben
Fünf Unterprogramme, je eine benennbare Aufgabe: leseMesswerte() liefert die Liste, herausgelöst, weil Einlesen unabhängig vom Rechnen ist und beim Testen durch feste Beispieldaten ersetzt werden kann. entferneUngueltige(liste) hat eine eigene Regel, die sich ändern kann. mittelwert(liste), groesster(liste) und kleinster(liste) liefern je eine Zahl, getrennt, weil man häufig nur eines braucht. zeigeBericht(mittel, max, min) gibt aus, getrennt vom Rechnen.
- 2
b) Welche einen Rückgabewert haben und warum
Mit Rückgabewert: leseMesswerte, entferneUngueltige, mittelwert, groesster, kleinster, alle beantworten eine Frage oder liefern Daten. Ohne: zeigeBericht, denn es erledigt eine Aufgabe.
- 3
c) Die leere Liste: drei Wege und eine begründete Wahl
Bei leerer Liste müsste durch 0 geteilt werden, ein Laufzeitfehler. Drei Umgangsweisen: erstens einen Sonderwert zurückgeben (gefährlich, weil 0 ein gültiger Mittelwert sein kann und der Aufrufer den Unterschied nicht sieht); zweitens mit einer klaren Fehlermeldung abbrechen; drittens die Prüfung an die Aufrufstelle verlagern. Am robustesten ist die zweite, weil sie den Fehler dort sichtbar macht, wo er entsteht.
- 4
d) Warum sich das aufgeteilte Programm besser prüfen lässt
Weil jedes Unterprogramm einzeln geprüft werden kann, und zwar mit Werten, deren Ergebnis man kennt: mit und erwartetem 4, mit und erwartetem 5, mit der leeren Liste und erwarteter Meldung. Findet man einen Fehler, ist er in zehn Zeilen eingeschlossen statt in hundert.
Zusammenfassung
Ein Unterprogramm ist ein benannter, abgeschlossener Ablauf, der von außen aufgerufen wird. Seine Parameter sind der eigentliche Punkt: Sie machen aus einem Einzelfall eine ganze Klasse von Aufgaben, so wie die Allgemeingültigkeit einen vom Einzelfall unterscheidet. Ein Rückgabewert liefert ein Ergebnis; Unterprogramme, die nur etwas erledigen, brauchen keinen. innerhalb eines Unterprogramms sind lokal, und das ist kein Nachteil, sondern der Gewinn: Es gibt keine Namenskollisionen, der Ablauf bleibt nachvollziehbar, und das Unterprogramm lässt sich in andere Programme übernehmen. Deshalb gilt die Regel, dass alles Benötigte als Parameter hereinkommt und alles Gelieferte zurückgegeben wird. Geschnitten wird nach Wiederholung, Benennbarkeit und der Regel, dass ein Unterprogramm genau eine Aufgabe hat. Der größte Gewinn ist am Ende nicht die Ersparnis an Zeilen, sondern dass sich jedes Stück einzeln prüfen lässt.


