• Keine Ergebnisse gefunden

12. Unterprogramme (Funktionen)

N/A
N/A
Protected

Academic year: 2022

Aktie "12. Unterprogramme (Funktionen)"

Copied!
25
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Teil A: Grundlagen strukturierter Programmierung

II. Fortgeschrittene Elemente der Programmierung

(2)

Rezept 105 – Gefüllte Tomaten

Zutaten:

1 ½ kg (8 grössere) Fleischtomaten 50 gr. Fett oder Margarine

1-1 ½ Tassen Wasser Salz

Für die Füllung

400 gr. Mageres Hackfleisch 2 mittelgrosse Zwiebeln 40 gr. (1 Handvoll) Reiskörner je 1 Bund Dill und Petersille

Zubereitung:

Tomaten waschen und einen flachen Deckel abschneiden. Das Fruchtfleisch mit einem Teelöffel aushöhlen und unter den Hackfleisch kneten, der wie Dolma-Rezept Nr. 1 zubereitet wird. Ausgehöhlte Tomaten mit Hackfleisch füllen, Deckel wieder aufsetzen und in einem Topf aufreihen. Mit Fettflocken belegen, mit Wasser begiessen und bei Mittelhitze zugedeckt 30-35 Minuten dünsten.

Eingabe (E)

Verarbeitung (V)

Ausgabe (A)

Teilrezept

(3)

12. Unterprogramme (Funktionen)

Ziele dieser Einheit:

- Aufgabenzerlegung in logisch abgeschlossene

Programmeinheiten zur Vermeidung überdimensionaler Programme.

- Erhöhung der Lesbarkeit und Erleichterung der Pflege langlebiger Programme („Legacy/Heritage Software“).

- Disziplinierung der Kommunikation zwischen

unterschiedlichen Programmeinheiten.

(4)

– Umfangreiche, komplexe Funktionalitäten führen oft zu Programmen, die zu lang und damit meist schwer verständlich werden.

– Gleiche Aufgabenstellungen, die an verschiedenen Stellen des Programms benötigt werden, werden wiederholt geschrieben.

– Ausweg: Lösung so lange in kleinere Teile zerlegen, dass nur noch leicht überschaubare Einheiten („Moduln“) übrig bleiben.

12.1 Motivation

(5)

12.2 Grundbegriffe

Prinzip: Teile und herrsche!

– Das Unterprogramm besteht dann aus:

• Programmkopf,

• Deklarationsteil,

• Unterprogramm-Körper („body“) als eigentliche Arbeitseinheit.

– Im Hauptprogramm: Aufruf(e) des Unterprogramms.

(6)

– Das Unterprogramm (UP) wird bei seinem Aufruf aktiv (erhält die Steuerung).

– Nach der letzten Anweisung ( „ } “) des UP erhält das Hauptprogramm (HP) die Steuerung wieder.

– UPe können selber UPe haben und eigene (lokale) Variablen besitzen. Diese sind für das HP unsichtbar

– (Globale) Variable des Hauptprogramms sind für das UP sichtbar.

– Aufgerufene UPe können vom HP (aufrufendes

Programm) Parameter erhalten.

(7)

- Beispiel: int square ( int zhl ) {

int quadrat= zhl*zhl;

return quadrat;

} Funktionsdefinition

Datentyp Bezeichner ( Parameterliste )

Zusammengesetzte Anweisung

12.3 Unterprogramme in C: Funktionen

- Bemerkung: Datentyp (hier: int - Rückgabetyp) entspricht dem Datentyp, den die Funktion zurückgibt (return).

(8)

Anweisung ;

Zusammengesetzte Anweisung (compound statement)

{ }

Datentyp Parameterliste

Bezeichner ,

(9)

12.3.1 Parameter

– Unterprogramme (Funktionen) sollten für möglichst viele Zwecke einheitlich benutzt werden können.

– Bei vielen Berechnungen ändern sich nur einige Parameter, der Rechengang bleibt gleich.

– An verschiedenen Stellen des Hauptprogramms tragen diese Parameter unterschiedliche Namen bzw. Werte.

– Die Parameter im Hauptprogramm sind aktuelle Parameter, die im Unterprogramm dagegen sind formale Parameter.

– Bei Aufruf des Unterprogramms werden formale Parameter zu

aktuellen (Parameter-Übergabe). Dann wird das Unterprogramm mit diesen Werten ausgeführt.

(10)

- Beispiel:

#include <stdio.h>

int square ( int zhl ) {

int quadrat = zhl*zhl;

return quadrat;

}

void main() {

int zhl1 = 10;

int zhl2;

zhl2 = square ( zhl1 );

printf("%d quadriert ergibt %d \n",zhl1, zhl2);

}

Aktuelle(r) Parameter Funktionsaufruf

Rückgabewert Rückgabetyp

Formale(r) Parameter UNTERPROGRAMM

HAUPTPROGRAMM Formale(r) Parameter

Aktuelle(r) Parameter

Lokale Variable

Globale Variable Lokale Variable

Globale Variable

(11)

Beispiel:

{

int wert;

...

wert = ...

...

return wert;

}

