7. Grundlagen von Funktionen Funktionen in C++ Bestandteile eines C++ - Programms C++ Kern Standardbibliothek Anwender Sonstiges Dr. Norbert Spangler /Programmieren vordefinierte Datentypen, Operatoren, Befehle vordefinierte Funktionen (und Klassen) selbsterstellte Funktionen (und Klassen) externe Bibliotheken 21.11.2015 2 Funktionen in C++: Standardbibliothek Mathematische Funktionen mittels #include <cmath> abs (x*x-a) >=1.0e-10 sqrt(summe) Argument und Wert z.b. double Weitere Funktionen in cmath: exp log log10 pow asin sin cos tan acos atan sinh cosh tanh … rand() ganzzahlige Zufallszahl Argument keines, Funktionswert int strlen(ca) Zeichenzahl eines Character-Arrays Argument Character-Array, Funktionswert int cin.eof() wahr/falsch bei Dateiende Dr. Norbert Spangler /Programmieren 21.11.2015 3 Funktionen in C++: Anwender-Funktionen Eigene Formeln p-q-Formel bei quadratischen Gleichungen Argumente: p und q Funktionswert : eine Lösung loesung = pqFormel(p,q) Suchen eines Elements in einem Array Argumente: Arrayelemente + Anzahl der Elemente + Suchelement Funktionswert : gefundener Index (Stelle) stelle = suche(anzahl,array, suchelement) Sortieren der Elemente eines Arrays Argumente: Arrayelemente + Anzahl der Arrayelemente Funktionswert : void Regel: sortiere(anzahl,array) Funktionen machen keine Ausgaben Eingabe von Daten am Bildschirm, es sei denn, Argumente: Daten es handelt sich um eine Ausgabefunktion Funktionswert : void oder bool Ausgabe von Daten Argumente: Daten Funktionswert : void Dr. Norbert Spangler /Programmieren 21.11.2015 4 Motivation: wofür? Funktionen lösen spezielle (Teil-)Aufgaben mathematische Formeln spezielle Algorithmen: Suchen, Sortieren, Gleichungen, Auswertungen Ein-/Ausgabe für Tastatur, Bildschirm, Dateien usw. Steuerungen von Geräten, Anlagen,… Funktionen sind Zusammenfassungen von Arbeitspaketen und bieten eine Möglichkeit zur Verteilung des Programmieraufwands auf Teams Voraussetzung Die Schnittstellen (d.h. die Kommunikation) der Funktionen untereinander sind klar festgelegt bzw. beschrieben. -> Welche Daten werden benötigt, um die Funktion auszuführen ? -> Welche Daten/Ergebnisse liefert die Funktion? Dr. Norbert Spangler /Programmieren 21.11.2015 5 Motivation: Programmqualität Funktionen sind damit „eigenständige" Programmteile innerhalb einer Anwendung zur - Strukturierung/Beherrschung der Komplexität (Komponenten), - Lösung von Teilaufgaben, - Arbeitsorganisation d.h. Aufteilung auf Teams, - Verbesserung der Übersichtlichkeit und Lesbarkeit, - Verbesserung des Testens, - Wiederverwendung (z. Bsp. Ein-/Ausgabe von Arrays), - Archivierung in Bibliotheken, - Übersetzung: jede Funktion wird durch einen eigenen Compilerlauf bearbeitet. Damit könnten auch unterschiedliche Programmiersprachen verwendet werden Funktionen erhöhen die Programmqualität Dr. Norbert Spangler /Programmieren 21.11.2015 6 7.1 Beispiel einer Anwender-Funktion: Musterprogramm Wurzel berechnen Wurzel berechnen Eingabe a Eingabe a a<=0 a <= 0 Ja a muss >0 sein ja Nein nein a muss > 0 sein Ausgabe wurzel(a) x=a Solangex*x-a ungenau Wurzel(a) x*x-a x = x - ------2x Ausgabe x Das "große unübersichtliche" Struktogramm wird ersetzt durch "kleine" übersichtliche" für jede Funktion, sowie das eigentliche Programm: - Eingabe mit Plausibilitätskontrolle->einfach zu testen - „eigentliche“ Aufgabe->keine unzulässigen Daten mehr Dr. Norbert Spangler /Programmieren x=a Solangex*x-a ungenau x*x-a x = x - ------2x Ergebnis x 21.11.2015 7 main mit Verwendung einer Funktion wurzel // Wurzel berechnen #include <iostream> using namespace std; void main() { double radikand; double wurzel(double); cout <<"\n radikand eingeben "; cin>>radikand; //Plausibilitaetskontrolle if ( radikand<0 )// unzulaessige Eingabe cout <<"\n darf nicht < 0 sein "; else //Ergebnis cout <<"\n Wurzel von "<<radikand <<" = "<< wurzel(radikand) <<endl; } Dr. Norbert Spangler /Programmieren Funktion1: main Prototyp: Funktionstyp ist double 1 Parameter vom Typ double Dadurch ist wurzel in main bekannt und kann verwendet werden. Aufruf Hier wird wurzel verwendet. aktuelle Parameter Mit diesen Daten aus dem main soll wurzel arbeiten 21.11.2015 8 Die Funktion wurzel formale Parameter (Platzhalter, lokale Variable der Funktion wurzel) double wurzel(double a) { const double genauigkeit=0.001; double x=a; if (a==0.0) return 0.0; else while ( abs (x*x-a)>genauigkeit ); x=x-(x*x-a)/(2*x); return x; } Funktionskopf Definition Funktionsblock Ergebnis (Funktionswert) Dr. Norbert Spangler /Programmieren 21.11.2015 9 Dateien Üblicherweise sollte man jede Funktion innerhalb eines Projekts in einer eigenen Datei speichern. Anmerkung: es geht auch mit einer Datei. main Funktion in Datei main.cpp in einer Datei func.cpp Compiler erzeugt main.obj Compiler erzeugt func.obj Linker projekt.exe-Datei Dr. Norbert Spangler /Programmieren 21.11.2015 10 7.2 Aufgabenstellung Prinzipielle Ausgangssituation: main (ist eine benutzerdefinierte Funktion); sie verwendet wurzel (ist eine weitere benutzerdefinierte Funktion), diese verwendet abs (ist eine bereitgestellte Funktion) Allgemein: Eine Funktion function1 verwendet eine andere Funktion function2. Dr. Norbert Spangler /Programmieren 21.11.2015 11 Aufgabenstellung: Anforderungen Situation: funktion1 verwendet funktion2 z.B. funktion1 geschrieben von Programmierer/Team a funktion2 geschrieben von Programmierer /Team b Wie erkennt funktion1 dass es funktion2 gibt? Verfügbarkeit: Was passiert wenn funktion2 nicht zur Verfügung steht? Wie kann funktion1 programmiert werden wenn funktion2 nicht verfügbar ist? Kann funktion2 programmiert/getestet werden wenn funktion1 nicht existiert? Schnittstellen: Wie erfährt funktion2, mit welchen Daten aus funktion1 sie arbeiten muss? Wie wird das Ergebnis von funktion2 an funktion1 übermittelt? Bei Mehrfachverwendung von funktion2 in funktion1: An welcher Stelle in funktion1 geht es weiter? Dr. Norbert Spangler /Programmieren 21.11.2015 12 Schnittstellen funktion1(main) – funktion2 (f) main f(t) Programmcode y=f(x); Sprung Rücksprung/Ergebnis Stelle 1 z=f(h)+1; Rücksprung/Ergebnis Stelle 2 return ergebnis x y h z Variante 1: Wert ausrechnen kopieren Daten funktion 2 Daten funktion 1 Programmcode Sprung t ergebnis Variante 2: Adresse verraten t wird an derselben Stelle gespeichert wie h Dr. Norbert Spangler /Programmieren 21.11.2015 13 Erfüllung der Anforderungen/1 Wie erkennt funktion1 dass es funktion2 gibt? Ein Hinweis ist erforderlich: Prototyp Was passiert wenn funktion2 nicht zur Verfügung steht? Fehlermeldung des Linkers Wie kann funktion1 programmiert werden wenn funktion2 nicht verfügbar ist? Man erstellt eine einfache Vorabversion von funktion2 mit korrekten Schnittstellen aber ohne wesentliche Funktionalität: Stub Kann funktion2 programmiert/getestet werden wenn funktion1 nicht existiert? Man erstellt ein separates Testprogramm für funktion2: Treiber Dr. Norbert Spangler /Programmieren 21.11.2015 14 Erfüllung der Anforderungen/2 Wie erfährt funktion2, mit welchen Daten aus funktion1 sie arbeiten muss? Bei der Verwendung der Funktion (Aufruf) müssen diese mittels Parameter übermittelt werden. Hierzu gibt es unterschiedliche Techniken (durch Kopien oder mittels Adressen). Wie wird das Ergebnis von funktion2 an funktion1 übermittelt? Hierzu gibt es unterschiedliche Techniken. Die einfachste Variante ist mittels des Returnbefehls: return Funktionswert; Alternative: Ändern von Parametern (später) Bei Mehrfachverwendung von Funktion2: An welcher Stelle in funktion1 geht es weiter? Die Stelle (Rücksprungadresse) muss beim Wechsel vom Programmcode von funktion1 in den von funktion2 gemerkt und bei der Rückkehr verwendet werden. Dies wird automatisch erledigt. Dr. Norbert Spangler /Programmieren 21.11.2015 15 Weitere Aspekte Eine Funktion hat einen Wert (Typ) Prinzipiell ist jeder Typ zulässig, also auch int, short,char,…. Hat eine Funktion "keinen Wert" wird als Typ void verwendet. Funktionen vom Typ void werden direkt aufgerufen Beispiel : tausche(x,y); sortiere(n,x); ausgabeArray(n,a); Funktionen mit Typ erscheinen als R-Wert Beispiel: w=wurzel(radikand) ; cout<<wurzel(b*b-4*a*c) <<endl; Eine Funktion hat kann beliebig viele Parameter haben Parameter werden durch Komma getrennt Beispiel wurzel(a,genauigkeit) allgemein funktionsname(parameter1,parameter2,.....,parameter_n) aber auch void main() //ohne Parameter int rand();// Typ int aber keine Parameter Dr. Norbert Spangler /Informatik 21.11.2015 16 7.3 Programmierung von Funktionen Die Funktion sollte sinnvollerweise in einer eigenen cpp-Datei im Projekt stehen. Daher ist zu main eine weitere cpp-Datei hinzuzufügen. Der Name kann beliebig gewählt werden; üblich ist Funktionsname.cpp. Diese Datei enthält dann die Funktionsdefinition. Sie besteht aus dem Funktionskopf und dem Funktionsblock. Je nach Größe des Projekts bzw. Anzahl oder Umfang der Funktionen kann man auch mehrere Funktionsdefinitionen in einer Datei zusammenfassen. Ziel sollte generell die Übersichtlichkeit des Gesamtprogramms sein. Dr. Norbert Spangler /Programmieren 21.11.2015 17 Funktionsdefinition = Funktionskopf + Funktionsblock Angabe des Funktionskopfs Typ der Funktion entspricht dem Typ des return-Wertes Name der Funktion wie ein Variablenname Deklarationsliste Typ und Name der Parameter genauer: formale Parameter (Platzhalter) Allgemeine Funktionsdefinition: typfunktion namefunktion(typ1 p1,…,typn pn) Beispiele: double wurzel(double a) //1 Parameter double wurzel(double a, double genauigkeit) //2 Parameter double loesung1(double a, double b, double c) //quadratische Gleichung - 3 Par. int rand() //kein Parameter- ganzzahlige Zufallszahl void ausgabeKreisdaten( float radius) // Typ der Funktion void Dr. Norbert Spangler /Programmieren 21.11.2015 18 Funktionsdefinition = Funktionskopf + Funktionsblock Funktionsblock { Befehle der Funktion} In einem Paar geschweifter Klammern stehen die Befehle der Funktion. Er kann alle bekannten Befehle enthalten. Insbesondere ist es möglich, neu benötigte Größen zu deklarieren. Diese sind dann lokale Größen im Funktionsblock und nach Verlassen des Blocks, d.h. nach Beendigung der Funktion, nicht mehr existent. Für die formalen Parameter im Funktionskopf , wie sie bisher dargestellt wurden, werden ebenfalls lokale Variable deklariert. Eine Funktion wird mittels return beendet. Danach erfolgt der Rücksprung in die aufrufende Funktion. Hierbei gibt es 2 Varianten. Dr. Norbert Spangler /Programmieren 21.11.2015 19 Beendigung der Funktion mit return Wenn die Funktion vom Typ void ( z.B. void main() , void ausgabeKreisdaten(...) ist, wird sie üblicherweise mittels return ohne zusätzlichen Angaben beendet. Beispiel: if ( a< 0 ) { cout<<"Fehler: unzulaessige Eingabe"; return; } Ein return am Ende des Funktionsblocks, d.h. am Ende der Funktion kann auch weggelassen werden. Dr. Norbert Spangler /Programmieren 21.11.2015 20 Beendigung der Funktion mit return wert Wenn die Funktion nicht vom Typ void ist, dann muss sie immer mit return wert; beendet werden. Dabei ist wert ein Ausdruck vom selben Typ wie die Funktion also etwa im Falle des Typs double ( wie bei wurzel) : return 0.0; //Konstante vom Typ double return x; // Variable vom Typ double return x*x-1; //Ausdruck vom Typ double Der Funktioswert funktion(Parameter) ist dann als R-Wert zu verwenden. Dr. Norbert Spangler /Programmieren 21.11.2015 21 Definition/Beispiel 1 #include<cmath> using namespace std; double wurzel(double a) { const double genauigkeit=0.001; double x=a; if (a==0.0) return 0.0; else { while ( abs (x*x-a)>genauigkeit ) x=x-(x*x-a)/(2*x); } return x; } Dr. Norbert Spangler /Programmieren Wegen Verwendung von abs Achtung: Alle hier vorkommenden Größen sind lokale Größen der Funktion a genauigkeit x 21.11.2015 22 Definition: weitere Beispiele/1 #include <string> using namespace std; bool ist_palindrom(string s)//Typ bool { int laenge=s.length(); for ( int i=0;i<laenge/2;i++) if ( s[i]!=s[laenge-1-i] ) return false; return true; } Überprüft, ob eine Variable vom Typ string ein Palindrom enthält. Lokale Variable: s laenge i Lokale Variable: radius pi void ausgabeKreisdaten(float radius) { float pi=3.14159f; cout<<"Radius "<<setw(10)<<setprecision(3)<<fixed<<radius<<endl; cout<<"Durchmesser "<<setw(10)<<setprecision(3)<<fixed<<radius*2<<endl; cout<<"Umfang "<<setw(10)<<setprecision(3)<<fixed<<(2*radius*pi)<<endl; cout<<"Flaeche "<<setw(10)<<setprecision(3)<<fixed<<(radius*radius*pi)<<endl; } Dr. Norbert Spangler /Programmieren 21.11.2015 23 Definition: weitere Beispiele/2 #include <string> using namespace std; string notentext(int note) { if ( note==1 ) return "sehr gut"; else if ( note==2 ) return "gut"; else if ( note==3 ) return "befriedigend"; else if ( note==4 ) return "ausreichend"; else if ( note==5 ) return "mangelhaft"; else return "unbefriedigend"; } Dr. Norbert Spangler /Programmieren int rabatt_prozent(int menge) { if ( menge<10 ) return 0; else if ( menge<50 ) return 5; else if ( menge<100 ) return 10; else return 20; } 21.11.2015 24 7.4 Verwendung einer Funktion/Aufruf Will man in einer funktion1 (z.B. main) eine andere funktion2 (z.B. wurzel oder sin ) verwenden, so muss man sie im Falle von Standardfunktionen mittels include bereitstellen bzw. im Falle eigenentwickelter Funktionen dem Compiler zur Plausibilitätskontrolle alle relevanten Informationen mitteilen wie - Name der Funktion - Typ der Funktion ( genauer des Ergebnisses) - Anzahl der Parameter - Typ der Parameter - Reihenfolge der Parameter Dies geschieht durch die Angabe des Prototyps. Dr. Norbert Spangler /Programmieren 21.11.2015 25 Prototyp (Deklaration) Der Prototyp ist ähnlich dem Funktionskopf in der Definition. Es kann auf die Angabe der Namen der Parameter verzichtet werden. Der Typ ist jedoch erforderlich. Der Prototyp muss vor der ersten Verwendung angegeben sein. Form: typderfunktion namederfunktion(parametertyp1,…,parametertypn); Beispiele: double wurzel(double); int rabatt(int); bool ist_palindrom(string); int rabatt_prozent(int); string notentext(int); void ausgabeKreisdaten(float]); Dr. Norbert Spangler /Programmieren 21.11.2015 26 Aufruf der Funktion Beim Aufruf der Funktion müssen die (formalen) Parameter durch die aktuell zu verwendenden Parameter (Ausdrücke) ersetzt werden. Es gibt 2 Arten des Aufrufs: Für Funktionen vom Typ void: Die Funktion wird mit aktuellen Parametern direkt hingeschrieben: ausgabeKreisdaten(r); Für Funktionen mit Typ: Die Funktion hat damit einen Wert, welcher wie ein R-Wert verwendet wird. Dr. Norbert Spangler /Programmieren 21.11.2015 27 Aufruf der Funktion/ Beispiele Für Funktionen mit Typ: Die Funktion hat damit einen Wert, welcher wie ein R-Wert verwendet wird. summe=bestellmenge*stueckpreis; //Berechnung Rabattbetrag rabatt=summe * rabatt_prozent(bestellmenge) /100; cout<<" Note "<<n<<" ist "<<notentext(n)<<endl; void main()//Treiber Palindrom { string text; bool ist_palindrom(string); cout<<" Text "; cin>>text; if ( ist_palindrom(text) ) cout<<text<<" ist Palindrom"<<endl; else cout<<text<<" ist Palindrom"<<endl; } Dr. Norbert Spangler /Programmieren 21.11.2015 28 Parameterübergabe Beim Aufruf der Funktion wird (lokaler) Speicherplatz bereitgestellt für formale Parameter, sonstige lokale Variable, und die Rücksprungadresse Es werden die aktuellen Parameter ausgewertet (Ausdrücke). Diese Werte werden auf die lokalen Variabler für die formalen Parameter kopiert. Technik der Parameterübergabe : Call by Value Die Funktion arbeitet also immer mit Kopien und nie mit Variablen aus der aufrufenden Funktion (=Originaldaten). Damit können die aktuellen Parameter aus der aufrufenden Funktion nicht geändert werden (da nicht bekannt)! Sollte dies erforderlich sein müssen andere Techniken gewählt werden (->später). Nachteilig ist, dass Parameter mit hohem Speicherbedarf dupliziert werden. Dr. Norbert Spangler /Programmieren 21.11.2015 29 Prinzipieller Ablauf des Aufrufs main Aufruf, Rücksprungadresse merken wurzel(b*b-4*a*c); Aktuelle Parameter auswerten und auf formale Parameter kopieren wurzel( double a ); Funktionsblock ausführen (lokale Objekte : a, genauigkeit, x) Rücksprungadresse holen, Wert mittels return übergeben main Mit Wert/Ergebnis arbeiten Dr. Norbert Spangler /Programmieren 21.11.2015 30 7.5 Test einer Funktion Funktionen werden in der Regel separat getestet mittels eines zugehörigen Testprogramms (Treiber). Dabei sind anstelle der bisher verwendeten „Eingaben“ jetzt üblicherweise die Parameter zu variieren. Da aber diese stets einen fest vorgegebenen Typ haben, können hier keine „verkehrten“ Datentypen vorkommen. Damit entfallen Testbeispiele mit unzulässigen Daten, wenn dies die Datentypen betrifft. Es sind allenfalls „unsinnige“ Daten zu betrachten wie negative Anzahlen etc. Der Test einer Funktion ist daher in der Regel einfacher als der eines Programms mit Eingaben und Plausibilitätskontrollen. Dr. Norbert Spangler /Programmieren 21.11.2015 31
© Copyright 2024 ExpyDoc