Strukturierte Programmierung und Funktionen

Ähnliche Dokumente
Funktionen: Rückgabewert

Einstieg in die Informatik mit Java

Methoden. Gerd Bohlender. Einstieg in die Informatik mit Java, Vorlesung vom

HSR Rapperswil 2001 Markus Rigling. Programmieren: Exceptions Auflage

Verwendung Vereinbarung Wert einer Funktion Aufruf einer Funktion Parameter Rekursion. Programmieren in C

Modul Entscheidungsunterstützung in der Logistik. Einführung in die Programmierung mit C++ Übung 4

Einstieg in die Informatik mit Java

Elementare Datentypen in C++

Einstieg in die Informatik mit Java

Einführung in den Einsatz von Objekt-Orientierung mit C++ I

7 Funktionen. 7.1 Definition. Prototyp-Syntax: {Speicherklasse} {Typ} Name ({formale Parameter});

Programmiertechnik. Teil 4. C++ Funktionen: Prototypen Overloading Parameter. C++ Funktionen: Eigenschaften

C++ - Einführung in die Programmiersprache Header-Dateien und Funktionen. Leibniz Universität IT Services Anja Aue

Programmierung und Angewandte Mathematik

Methoden und Wrapperklassen

Java Methoden. Informatik 1 für Nebenfachstudierende Grundmodul. Kai-Steffen Hielscher Folienversion: 1. Februar 2017

Programmiersprache 1 (C++) Prof. Dr. Stefan Enderle NTA Isny

Systemnahe Programmierung in C (SPiC)

C++ - Funktionen und mehr -

Einführung in die Programmierung Wintersemester 2008/09

Einstieg in die Informatik mit Java

Grundlagen der Objektorientierten Programmierung - Methoden -

Bedingte Anweisungen

C++ Teil 5. Sven Groß. 12. Nov IGPM, RWTH Aachen. Sven Groß (IGPM, RWTH Aachen) C++ Teil Nov / 16

Praxis der Programmierung

Vorlesungsprüfung Programmiersprache 1

Prozeduren vs. Funktionen

Implementieren von Klassen

2. Unterprogramme und Methoden

Übung zur Vorlesung EidP (WS 2018/19) Blatt 4

2. Programmierung in C

CS1005 Objektorientierte Programmierung

Vorkurs C++ Programmierung

C++ - Objektorientierte Programmierung Konstruktoren und Destruktoren

Übung zur Vorlesung Wissenschaftliches Rechnen Sommersemester 2012 Auffrischung zur Programmierung in C++, 1. Teil

Übung zur Vorlesung Wissenschaftliches Rechnen Sommersemester 2012 Auffrischung zur Programmierung in C++, 1. Teil

Teil II. Literatur zur C-Programmierung:

Funktionen. mehrfach benötigte Programmteile nur einmal zu schreiben und mehrfach aufzurufen

Ein paar Kleinigkeiten zum Einstieg

Tag 5. Repetitorium Informatik (Java) Dozent: Marius Kamp Lehrstuhl für Informatik 2 (Programmiersysteme)

Programmierung mit C Zeiger

C# - Einführung in die Programmiersprache Methoden. Leibniz Universität IT Services

Einführung in C. EDV1-04C-Einführung 1

Grundelemente objektorientierter Sprachen (1)

Java Übung. Übung 2. Werner Gaulke. 19. April Universität Duisburg-Essen Kommedia, Übung EinPro SS06, Einführung in Java - Übung.

Projekt 3 Variablen und Operatoren

Einstieg in die Informatik mit Java

3.2 Datentypen und Methoden

ÜBUNGS-BLOCK 7 LÖSUNGEN

7. Übung Informatik II - Objektorientierte Programmierung

Funktionen in JavaScript

C++ Teil 4. Sven Groß. 30. Apr IGPM, RWTH Aachen. Sven Groß (IGPM, RWTH Aachen) C++ Teil Apr / 16

Die erste C++ Funktion

Einführung in die Programmierung WS 2009/10. Übungsblatt 5: Typen, Variablen und einfache Methoden in Java

(Ausnahmebehandlung)

Inhalt. 4.9 Typen, Variable und Konstante

Beuth Hochschule Parameter-Übergabe-Mechanismen WS17/18, S. 1

Themen der Übung. Methoden und Wrapperklassen. Vorteile von Methoden. Methoden. Grundlagen

Grundlagen der Programmierung in C Funktionen

Operatoren in C/C++ und Java:

Präzedenz von Operatoren