Formale Parameter

Aktuelle Parameter Rückgabetyp

Aufruf der Funktion im Hauptprogramm mit int zahl = funkt (3, 6.9, 'b');

Definition im Unterprogramm:

int funkt (int zahl1, float zahl2, char zeichen )

(12)

UP: int func (int zahl1, float zahl2, char zeichen){...}

...

HP: func(3, 6.9, 'b'); /* Aufruf */

Bemerkungen

- Die Datentypen der formalen Parameter und des Rückgabetyps können

ƒ einfache Datentypen (int, char, ...), aber auch

ƒ Zeiger und strukturierte Datentypen sein.

Beispiele:

void func1 (struct complex cmp_zhl) {...}

void func2 (struct complex *cmp_zhl) {...}

int *func3 (int *pInt) {...}

- Die Reihenfolge der formalen Parameter entspricht der Reihenfolge der aktuellen Parameter.

Beispiel:

(13)

- Beispiel:

#include <stdio.h>

void func (int zhl) {zhl = 1;} /* Unterprogramm */

...

void main() /* Hauptprogramm */

{

int zahl = 0;

func(zahl); /* Unterprogrammaufruf */

printf("%d ", zahl);

Werteparameter („Call by value“)

- Die Werte der aktuellen Parameter werden den formalen Parametern zugewiesen.

- Diese verhalten sich wie lokale Variablen.

- Daher: Änderungen im Unterprogramm haben keine Auswirkung auf die Werte der aktuellen Parameter im Hauptprogramm.

/* Ausgabe: 0 */

(14)

Variablenparameter („Call by reference“)

Beispiel: (Pascal)

- Parameter-Übergabe: Formale Parameter werden durch die aktuellen Parameter ersetzt, d.h. Adressen werden übergeben.

- Daher: Die Änderungen im Unterprogramm werden an die Umgebung übergeben.

- Aber: Call by reference ist in C nicht explizit vorgesehen, jedoch durch Zeiger simulierbar.

PROGRAM prog (OUTPUT);

VAR zahl: INTEGER;

PROCEDURE func (VAR zhl: INTEGER);

(* Unterprogramm *) BEGIN

zhl:=1 END;

BEGIN (* Hauptprogramm *)

zahl:=0; (* Unterprogrammaufruf *) func (zahl);

WRITE (zahl) END.

(* Ausgabe: 1 *)

(15)

Beispiele in C:

#include <stdio.h>

void swap(int zhl1,int zhl2) {

int temp = zhl1;

zhl1 = zhl2;

zhl2 = temp;

}

void main() {

int zahl1=1, zahl2 = 2;

swap(zahl1, zahl2);

printf("Zahl1= %d ", zahl1);

printf("Zahl2= %d", zahl2);

/* Ausgabe: Zahl1= 1 Zahl 2= 2 */

/* Kein Vertauschen! */

#include <stdio.h>

void swap(int *zhl1,int *zhl2) {

int temp = *zhl1;

*zhl1 = *zhl2;

*zhl2 = temp;

}

void main() {

int zahl1=1, zahl2 = 2;

swap(&zahl1, &zahl2);

printf("Zahl1= %d ", zahl1);

printf("Zahl2= %d", zahl2);

/* Ausgabe: Zahl1= 2 Zahl2= 1 */

/* Vertauschen findet statt! */

Call by value: (Simuliertes) Call by reference:

(16)

- Bedeutung: Nach Beendigung einer Funktion Rückgabe eines Wertes an das aufrufende Programm.

- Der Rückgabetyp legt den Datentyp dieses Wertes fest.

- Der Befehl return bricht die Ausführung einer Funktion ab und gibt einen Wert an den Aufrufenden zurück.

Beispiel: int square ( int zhl ) {

return zhl*zhl;

}

- Falls kein Rückgabewert: void Beispiel: void ausgabe ()

{

printf("Hello World\n");

}

12.3.2 Rückgabetyp/-wert

(17)

Sonderfälle

• Das Folgende geht, aber *nicht* nachahmungswürdig:

int square ( int zhl ) {

int square; /* Lokale Variablen mit gleichem Namen wie die Funktion. */

. . .

int quadrat = zhl*zhl;

return quadrat;

}

• Folgendes geht auch, ist aber auch *nicht* nachahmungswürdig : Mit dem return wird ein Pointer auf die Funktion square zurückgegeben.

int square ( int zhl ) {

. . .

return square;

}

(Funktionspointer sind eine „Spezialität„ von C/C++, die wir in dieser Einführungsvorlesung aus gutem Grund unerwähnt lassen.)

• Pointer vor dem Funktionsaufruf erzeugt einen syntaktischen Fehler (es ist auch gut so!):

&square(zhl1);

(18)

12.3.3 Felder als Funktionsparameter

- Werden Felder als Parameter in Funktionen benutzt, wird beim

Funktionsaufruf nur die Adresse des ersten Feldelements übergeben.

- Konsequenzen:

ƒ Als Argument übergebene Felder können in Funktionen verändert werden.

ƒ Keine Feldgrenzenüberprüfung beim Funktionsaufruf mit Feldern!

ƒ Bei der Definition von Feld-Parametern: Einen entsprechenden Zeigertyp explizit angeben. Sonst findet automatisch eine

Umwandlung in einen Zeigertyp statt!

(19)

Beispiel 1: Die Funktion quad

#include <stdio.h>

void quad(int vector[], int len) {

int idx;

for(idx=0; idx<len; idx++)

vector[idx] = vector[idx]*vector[idx];

}

void main() {

int vektor[10]; int idx;

for(idx=0;idx<10;idx++)

vektor[idx]=idx+1; /* vektor[0]=1, vektor[1]=2, ..., vektor[9]=10 */

quad(vektor, 10);

for(idx=0;idx<10;idx++)

printf ("vektor[%d]=%d\n",idx,vektor[idx]);

quadriert alle Elemente eines Feldes.

(20)

Beispiel 1`: Die Funktion quad

#include <stdio.h>

int quad(int zahl) {

return zahl*zahl;

}

void main() {

int vektor[10]; int idx;

for(idx=0;idx<10;idx++) vektor[idx]=idx+1;

for(idx=0;idx<10;idx++)

vektor[idx]=quad(vektor[idx]);

for(idx=0;idx<10;idx++)

printf ("vektor[%d]=%d\n",idx,vektor[idx]);

}

quadriert eine gegebene Zahl.

(21)

- Bisher: void main() oder int main() - Ebenfalls möglich:

void main ( int argc, char *argv[] ) oder int main ( int argc, char *argv[] )

ƒ int argc: Anzahl der Kommadozeilenparameter (arguments)

ƒ char *argv[]: Feld mit Zeigern auf die einzelnen Parameter

ƒ Zeigerfeld argv dient zur „Kommunikation“ mit dem

Betriebssystem (das Betriebssystem ruft beim Start des Programms die main-Funktion auf)

Beispiel 2: Die main-Funktion

(22)

- Beispiel: Ausgabe der einzelnen Elemente der Kommandozeile.

#include <stdio.h>

void main ( int argc, char *argv[] ) {

int idx;

for(idx=0; idx<argc; idx++) {

printf("Parameter %d : %s \n", idx, argv[idx]);

} }

- Der ausführbare Objekt-Code sei in der Datei dtei . Die Ausgabe ist dann:

Parameter 0 : <Pfad-Name>dtei.exe

Parameter 1 : <Kommandozeilenparameter>

...

(23)

12.3.4 Bemerkungen

- Keine Schachtelung von Funktionen in Standard (ANSI)-C!

- ABER: Funktionen dürfen sich selbst aufrufen (Rekursion).

- Zeiger auf Funktionen sind möglich.

(24)

12.4 Bibliotheken

- „Wer alles selber macht, ist (auch) selber Schuld!“

- Denn: In Programmen werden öfter Lösungen für Teilaufgaben benötigt, die bei vielen Programmierern immer wieder vorkommen.

- Es ist nicht nötig, für diese Lösungen selber (Quell-)Programme zu schreiben, zu übersetzen usw. Oft stehen sie allen Benutzern in einer effizienten Form (Objekt-Code) zur Verfügung.

- Die meisten höheren Programmiersprachen bieten daher diese Lösungen im Sprachumfang als Bibliotheksfunktionen an.

(25)

<assert.h> <ctype.h> <errno.h> <float.h> <limits.h>

<locale.h> <math.h> <setjmp.h> <signal.h> <stdarg.h>

<stddef.h> <stdio.h> <stdlib.h> <string.h> <time.h>

- Die Standard Library ist eine standartisierte Bibliothek für C - Stellt wichtige Funktionen bereit zur

- Ein- und Ausgabe

- Zeichenketten- (String-)Verarbeitung - Mathematische Funktionen

- Speicherverwaltung usw.

Standard Library für C

Header-Dateien der Standard-Library:

Referenzen

ÄHNLICHE DOKUMENTE

Ziel dieser Aufgabe ist es, beide Funktionen in eine generalisierte Initialisierungs- funktion zu ¨ uberf¨ uhren.. Dazu m¨ ussen wir sie lediglich um zwei Parameter erweitern, die

Aufgabe : eine generalisierte Funktion zur Initialisieren eines Zeichen-Arrays Parameter : drei Parameter: Anfangswert, Array, Gr¨ oße.. Ausgabe : die Inhalte der beiden

Zachmann Informatik 1 - WS 05/06 Einführung in Python, Teil 2

Jeder natürlichen Zahl werden ihre Teiler zugeordnet.. Jeder reellen Zahl wird ihr

Scheitel Nullstellen Schnittpunkte Extremwert Zeichnung... Den

Scheitel Nullstellen Schnittpunkte Extremwert Zeichnung... Den

o Funktionen zur Beschreibung von Abhängigkeiten benutzen und in verschiedenen mathematischen Formen ausdrücken/ darstellen können. o selbstständig Experimente durchführen und

In jeder separat übersetzbaren Datei muss jede verwendete In jeder separat übersetzbaren Datei muss jede verwendete Variable oder Funktion.. Variable oder Funktion definiert