namespace cpp {}

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


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 [[#main()-Funktion|main()]] aufgerufen werden.
 +
 +Funktionen gliedern 
 +[[.:begriffe#Block|Anweisungsblöcke]] in kleinere,
 +auch wiederholt ausführbare Einheiten.
 +Sie [[.:begriffe#Geheimnisprinzip|verbergen Einzelheiten]] 
 +vor dem Nutzer, 
 +lassen sich in [[.:Module]]
 +und [[.:begriffe#Bibliothek|Bibliotheken]] 
 +zusammenfassen und in mehreren Programmen verwenden.
 +
 +Die [[#Deklaration]]
 +gibt die Schnittstelle für den [[#Aufruf]]
 +der Funktion bekannt. Die von der Funktion abzuarbeitenden 
 +Anweisungen werden bei der [[#Definition]]
 +festgelegt.
 +
 +==== Deklaration ====
 +Eine Funktion muss vor dem [[#Aufruf]]
 +mindestens durch Angabe ihres Funktionskopfes 
 +(Prototyp) angemeldet
 +([[.:begriffe#Deklaration|deklariert]]) werden.
 +Eine Funktion kann mehrfach deklariert werden, 
 +sofern die Prototypen übereinstimmen.
 +
 +Syntax:
 +
 +>  Ergebnistyp Funktionsname ''('' Parameterliste '')'' throw-Deklaration '';'' 
 +
 +Die Parameterliste enthält, durch Komma getrennt,
 +die [[#Parameter]]
 +der Funktion, jeweils mit Typ und (optional) Name des Parameters.
 +Bei parameterlosen Funktionen kann die Parameterliste leer bleiben.
 +Dies ist gleichbedeutend mit der Angabe [[.:keywords#void]]
 +in der Funktionsklammer.
 +
 +<code cpp>
 +void faul(); // void faul(void);
 +</code>
 +Drei Punkte ''...'' stehen für eine 
 +bei der Deklaration unbestimmte Anzahl von Parametern.
 +Variable Argumentlisten werden mit der Bibliothek 
 +<[[.:include:cstdarg]]>
 +verarbeitet.
 +
 +<code cpp>
 +int printf(char const* fmt, ...); // in <cstdio>
 +</code>
 +Die [[.:ausnahmen#anmelden|throw-Deklaration]] muss nicht angegeben werden
 +(siehe [[.:ausnahmen|Ausnahmebehandlung]]).
 +
 +==== 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 ''('' Parameterliste '')'' throw-Deklaration
 +>  ''{'' 
 +>>   %%//%% Anweisungen
 +>  ''}''
 +
 +<code cpp>
 +double parabel(double x) 
 +{
 +  return x*x-2*x+4;
 +}
 +</code>
 +Die [[.:keywords#return|Rückkehranweisung]] 
 +''return'' Ausdruck '';'' 
 +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 [[.:keywords#void]] 
 +kann ''return;'' (ohne Ausdruck!) entfallen.
 +
 +Als [[.:keywords#inline]] definierte kleine Funktionen
 +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;
 +}
 +</code>
 +
 +==== Aufruf ====
 +Der Aufruf einer Funktion erfolgt durch Angabe ihres Namens mit der Funktionsklammer.
 +Die Anzahl der [[.:begriffe#Argument|Argumente]]
 +in der Funktionsklammer muss mit der Anzahl der [[#Parameter]]
 +in der [[#Deklaration]]
 +übereinstimmen.
 +
 +<code cpp>
 +double y = 2*parabel(2.71828);
 +</code>
 +
 +===== Parameter =====
 +In der Parameterliste der Funktionen wird festgelegt,
 +welchen Typ übergebene [[#Wertparameter|Werte]], 
 +[[#Referenzparameter|Referenzen]], [[#Zeigerparameter|Zeiger]] 
 +oder [[#Feldparameter|Felder]] haben.
 +
 +<code cpp>
 +void funktion(int wert, int& referenz, int* zeiger, int feld[], int vorgabe=0);
 +</code>
 +[[#Vorgabewerte]]
 +(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 
 +[[.:begriffe#Typumwandlung]].
 +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 [[.:typen#Referenzen|Referenz]]
 +mit dem Argument identifiziert.
 +Übernommen wird die Adresse (''&'') der Argumentvariable.
 +Damit kann der Wert der Argumentvariable 
 +aus der Funktion heraus geändert werden (Output-Parameter).
 +Durch [[.:keywords#const]]-Deklaration
 +kann die unabsichtliche Veränderung des Argumentes unterbunden werden 
 +(Input-Parameter).
 +
 +==== Zeigerparameter ====
 +[[.:typen#Zeiger]]parameter übernehmen eine (gültige?) Speicheradresse,
 +über die mit dem [[.:operator#einstellige Operatoren|Inhaltsoperator]] ''*'' 
 +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 [[.:keywords#const]]-Deklaration des Zeigers
 +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 [[.:keywords#const]]-Deklaration des Feldes
 +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)/nenner;
 +}
 +
 +float null    = dezimal();    
 +float zwei    = dezimal(2);
 +float einhalb = dezimal(1,2);
 +</code>
 +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 ''X'' sind:
 +
 +^                  ^  billig / nicht kopierbar  \\  (''int'', ''std::unique_ptr<T>'' ^  leicht / erträglich verschiebbar \\   (''std::string'', ''std::vector<T>'' ^  teuer  \\  (''BigBlob''
 +| Output            ''X f()''  ||  ''f(X& x)''  |
 +| In-/Output        ''f(X& x)''  |||
 +| Input            |  ''f(X x)''  |  ''f(X const& x)''  ||
 +| - Kopie behalten |  -" |  ''f(X const& x)'', ''f(X&& x)'' + ''std::move(x)''  | |
 +| - Verschieben    |  ''f(X&& x)''  |||
 +
 +Die Unterscheidung zwischen Kopieren und Verschieben ([[begriffe#rvalue-referenz|Weitergabe-Referenz]] ''X&&'', untere 2 Zeilen) ist ab [[begriffe#c++11|C++11]] möglich, um optimales Laufzeitverhalten zu erreichen.
 +
 +[[#Zeigerparameter]] an Stelle von Referenzparametern erweitern die Möglichkeiten((Das Erbe von C: Trust the programmer.)): 
 +  * Ein Zeiger kann auf ein Objekt zeigen (oder auch nicht). Es liegt in der Verantwortung des Programmierers zu entscheiden, ob dies zu prüfen ist.
 +  * 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 [[.:begriffe#überladen]]e Funktionen genannt.
 +
 +<code cpp>
 +int minimum(int x, int y)
 +{
 +  return x<y? x:y;
 +}
 +
 +double minimum(double x, double y)
 +{
 +  return x<y? x:y;
 +}
 +</code>
 +[[.:schablonen#Funktionsschablonen]] 
 +definieren einen ganzen Satz von gleichnamigen Funktionen,
 +bei denen mindestens ein Typ eines Parameters 
 +bis zum Funktionsaufruf offen gelassen wird ([[.:beispiel:template]]).
 +
 +<code cpp>
 +template <class T>
 +T minimum(T x, T y)
 +{
 +  return x<y? x:y;
 +}
 +</code>
 +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)     << '\n';  // minimum(int x, int y)
 +  std::cout << minimum(1.0, 3.0) << '\n';  // minimum(double x, double y)
 +  std::cout << minimum('a', 'b') << '\n';  // minimum<>(char x, char y)
 +</code>
 +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;
 +}
 +</code>
 +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 ''argc'' (argument counter) 
 +und ''argv'' (argument vector) benannten Parameter
 +enthalten die Anzahl der Wörter und Zeiger auf die Wortanfänge 
 +der Kommandozeile, mit der das Programm gestartet wurde:
 +
 +<code cpp>
 +rename  oldname newname
 +^             ^
 +argv[0] argv[1] argv[2]   argc==3
 +</code>
 +In ''argv[0]'' steht der Programmname.
 +Werden Kommandozeilenparameter nicht benötigt,
 +kann ''int main()'' parameterlos definiert werden.
 +
 +===== Nachfolgender Ergebnistyp =====
 +In Kombination mit dem Schlüsselwort [[.:keywords#auto]] ist die Angabe eines //trailing return type// möglich ([[begriffe#c++11|C++11]]).
 +<code cpp>
 +auto sum(int x, int y) -> int { return x+y; };
 +</code>
 +Auch der Ergebnistyp eines Ausdrucks kann eingesetzt werden:
 +<code cpp>
 +auto product(int x, int y) -> decltype(x*y) { return x*y; };
 +</code>
 +Ab [[begriffe#c++14|C++14]] kann der Compiler den Rückgabetyp selbst erschließen, sofern sich nicht mehrere Rückkehranweisungen widersprechen:
 +<code cpp>
 +auto product(int x, int y) { return x*y; };
 +</code>
 +
 +
 +===== Anonyme Funktionen =====
 +Ein [[.:begriffe#Lambda-Ausdruck]] ''[capturelist](parameterliste) -> ergebnistyp { Anweisungen }'' 
 +definiert ein [[.:begriffe#Funktionsobjekt]] zur sofortigen oder späteren Verwendung. 
 +
 +<code cpp>
 +auto twice = [](int x) { return 2+x; };
 +int n = twice(3);
 +</code>
 +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 ([[.:begriffe#Closure]]) genannt.
 +Die Angabe ''[=]'' übernimmt alle Werte, ''[&]'' alle Variablen als Referenz.
 +Auch Variablenlisten und gemischte Angaben sind möglich.
 +In [[.:klassen#Methoden]] definierte Lambdas können ''[this]'' einschließen, um an Attribute des umgebenden Objektes heranzukommen.
 +
 +[[lambda]] sind u.a. in [[.:stl#Algorithmen]] nützlich, die Funktionen/Funktoren bzw. Prädikate als Parameter erwarten. 
 +Mit unmittelbar aufgerufenen Lambda-Ausdrücken ([[begriffe#IILE]]) lassen sich komplexere konstante Daten initialisieren:
 +<code cpp>
 +auto const squares = [max = 10]() // "0" "1" "4" ... "81"
 +  {
 +    std::vector<std::string> v;
 +    for (int i = 0; i < max; ++i) v.push_back(std::to_string(i*i));
 +    return v;
 +  }(); // <- Aufruf hier
 +</code>
  

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki