kennen:funktion
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
— | kennen:funktion [2020-07-27 10:20] (aktuell) – angelegt - Externe Bearbeitung 127.0.0.1 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
+ | ====== Funktionen ====== | ||
+ | > Funktionen erlauben uns, auf dem aufzubauen, was andere vor uns programmiert haben. | ||
+ | >> --- Brian Kernighan & Dennis Ritchie : Programmieren in C | ||
+ | |||
+ | ===== Funktionen ===== | ||
+ | Ein (prozedurales) Programm ist | ||
+ | im wesentlichen eine Ansammlung von Funktionen, | ||
+ | die direkt oder indirekt von der | ||
+ | Funktion [[# | ||
+ | |||
+ | Funktionen gliedern | ||
+ | [[.: | ||
+ | auch wiederholt ausführbare Einheiten. | ||
+ | Sie [[.: | ||
+ | vor dem Nutzer, | ||
+ | lassen sich in [[.: | ||
+ | und [[.: | ||
+ | zusammenfassen und in mehreren Programmen verwenden. | ||
+ | |||
+ | Die [[# | ||
+ | gibt die Schnittstelle für den [[#Aufruf]] | ||
+ | der Funktion bekannt. Die von der Funktion abzuarbeitenden | ||
+ | Anweisungen werden bei der [[# | ||
+ | festgelegt. | ||
+ | |||
+ | ==== Deklaration ==== | ||
+ | Eine Funktion muss vor dem [[#Aufruf]] | ||
+ | mindestens durch Angabe ihres Funktionskopfes | ||
+ | (Prototyp) angemeldet | ||
+ | ([[.: | ||
+ | Eine Funktion kann mehrfach deklariert werden, | ||
+ | sofern die Prototypen übereinstimmen. | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | > Ergebnistyp Funktionsname '' | ||
+ | |||
+ | Die Parameterliste enthält, durch Komma getrennt, | ||
+ | die [[# | ||
+ | der Funktion, jeweils mit Typ und (optional) Name des Parameters. | ||
+ | Bei parameterlosen Funktionen kann die Parameterliste leer bleiben. | ||
+ | Dies ist gleichbedeutend mit der Angabe [[.: | ||
+ | in der Funktionsklammer. | ||
+ | |||
+ | <code cpp> | ||
+ | void faul(); // void faul(void); | ||
+ | </ | ||
+ | Drei Punkte '' | ||
+ | bei der Deklaration unbestimmte Anzahl von Parametern. | ||
+ | Variable Argumentlisten werden mit der Bibliothek | ||
+ | < | ||
+ | verarbeitet. | ||
+ | |||
+ | <code cpp> | ||
+ | int printf(char const* fmt, ...); // in < | ||
+ | </ | ||
+ | Die [[.: | ||
+ | (siehe [[.: | ||
+ | |||
+ | ==== Definition ==== | ||
+ | Funktionsdefinitionen geben nach dem Funktionskopf | ||
+ | den Funktionsrumpf anstelle des Semikolons an. | ||
+ | Jede genutzte Funktion muss im Programm genau einmal definiert werden. | ||
+ | Funktionsdefinitionen sind nicht ineinander verschachtelbar. | ||
+ | Die Reihenfolge der Funktionsdefinitionen im Quelltext ist beliebig | ||
+ | (sofern die Funktionen vor ihrem Aufruf deklariert wurden). | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | > Ergebnistyp Funktionsname '' | ||
+ | > '' | ||
+ | >> | ||
+ | > '' | ||
+ | |||
+ | <code cpp> | ||
+ | double parabel(double x) | ||
+ | { | ||
+ | return x*x-2*x+4; | ||
+ | } | ||
+ | </ | ||
+ | Die [[.: | ||
+ | '' | ||
+ | beendet die Abarbeitung der Funktion. | ||
+ | Rückkehranweisungen können mehrfach, auch mitten im Funktionsrumpf stehen. | ||
+ | |||
+ | Der Wert des Ausdrucks wird (falls notwendig) in den Ergebnistyp umgewandelt | ||
+ | und als Ergebnis an den Aufrufer der Funktion übergeben. | ||
+ | Der Aufrufer kann dieses Ergebnis auswerten und weiterverwenden, | ||
+ | ist dazu jedoch nicht verpflichtet. | ||
+ | |||
+ | Bei Funktionen mit dem Ergebnistyp [[.: | ||
+ | kann '' | ||
+ | |||
+ | Als [[.: | ||
+ | vermeiden aufwendige Funktionsaufrufe. | ||
+ | Statt dessen wird der Funktionsrumpf in den Code eingefügt. | ||
+ | |||
+ | <code cpp> | ||
+ | inline int minimum(int x, int y) | ||
+ | { | ||
+ | return x<y? x:y; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== Aufruf ==== | ||
+ | Der Aufruf einer Funktion erfolgt durch Angabe ihres Namens mit der Funktionsklammer. | ||
+ | Die Anzahl der [[.: | ||
+ | in der Funktionsklammer muss mit der Anzahl der [[# | ||
+ | in der [[# | ||
+ | übereinstimmen. | ||
+ | |||
+ | <code cpp> | ||
+ | double y = 2*parabel(2.71828); | ||
+ | </ | ||
+ | |||
+ | ===== Parameter ===== | ||
+ | In der Parameterliste der Funktionen wird festgelegt, | ||
+ | welchen Typ übergebene [[# | ||
+ | [[# | ||
+ | oder [[# | ||
+ | |||
+ | <code cpp> | ||
+ | void funktion(int wert, int& referenz, int* zeiger, int feld[], int vorgabe=0); | ||
+ | </ | ||
+ | [[# | ||
+ | (engl. default arguments) ergänzen unvollständige Argumentlisten. | ||
+ | |||
+ | ==== Wertparameter ==== | ||
+ | Wertparameter sind innerhalb der Funktion gültige lokale Variablen. | ||
+ | Ein Wertparameter erhält beim Aufruf der Funktion | ||
+ | eine Kopie des Argumentwertes. Stimmt der Typ des Argumentes | ||
+ | nicht mit dem Parametertyp überein, erfolgt eine implizite | ||
+ | [[.: | ||
+ | Wertparameter sind innerhalb der Funktion frei änderbar. | ||
+ | Ihre Änderung hat keinen Einfluss auf den Wert des übergebenen Argumentes | ||
+ | (Input-Parameter). | ||
+ | |||
+ | ==== Referenzparameter ==== | ||
+ | Ein Referenzparameter erwartet eine Variable als Argument, | ||
+ | deren Typ mit dem Parametertyp übereinstimmt. | ||
+ | Für die Dauer des Funktionsaufrufs wird die [[.: | ||
+ | mit dem Argument identifiziert. | ||
+ | Übernommen wird die Adresse (''&'' | ||
+ | Damit kann der Wert der Argumentvariable | ||
+ | aus der Funktion heraus geändert werden (Output-Parameter). | ||
+ | Durch [[.: | ||
+ | kann die unabsichtliche Veränderung des Argumentes unterbunden werden | ||
+ | (Input-Parameter). | ||
+ | |||
+ | ==== Zeigerparameter ==== | ||
+ | [[.: | ||
+ | über die mit dem [[.: | ||
+ | lesend oder schreibend auf den Speicher zugegriffen werden kann. | ||
+ | Als Argument ist ein zum Parameter typgleicher Zeiger einzusetzen. | ||
+ | Zeigerparameter können sowohl auf Einzelwerte als auch auf Felder | ||
+ | verweisen. | ||
+ | |||
+ | Das (unabsichtliche) Ändern des verwiesenen Speicherplatzes | ||
+ | kann durch [[.: | ||
+ | unterbunden werden. | ||
+ | Der Zeiger selbst ist eine Kopie und damit in der Funktion | ||
+ | frei änderbar, z.B. um durch das Feld zu wandern. | ||
+ | |||
+ | ==== Feldparameter ==== | ||
+ | Felder werden als Zeiger auf das Anfangselement übernommen. | ||
+ | Sie haben damit Referenzverhalten. | ||
+ | Größenangaben bei Feldparametern haben lediglich Informationswert | ||
+ | für den Nutzer. Feldparameter können auch als Zeiger deklariert werden. | ||
+ | |||
+ | Durch [[.: | ||
+ | verpflichtet sich die Funktion, den Feldinhalt nicht zu ändern. | ||
+ | |||
+ | ==== Vorgabewerte ==== | ||
+ | Parameter können mit Vorgabewerten versehen werden. | ||
+ | Danach dürfen keine Parameter ohne Vorgabewert mehr folgen. | ||
+ | |||
+ | <code cpp> | ||
+ | float dezimal(int zaehler=0, int nenner=1) | ||
+ | { | ||
+ | return float(zaehler)/ | ||
+ | } | ||
+ | |||
+ | float null = dezimal(); | ||
+ | float zwei = dezimal(2); | ||
+ | float einhalb = dezimal(1, | ||
+ | </ | ||
+ | Beim Aufruf werden die übergebenen Argumente | ||
+ | links beginnend den Parametern zugeordnet. | ||
+ | Für die fehlenden Argumente werden die Vorgabewerte eingesetzt. | ||
+ | |||
+ | ==== Ein- und/oder Ausgabe ==== | ||
+ | Je nach der beabsichtigten Richtung des Datenflusses wird unterschieden in | ||
+ | * Input (Eingabe in die Funktion), | ||
+ | * Output (Ausgabe aus der Funktion), | ||
+ | * In & Output (Ein- und Ausgabe). | ||
+ | Die Art der Übergabe sollte sich danach richten, wie groß die Übergabekosten beim Kopieren oder Verschieben des Datentyps '' | ||
+ | |||
+ | ^ ^ billig / nicht kopierbar | ||
+ | | Output | ||
+ | | In-/ | ||
+ | | Input | '' | ||
+ | | - Kopie behalten | -" | ||
+ | | - Verschieben | ||
+ | |||
+ | Die Unterscheidung zwischen Kopieren und Verschieben ([[begriffe# | ||
+ | |||
+ | [[# | ||
+ | * Ein Zeiger kann auf ein Objekt zeigen (oder auch nicht). Es liegt in der Verantwortung des Programmierers zu entscheiden, | ||
+ | * Ein nicht-konstanter Zeiger kann über einen Speicherbereich wandern. Hier sollte klar sein, wo aufzuhören ist. | ||
+ | |||
+ | ===== Funktionen überladen ===== | ||
+ | Gleichnamige Funktionen mit unterschiedlicher Parameterliste | ||
+ | werden [[.: | ||
+ | |||
+ | <code cpp> | ||
+ | int minimum(int x, int y) | ||
+ | { | ||
+ | return x<y? x:y; | ||
+ | } | ||
+ | |||
+ | double minimum(double x, double y) | ||
+ | { | ||
+ | return x<y? x:y; | ||
+ | } | ||
+ | </ | ||
+ | [[.: | ||
+ | definieren einen ganzen Satz von gleichnamigen Funktionen, | ||
+ | bei denen mindestens ein Typ eines Parameters | ||
+ | bis zum Funktionsaufruf offen gelassen wird ([[.: | ||
+ | |||
+ | <code cpp> | ||
+ | template <class T> | ||
+ | T minimum(T x, T y) | ||
+ | { | ||
+ | return x<y? x:y; | ||
+ | } | ||
+ | </ | ||
+ | Der Compiler prüft beim Übersetzen eines Funktionsaufrufes | ||
+ | Anzahl und Typ der Argumente | ||
+ | und vergleicht diese mit den bekanntgemachten Prototypen. | ||
+ | Damit ist bestimmbar, welche überladene Funktion aufgerufen werden soll. | ||
+ | |||
+ | <code cpp> | ||
+ | std::cout << minimum(1, 3) << | ||
+ | std::cout << minimum(1.0, | ||
+ | std::cout << minimum(' | ||
+ | </ | ||
+ | Existiert eine spezielle Funktion, | ||
+ | so hat diese Vorrang vor der Schablone. | ||
+ | Findet sich kein Kandidat oder kommen mehrere in Betracht, | ||
+ | so ist das ein Fehler. | ||
+ | |||
+ | ===== main()-Funktion ===== | ||
+ | Jedes Programm enthält eine Hauptfunktion. | ||
+ | (In plattformspezifischen Programmiersystemen | ||
+ | kann diese Funktion unzugänglich sein.) | ||
+ | |||
+ | <code cpp> | ||
+ | int main(int argc, char *argv[]) | ||
+ | { | ||
+ | // ... | ||
+ | return statuscode; | ||
+ | } | ||
+ | </ | ||
+ | Nach Initialisierung globaler Variablen beginnt der Programmablauf | ||
+ | in dieser Funktion. Das Programm endet mit der Rückgabe | ||
+ | eines ganzzahligen Statuscodes an das aufrufende Programm (Betriebssystem). | ||
+ | Ein Programm mit dem Ergebnis 0 gilt als erfolgreich beendet. | ||
+ | Im Rückgabewert kann eine Fehlerdiagnose codiert werden. | ||
+ | |||
+ | Die traditionell [in K&R] als '' | ||
+ | und '' | ||
+ | enthalten die Anzahl der Wörter und Zeiger auf die Wortanfänge | ||
+ | der Kommandozeile, | ||
+ | |||
+ | <code cpp> | ||
+ | rename | ||
+ | ^ | ||
+ | argv[0] argv[1] argv[2] | ||
+ | </ | ||
+ | In '' | ||
+ | Werden Kommandozeilenparameter nicht benötigt, | ||
+ | kann '' | ||
+ | |||
+ | ===== Nachfolgender Ergebnistyp ===== | ||
+ | In Kombination mit dem Schlüsselwort [[.: | ||
+ | <code cpp> | ||
+ | auto sum(int x, int y) -> int { return x+y; }; | ||
+ | </ | ||
+ | Auch der Ergebnistyp eines Ausdrucks kann eingesetzt werden: | ||
+ | <code cpp> | ||
+ | auto product(int x, int y) -> decltype(x*y) { return x*y; }; | ||
+ | </ | ||
+ | Ab [[begriffe# | ||
+ | <code cpp> | ||
+ | auto product(int x, int y) { return x*y; }; | ||
+ | </ | ||
+ | |||
+ | |||
+ | ===== Anonyme Funktionen ===== | ||
+ | Ein [[.: | ||
+ | definiert ein [[.: | ||
+ | |||
+ | <code cpp> | ||
+ | auto twice = [](int x) { return 2+x; }; | ||
+ | int n = twice(3); | ||
+ | </ | ||
+ | Auch hier kann der Compiler den Ergebnistyp selbst erschließen. | ||
+ | |||
+ | Lambda-Ausdrücke beginnen mit einer eckigen Klammer. | ||
+ | Darin ist anzugeben, welche lokalen Variablen der Umgebung im Lambda-Audruck bekannt sein sollen. | ||
+ | Dieses Einbeziehen der Umgebung wird Einschluss ([[.: | ||
+ | Die Angabe '' | ||
+ | Auch Variablenlisten und gemischte Angaben sind möglich. | ||
+ | In [[.: | ||
+ | |||
+ | [[lambda]] sind u.a. in [[.: | ||
+ | Mit unmittelbar aufgerufenen Lambda-Ausdrücken ([[begriffe# | ||
+ | <code cpp> | ||
+ | auto const squares = [max = 10]() // " | ||
+ | { | ||
+ | std:: | ||
+ | for (int i = 0; i < max; ++i) v.push_back(std:: | ||
+ | return v; | ||
+ | }(); // <- Aufruf hier | ||
+ | </ | ||