JavaScript. Dies ist normales HTML. Hallo Welt! Dies ist JavaScript. Wieder normales HTML.

C++ Teil 2. Sven Groß. 16. Apr IGPM, RWTH Aachen. Sven Groß (IGPM, RWTH Aachen) C++ Teil Apr / 22

Einführung in die C-Programmierung

Funktionen in JavaScript

2. Programmierung in C

Objektorientierte Programmierung

Javaprogrammierung mit NetBeans. Variablen, Datentypen, Methoden

Einführung in die Programmierung mit C++

Grundelemente objektorientierter Sprachen (1)

OCP Java SE 8. Lambda

Grundelemente objektorientierter Sprachen (1)

Einführung in die Programmierung für NF. Übung

OCP Java SE 8. Lambda

5.3 Auswertung von Ausdrücken

Kontrollstrukturen (1)

Unterprogramme. AnPr. Wiederholungen im Code werden vermieden. Programme werden leichter lesbar. Die Entwicklung und der Test werden vereinfacht.

2 FUNKTIONSZEIGER UND BEHÄLTER

SimpleStat mit Methoden

Methoden (fortgeschritten) in C# - 1

Ein kleiner Blick auf die generische Programmierung

C-Pointer (Zeiger, Adressen) vs. C++ Referenzen

Programm-Ablauf. int main() // Beispiel- Struktur eines Programmes. prepare_everything(); read_input(); calculate_result(); write_output();

Programmierung in C: Vermischtes (Teil 1)

Felder, Zeiger und Adreßrechnung

10.4 Konstante Objekte

Typ : void* aktuelle Parameter Pointer von beliebigem Typ

Methoden. (Softwareentwicklung II (IB)) Prof. Dr. Oliver Braun. Letzte Änderung: :40. Methoden 1/44

Praktische Informatik 1

Speicherklassen (1) Lokale Variablen

Java Einführung Methoden. Kapitel 6

Kapitel 10 Delegationsvariablen

Softwareentwicklung II (IB) Methoden. Prof. Dr. Oliver Braun. Fakultät für Informatik und Mathematik Hochschule München

Systemprogrammierung

Test-Klausuraufgaben Softwaretechnik Fachbereich BW, für WINFO

Schleifen in C/C++/Java

Objektorientierte Programmierung mit C++ SS 2007

Transkript:

Strukturierte Programmierung und Funktionen Um ein Programm übersichtlicher zu gestalten, zerlegt man seine Funktionalität meist in mehrere (oder auch ganz viele) Teile. Dadurch lässt sich das Programm übersichtlicher darstellen und manchmal lassen sich die Einzelteile auch in anderen Programmen sinnvoll einsetzen(wiederverwertbarer Code). C besitzt für diese Aufteilung nur die Funktion, während objektorientierte Sprachen auch Objekte (Klassen) dafür einsetzen können. Wichtig: C (und C++)-Programme bestehen aus einer oder mehrerer Funktionen. Es muss mindestens die main()-funktion vorhanden sein. Mit dieser startet und endet das Programm im Normalfall. Der Programm-Code kann auch auf mehrere Quellcodedateien aufgeteilt werden, die aber vollständig sein sollten (d.h. jede sollte sich auch alleine ohne die übrigen übersetzen lassen). Eine Funktion wird nur ausgeführt, wenn sie im Programmcode aufgerufen wird (die einzige Ausnahme ist die main()-funktion, die automatisch beim Programmstart vom Betriebssystem aufgerufen wird). Ist der Code einer Funktion abgearbeitet, springt die Programmausführung zurück zum Aufrufer und setzt dort fort. double quadrat(double x) return x*x; // die Funktion wird definiert // hier wird das Ergebnis der Funktion festgelegt... quadrat; // kein Aufruf der Funktion: Klammern fehlen quadrat(1.0); // Aufruf der Funktion: Ergebnis nicht verwendet double u = quadrat(4.0); // 1 Aufruf der Funktion quadrat() double v = quadrat(u) + quadrat(3.0) // 2 Aufrufe der Funktion Funktionsargumente und Rückgabewert Viele Funktionen brauchen Eingabewerte vom Aufrufer, aus denen sie das Resultat berechnen. Es gibt daher einen Übergabe-Mechanismus, der es dem Aufrufer erlaubt, beliebig viele Daten an die Funktion zu übergeben (= Funktionsargumente) und der es der Funktion gestattet, das Ergebnis (es ist nur 1 Wert gestattet!) an den Aufrufer zurückzugeben (= Funktions-Rückgabewert). Sowohl die Funktion als auch der/die Aufrufer definieren die Funktionsargumente. Die Funktion definiert dabei die sog. formalen Funktionsargumente (oben: double x), die innerhalb der Funktion wie lokale Objekte benützt werden dürfen, und den Rückgabewert-Typ (oben double). Der Aufrufer spezifiziert im Aufruf die aktuellen Funktionsargumente (oben bei den 3 Aufrufen: 4.0, u, 3.0). C und C++ sind stark typisierte Sprachen, d.h. der Compiler überwacht

