Funktionen Flashcards
Funktionsdefinitionen- und Aufrufe; Auswertung von Funktionsaufrufen; Der Typ ππππ
WofΓΌr braucht man Funktionen?
Sie kapseln hΓ€ufig gebrauchte FunktionalitΓ€ten (z.B. Potenzberechnung) und machen sie einfach verfΓΌgbar. Ausserdem strukturieren sie das Programm und unterteilen es in kleine Teilaufgaben.
Betrachte folgenden Codeausschnitt:
ππππππ π;
πππ π;
πππ::πππ»_space; π;
πππ::πππ»_space; π;
ππππππ ππππππ = π·.0; ππ (π < 0) { π = π·.0/π; π = -π; } πππ (πππ π = 0; π < π; ++π) ππππππ *= π;
πππ::ππππ «_space;π «_space;β^β «_space;π «_space;β = β «_space;ππππππ «_space;β.\πβ;
Wie kΓΆnnte man ihn mithilfe einer Funktion vereinfachen? Um was fΓΌr eine Funktion geht es?
Der Codeausschnitt umschreibt die Potenzfunktion (βpowβ). Wir kΓΆnnen den mittleren Teil zu einer Funktion umformen,β¦
ππππππ πππ (ππππππ π, πππ π) { ππππππ ππππππ = π·.0; ππ (π < 0) { π = π·.0/π; π = -π; } πππ (πππ π = 0; π < π; ++π) ππππππ *= π; ππππππ ππππππ; }
β¦und brauchen danach nur noch
ππππππ πππ (ππππππ π, πππ π) {β¦}.
Wie sieht die Anatomie einer Funktion aus, d.h. aus welchen Elementen besteht sie?
π πππππ (πβ πππππβ, πβ πππππβ, . . . ,πβ πππππβ)
{πππππ}
Die Namen der Funktion πππππ und der Argumente πππππ werden jeweils von einer Typendeklaration π initiiert. Im Funktionsrumpf {πππππ} wird die Funktion an sich definiert, d.h., was die Funktion βmachtβ.
Wie wΓΌrde eine Funktion aussehen, die das Minimum zweier ganzen Zahlen π und π ausrechnet?
πππ πππ(πππ π, πππ π)
{
ππ (π
Was gilt fΓΌr die in einer Funktion deklarierten Typen, wenn die Funktion aufgerufen wird?
(1) Alle Aufrufargumente mΓΌssen konvertierbar sein in die entsprechenden Argumenttypen.
(2) Der Funktionsaufruf selbst ist ein Ausdruck vom RΓΌckgabetyp (bei πππ (π, π) z.B. vom Typ ππππππ).
Was gilt fΓΌr die in einer Funktion vorhandenen Werte, wenn die Funktion aufgerufen wird?
Aufrufargumente sind R-Werte (fΓΌr die bereits bekannten Typen). Der Funktionsaufruf selbst ist somit auch ein R-Wert.
Etwas informell: R-Wert Γ R-Wert Γ β¦ Γ R-Wert β R-Wert.
In welcher Reihenfolge wird ein Funktionsaufruf ausgewertet? Was sind die Schritte?
- Auswertung der Aufrufargumente
- Initialisierung der formalen Argumente mit den resultierenden Werten
- AusfΓΌhrung des Rumpfes: formale Argumente verhalten sich dabei wie lokale Variablen.
- AusfΓΌhrung endet mit ππππππ βexprβ.
Was sind formale Funktionsargumente?
Sind innerhalb einer Funktionsdefinition deklariert und werden bei jedem Aufruf der Funktion neu angelegt. Die Γnderung ihrer Werte haben keinen Einfluss auf die Werte der Aufrufargumente.
Sind also in etwa wie Parameter einer Funktion.
Was ist der Typ ππππ und was macht eine Funktion mit diesem Typ?
ππππ ist ein Typ mit leerem Wertebereich. Er wird verwendet fΓΌr Funktionen, die nur einen Effekt haben, also nur eine Eingabe zurΓΌckgeben.
Sie benΓΆtigen somit auch keine ππππππ-Anweisung.
Betrachte folgende Funktion zum Vergleich zweier Zahlen:
ππππ πππππππ(πππππ π‘, πππππ π’) {
πππππ πππππ = π‘ - π’;
ππ (πππππ*πππππ < 0.00π·π) ππππππ ππππ;
}
Weswegen wird diese Funktion in den meisten FΓ€llen nicht funktionieren?
Das Verhalten einer Funktion mit RΓΌckgabetyp ungleich ππππ ist nicht definiert, wenn das Ende des Funktionsrumpfes ohne ππππππ-Anweisung erreicht wird.
In diesem Beispiel ist ππππππ nur fΓΌr den βwahrenβ Fall definiert. FΓΌr eine Eingabe πππππππ(π·0, πΈ0), z.B., wΓΌrde die Funktion nicht funktionieren.
Was sind Vor- und Nachbedingungen (pre and post conditions)? Was muss man allgemein beachten?
Sie beschreiben und dokumentieren, was die Funktion macht. Wie auch Kommentare werden sie vom Compiler ignoriert und machen Programme lesbarer. Sie machen daher auch Aussagen ΓΌber die Korrektheit eines Programmes mΓΆglich, weshalb sie mΓΆglichst korrekt sein sollten.
Wenn eine Vorbedingung beim Funktionsaufruf gilt, muss auch die Nachbedingung nach Funktionsaufruf gelten.
Was genau beschreibt eine Vorbedingung und was muss man beim Schreiben einer Vorbedingung beachten?
Sie beschreiben, was bei Funktionsaufruf gelten muss und spezifizieren den Definitionsbereich der Funktion.
Sie sollte so schwach wie mΓΆglich gehalten sein (mΓΆglichst grosser Definitionsbereich).
Was genau beschreibt eine Nachbedingung und was muss man beim Schreiben einer Nachbedingung beachten?
Sie beschreiben, was nach Funktionsaufruf gelten muss und spezifizieren Wert und Effekt des Funktionsaufrufes.
Sie sollten so stark wie mΓΆglich gehalten sein (mΓΆglichst detaillierte Aussage).
Betrachte die Funktion πππ (π, π), wobei π die Basis ist und π der Exponent.
Wie sehen gute Pre- und Postconditions dieser Funktion aus?
//πΏππ΄: π >= 0 || π != 0.0 //πΏπΎππ: ππππππ πππππ ππ π^π
Weshalb kann man ΓΌber gute Pre- und Postconditions sagen, sie seien ein βKompromiss zwischen formaler Korrektheit und lascher Praxisβ?
Da exakte Pre- und Postconditions plattformabhΓ€ngig und sehr kompliziert sind, abstrahiert man und gibt die mathematischen Bedingungen an, die fΓΌr alle FΓ€lle gelten.
Wie kann man sicherstellen, das Vor- und Nachbedingungen beim Funktionsaufruf bzw. nach Funktionsaufruf auch gelten?
Mit Assertions, z.B. in der πππ (π, π)-Funktion mit der Vorbedingung //πΏππ΄: π >= 0 || π != 0.0 fΓΌgt man eine Assert-Zeile hinzu:
ππππππ (π >= 0 || π != 0);
Was ist das Problem mit Assertions, bzw. was kΓΆnnten allmΓ€hliche Schwachstellen sein? Was wΓ€ren Alternativen?
Falls die Assertion fehlschlΓ€gt, wird das Programm hart abgebrochen. DafΓΌr bilden die sogenannten Exceptions ein eleganteres Mittel, da es auf solche FehlschlΓ€ge situationsabhΓ€ngig reagiert und das Programm nicht gleich zum Teufel jagt.
(Anmerkung: Exceptions jedoch kein Teil dieser Vorlesung)
Was bedeutet Stepwise Refinement? Wie sieht der Prozess aus und was fΓΌr Vorteile bringt er?
Ein grΓΆsseres Problem wird schrittweise gelΓΆst. Zu erst wird ganz grob abstrahiert, also nur mit Kommentaren und fiktiven Funktionen gearbeitet. Danach werden Schritt fΓΌr Schritt Kommentare durch Programmtest ersetzt und Funktionen implementiert.
Dies hat zum Vorteil, das das strukturelle VerstΓ€ndnis des Problems gefΓΆrdert wird und - falls die Verfeinerung grΓΆsstmΓΆglich durch Funktionen realisiert wird - TeillΓΆsungen auch bei anderen Problemen eingesetzt werden kΓΆnnen.
(FΓΌr Beispiel siehe Slides zur VL6: Rechteckproblem)
Wie ist der GΓΌltigkeitsbereich einer Funktion definiert?
Der GΓΌltigkeitsbereich einer Funktion ist der Teil des Programmes, in dem die Funktion aufgerufen werden kann. Er ist definiert als die Vereinigung der GΓΌltigkeitsbereiche aller ihrer Deklarationen.
Was sind Forward Declarations?
Forward Declarations sind Funktionen, die sich gegenseitig aufrufen (also eine Funktion in einer Funktion). Betrachte als Beispiel folgenden kommentierten Programmtext:
πππ π(...); //ππππ πππ πππππππππππ πππ π(...) //π ππ ππππ ππΜππππ { π(...) //ππ } πππ π(...) { π(...) //ππ }
Betrachte die Funktion πππ . Auch wenn man sie gerade in einem Programm braucht, welches genau dazu da ist, Potenzen zu berechnen, braucht man sie sicher noch in anderen Programmen. Wie kΓΆnnte man dieses Problem lΓΆsen, ohne jedes mal die Funktion neu zu schreiben? Wie macht man das? Was ist ein wesentlicher Nachteil dieser Methode?
Man inkludiert (kopiert) die Funktion ins Hauptprogramm, wenn man sie braucht. Dazu lagert man die Funktion erst als separates Programm ins Arbeitsverzeichnis aus, und inkludiert sie dann mittels der Anweisung #πππππππ im Hauptprogramm. Der Nachteil ist jedoch, dass der Compiler die Funktionsdefinition fΓΌr jedes Programm neu ΓΌbersetzen muss, was bei sehr vielen und grossen Funktionen sehr lange dauern kann.
Was ist die getrennte Γbersetzung eines Programms? Betrachte die Funktion ππππππ πππ (ππππππ π, πππ π) innerhalb eines Programms mymath.cpp und das Programm callpow3.cpp, in dem die Funktion πππ mindestens einmal aufgerufen wird: Gebe alle Schritte an, in denen das Programm getrennt ΓΌbersetzt werden wΓΌrde.
Bei der getrennten Γbersetzung wird ein Programm unabhΓ€ngig vom Hauptprogramm ΓΌbersetzt.
- mymath.cpp wird in mymath.o (Objektcode, fΓΌr Menschen nicht / schwer lesbar; Zwischenschritt des Compilens) ΓΌbersetzt.
- Alle benΓΆtigten Symbole werden vom Programmierer in einer Header-Datei deklariert. Im Beispiel wΓΌrde diese Datei mymath.h (fΓΌr Header) so aussehen:
//πΏππ΄: π >= 0 || π != 0.0
//πΏπΎππ: ππππππ πππππ ππ π^π
ππππππ πππ (ππππππ π, πππ π); - Jedes mal, wenn eine Deklaration aus mymath im Programm (hier callpow3.cpp) inkludiert wird, wird das Hauptprogramm unabhΓ€ngig von mymath.cpp ΓΌbersetzt (hier wieder in Objekt-Code: callpow3.o)
- Der sogenannte Linker vereint nun den βUrsprungβ der Funktion mymath.o mit dem Hauptprogramm callpow3.o zu einer wieder ausfΓΌhrbaren Datei callpow3.
Bemerke, dass mymath.cpp nach dem Erzeugen von mymath.o nicht mehr gebraucht wird.
(FΓΌr Bilder siehe Slides zur VL6)
Was sind Bibliotheken?
Bibliotheken sind logische Gruppierungen Γ€hnlicher Funktionen, z.B. die Funktionen πππ , ππ‘π, πππ, πππ, usw. werden zur Bibliothek πππππ gruppiert.
Was ist der Vorteil, Funktionen aus einer Standartbibliothek zu verwenden gegenΓΌber dem Verwenden selbst erstellter Funktionen / Bibliotheken?
- Vermeiden die Neuerfindung des Rades (wie z.B. bei πππ )
- FΓΌhren auf einfache Weise zu interessanten und effizienten Programmen.
- Garantieren einen QualitΓ€tsstandart.