genauestens, ob die Anzahl der formalen Argumente mit der Anzahl der aktuellen Argumente übereinstimmt (oben: jedes Mal genau 1 Argument) und ob die Typen der formalen Argumente mit den Typen der aktuellen Argumente übereinstimmen oder zumindest kompatibel sind (oben: alle sind double).... int i = quadrat(1) + quadrat('a'); Bei diesem Aufruf sieht man mehrere Typ-Ungleichheiten: der erste Aufruf übergibt den int 1, der 2. den char 'a' als aktuelles Argument (statt double), der Compiler wandelt beide Argumente stillschweigend in double um, d.h. er führt aus: int i = quadrat(1.0) + quadrat(97.); // 'a' ist 97 Die rechte Seite ist vom Typ double (,da das der Rückgabewert-Typ der Funktionsaufrufe und der Addition ist). Dieser Wert wird sodann in einen int konvertiert und die Variable i damit initialisiert. Syntax der Funktionsdefinition Ergebnistyp Funktionsname(formales Argument 1, f. Argument 2,...) Anweisung 1; // Anweisungen enden mit Strichpunkt Anweisung 2;... // kein Strichpunkt! Jedes formale Funktionsargument besteht aus einer Typangabe und einem Namen (und in C++ optional einem Defaultwert). Die Funktionsdefinition bestimmt sowohl die Signatur der Funktion (Ergebnistyp, Name, formale Argumenttypen, Zusätze wie noexcept, constexpr etc.) als auch deren Code. Die Namen der Argumente gehören nicht zur Signatur (nur deren Typ). Beispiel: constexpr int summe(int a, int b) noexcept return a+b; Ergebnistyp: int

Name der Funktion: summe 1. Argument: int a, kein Defaultwert 2. Argument: int b, kein Defaultwert Zusätze: constexpr (Funktionsergebnis darf u.u. schon vom Compiler berechnet werden) noexcept (Funktion erzeugt keine Exceptions = Laufzeitfehler) Signatur: constexpr int summe(int, int) noexcept Der Compiler prüft beim Aufruf von Funktionen (d.h. der Name der Funktion gefolgt vom Aufruf-Operator () steht irgendwo im Programm), ob die richtige Anzahl von aktuellen Argumenten und die richtigen Typen vorhanden sind: summe(1) // Fehler: nur 1 aktuelles Argument vorhanden summe(1, 2) // korrekt: das Ergebnis ist 3 (1+2) // der Compiler wird statt des Funktionsaufrufs // dessen Ergebnis 3 verwenden (constexpr) summe(1.5, 2.1) // C/C++: korrekt: Wert ist 3 (1+2), Java: Fehler! summe("1", 2) // Fehler oder Warnung: das 1. Argument ist ein String // das Ergebnis ist nicht vorhersagbar!! Man sieht hier, dass C (und C++, Java) beim Programmaufruf automatisch einige Typumwandlungen vornehmen können, wenn solche definiert sind (z.b. double -> int in C/C++ aber nicht in Java). Es wird immer das aktuelle Argument beim Aufruf in den Typ des formalen Arguments der Funktions-Definition gewandelt. Manchmal gibt es trotzdem eine Compilerwarnung dafür. Falls es keine (gute) Typumwandlung gibt (wie hier Zeichenkette -> int beim letzten Beispiel) erfolgt eine Fehlermeldung oder auch nur eine Warnung. Die formalen Argumente der Funktionsdefinition (hier a,b) stehen innerhalb der Funktion wie lokale Variable zur Verfügung. Ihre Anfangswerte erhalten sie vom Aufrufer der Funktion (entweder als Kopie oder als Referenz etc.!). Der Rückgabetyp auto ist seit C++14 für Funktionen erlaubt. C++ bestimmt in diesem Fall den Ergebnistyp aus der (den) return-anweisung(en). constexpr auto summe(int a, int b) noexcept return a+b;

Syntax des Funktionsaufrufs Funktionsname(aktuelles Argument 1, aktuelles Argument 2,...) Insbesondere müssen die Klammern geschrieben werden, auch wenn keine Argumente vorhanden sind! sin(x) sin() sin // Aufruf der Funktion sin mit dem aktuellen Argument x // Aufruf der Funktion sin ohne Argument: Fehler // KEIN Aufruf der Funktion, sondern das Funktionsobjekt Verwendung von void C/C++/Java verfügen nicht, wie etwa Pascal, über sogenannte Routinen oder Prozeduren (Unterprogramme ohne Ergebnis) sondern nur über Funktionen, die immer ein Ergebnis und deshalb einen Rückgabetyp haben müssen! Aus Kompatibilitätsgründen wäre früher ein fehlender Rückgabetyp als int interpretiert worden, moderne C++-Versionen gestatten solche Konstruktionen nicht mehr. Um nichts zurückzugeben, existiert seit einiger Zeit der Datentyp void. Ein expliziter Rückgabetyp void besagt, dass die Funktion kein Ergebnis besitzt. In diesem Fall darf sie im (in den ) return-statements auch keinen Rückgabewert spezifizieren. Hat die Funktion auch keine Aufruf-Parameter, so sollte man in C (nicht nötig in C++ oder Java, aber erlaubt) auch hier explizit void in die Klammern schreiben, weil aus Kompatibilitätsgründen eine leere Liste für C nicht bedeutet, dass keine Argumente erlaubt sind. Für C++ und Java gilt: Hat die Funktion in der Definition keine Argumente, darf sie auch nur so aufgerufen werden. void f() // diese Funktion darf in C mit Argumenten aufgerufen // werden, hat kein Resultat // darf in C++ und Java nicht mit Argumenten aufgerufen werden void f(void) // die Funktion darf KEINE Aufrufargumente haben, hat kein Resultat Die return-anweisung

Mit der return-anweisung wird eine Funktion beendet. Folgt dem Schlüsselwort return ein Ausdruck, legt dieser den Rückgabewert fest. Nur auf diese Art können Rückgabewerte für Funktionen vereinbart werden. Eine Funktion kann mehrere return-statements haben (die aber dann meistens in if-blöcken stehen). Die erste ausgeführte return- Anweisung beendet die Funktion (und vereinbart, wenn vorhanden, das Ergebnis). Falls nötig, wird auch eine automatische Typkonvertierung des Ausdrucks in den Rückgabewert- Typ der Funktion gemacht. Auch mit der schließenden geschwungenen Klammer endet die Funktion, es wird hier KEIN Rückgabewert vereinbart. Alle return-anweisungen in einer Funktion sollten natürlich konsistent sein, d.h. alle sollten alle einen Rückgabewert vereinbaren oder keinen. Ist der Ergebnistyp nicht void, sollte zudem als letzte Anweisung vor der schließenden Klammer eine return-anweisung mit einem passenden Rückgabewert sein (verpflichtend in Java!). Das ist sogar erforderlich, wenn die Programmlogik es unmöglich macht, an diese Stelle zu gelangen! Die Funktionsdeklaration Durch eine Funktionsdeklaration wird nur die Signatur der Funktion bekannt gemacht, nicht aber ihr Code. Sie endet mit einem Strichpunkt ohne die Klammern. Man darf/sollte die Namen der Argumente weglassen, da der Compiler diese immer ignoriert. Ergebnistyp Funktionsname(Argument1, Argument 2,...); // Strichpunkt!! constexpr int summe(int, int) noexcept; // so ist es richtig constexpr int summe(int, int = 1) noexcept; // mit einem Defaultwert constexpr int summe(int = 5, int = 1) noexcept; // mit zwei Defaultwerten constexpr int summe(int a, int b) noexcept; // geht auch, gefällt mir aber nicht so gut void f(); // gut in C++, weniger gut in C s.o. Funktionsdeklarationen benötigt man oft, wenn das Programm aus mehreren Quellcode- Dateien bestehen soll (d.h. bei größeren Programmen). Wann immer ein Aufruf einer Funktion erfolgt, es muss vorher diese Funktion entweder definiert (also ihr ganzer Code wird programmiert) oder deklariert werden. Eine Funktion darf in einem Programm nur einmal (eigentlich muss sie genau einmal) definiert werden, kann aber beliebig oft konsistent deklariert werden. Sehr oft erfolgen diese Deklarationen in Headerdateien, die dann per #include eingefügt werden. Dies gilt insbesondere auch für die Bibliotheksfunktionen von C/C++:

std::cin ist deklariert in iostream (auch std::cout, << usw.) sin() ist deklariert in cmath (auch exp(),log() usw.) exit(), EXIT_SUCCESS ist deklariert in cstdlib Die main-funktion Die main()-funktion in C/C++ hat immer den Rückgabetyp int. Der Rückgabewert ist für das Betriebssystem ein Fehlercode, der aussagt, ob das Programm erfolgreich ohne Fehler ablaufen konnte oder ob es zu einem Fehler kam. Der Wert 0 steht für Erfolg und jeder andere Wert als Anzeichen für einen Fehler. Lesbarer wird das Programm aber durch die Verwendung der Makros EXIT_SUCCESS (ist logischerweise 0) und EXIT_FAILURE (ist 1) aus cstdlib Die main()-funktion in C/C++ hat entweder kein Argument oder aber meist genau 2 oder 3. Wir werden vorderhand nur die Version ohne Argument verwenden, somit lautet die Definition bis auf Weiteres: int main() // in C: int main(void)... return EXIT_SUCCESS; Jede Rückkehr aus der main()-funktion beendet das Programm. Überladen von Funktionen In C++ (aber nicht in C!) ist es erlaubt, denselben Funktionsnamen im gleichen Scope für verschiedene Funktionen zu verwenden. Diese müssen sich dann in der Argumentliste unterscheiden (entweder haben sie eine andere Anzahl von Argumenten oder wenigstens ein Argument hat einen unterschiedlichen Typ). Ein unterschiedlicher Rückgabetyp reicht nicht aus, natürlich auch nicht ein anderer Name eines formalen Arguments: Erlaubt sind z.b. folgenden Paare von Funktionen: void read(int& a) void read(double& x) // jeweils 1 Argument, aber unterschiedlicher Typ int f(int a) int f(int a, int b)

// 1 Argument vs. 2 Argumente int f(int a) int f(int& a) // jeweils 1 Argument, aber unterschiedlicher Typ!! Falsch: int f(int a) double f(int b) // jeweils 1 Argument mit gleichem Typ!! // Rückgabetyp und Name des Arguments werden NICHT verglichen Überladene Funktionen werden als absolut eigenständige Objekte behandelt, d.h. sie müssen keineswegs eine ähnliche Aufgabe haben (obwohl das meist der Fall ist). Beim Aufruf von überladenen Funktionen muss es für den Compiler eindeutig sein, welche der überladenen Funktionen aufgerufen werden soll, sonst ist es ein Fehler! 1) int f(int a, double b)... 2) int f(double a, int b)... 3) int f(double a, double b)... f(1, 1.0) f(1.0, 1) f(1.0, 2.0) f(1, 2) // Aufruf von 1), da exakte Übereinstimmung // Aufruf von 2), da exakte Übereinstimmung // Aufruf von 3), da exakte Übereinstimmung // Fehler: keine exakte Übereinstimmung, alle Varianten gleichwertig Findet der Compiler keine exakt passende Funktion mit diesem Namen, untersucht er auch alle Funktionen mit dem gleichen Namen, die er mit einer (oder mehrerer) erlaubten Typumwandlung(en) aufrufen kann. Gibt es hier mehr als eine Möglichkeit, ist das ein Fehler! Es ist dabei egal, wie viele Typumwandlungen für den Aufruf nötig wären: f(1, 2): könnte 1) aufrufen und 2 in 2.0 umwandeln könnte 2) aufrufen und 1 in 1.0 umwandeln könnte 3) aufrufen und 1 in 1.0 und 2 in 2.0 umwandeln Das Überladen von Funktionen in der Standardbibliothek C++ macht von diesen Möglichkeiten auch in den Standardbibliotheken (z.b. <cmath>) regen Gebrauch, während C hier passen muss: Alle Funktionen der Mathematikbibliothek werden in C++ für die Typen float, double und long double extra implementiert: float x;

sin(x); double a; std::abs(a); // -> float sin(float) // -> double abs(double) Aber Achtung: Auch in <cstdlib> ist eine abs()-funktionen definiert, nämlich: long abs(long). Diese Funktion sollte man nicht aufrufen, wenn das Argument ein Gleitkommatyp ist. Daher IMMER #include <cmath> verwenden, wenn man die abs() Funktion für Gleitkommazahlen (float, double) braucht. C muss für die unterschiedlichen Varianten unterschiedliche Namen definieren: int abs(int); long labs(long); double fabs(double);