next up previous contents
Next: Funktionen ohne Argumente oder Up: Grundlagen von C++ Previous: switch-Anweisung


Funktionen und Operatoren

Längere Programme enthalten in der Regel Programmteile, die sich mehr oder weniger häufig wiederholen. Diese Teile will man gern an anderer Stelle ausführlich definieren, und im Programm nur durch einen ``Platzhalter'', also einen Funktionsaufruf ersetzen. Ein Beispiel ist das Einholen einer Bestätigung durch den Benutzer, ob eine bestimmte numerische Aufgabe das Löschen oder das Umsortieren von Daten ausgeführt werden soll. Weiterhin möchte man häufig aus Gründen der Übersicht bestimmte Programmteile gruppieren und wenn möglich, die dazugehörigen Anweisungen nur noch durch einen Namen kennzeichnen, der ihre ``Funktion'' charakterisiert.

Das zu diesem Zweck existierende Sprachmittel sind die Funktionen, die in anderen Sprachen auch Prozeduren oder Unterprogramme genannt werden. Eine Funktion ist gekennzeichnet durch Parameter, die eine Art ``Eingabe'' in den Funktionsblock darstellen und solche, die eine ``Ausgabe'' darstellen. Im einfachsten Falle erfolgt die Übergabe der Eingabeparameter als Argument an die Funktion und die ``Ausgabe'' durch einen entsprechenden Rückgabewert.

Außer in wenigen Ausnahmefällen erzwingt C++ die Spezifikation von Argument- und Rückgabetypen von Funktionen. Hier definiert power eine Funktion, die aus einer Eingabe eines doppeltgenauen Wertes base und einer ganzen Zahl exponent einen neuen ``double''-Wert berechnet und zurückgibt. Der Name deutet an, welcher Algorithmus sich dahinter versteckt.

// raise 'base' to the power 'exponent', with exponent being integer, 
// base being double; accept also negative exponents
double power(double base, int exponent){
   double result  = 1.;    // will multiply this by base 'exponent' times
   bool   neg_exp = false; 
   if (exponent < 0 ) {    // for negative exponents we use a single
                           // division at the end of the function
      neg_exp = true;
      exponent = -exponent;
   }
   for (int i=0; i < exponent; i++ )
      result *= base;      // successive multiplication
   if ( neg_exp )          // have to take the inverse 
      result = 1./result;
   return result;          // return the result to the calling program
}
Die Namen der Argumente sind wie Variablennamen frei wählbar; unter diesem Namen können sie dann im Funktionskörper angesprochen werden. Der Anweisungsblock des Funktionskörpers wird wie bei Schleifen nicht durch Semikolon abgeschlossen.

Das Schlüsselwort return bricht das Unterprogramm an der spezifizierten Stelle ab, legt den Wert des dahinter angegebenen Ausdrucks auf dem Stack ab und kehrt ins Hauptprogramm zurück. Im obigen Fall besteht dieser Ausdruck nur aus der Variable result. Runde Klammern werden an dieser Stelle nicht benötigt. Ein Unterprogramm kann mehrere return Anweisungen enthalten. Dies kann ein nützliches Mittel sein, um z.B. bei Angabe unpassender Argumenttypen oder bei Problemen mit der Berechnung die Bearbeitung frühzeitig abzubrechen.

Eine Funktion muß definiert oder deklariert sein, bevor sie im Programm verwendet werden kann. Eine Deklaration ist im wesentlichen die erste Zeile der Funktionsdefinition, ohne ihren Körper. Sie teilt dem Compiler den Namen der Funktion und die Typen der Argumente und des Rückgabewertes mit.

  double power(double base, int exponent);
Anstelle des Anweisungsblocks tritt ein einzelnes Semikolon. Während die Angabe des Argumenttyps zwingend ist, ist die eines Namens für die Argumentvariable dem Benutzer freigestellt. Es ist jedoch guter Stil, hier Namen anzugeben, um die Bedeutung der Argumente klarzustellen.

Deklarationen können im Prinzip beliebig häufig im Programm wiederholt werden, sie sind sozusagen ein Versprechen an den Compiler, daß diese Funktion später oder in einem anderen Programmteil definiert wird. Funktionen sind immer globale Objekte innerhalb eines Namesraumes. Man kann Funktionen nicht wie Variablen innerhalb lokaler Bezugsrahmen definieren, z.B. innerhalb eines geschweiften Klammer-Paares (oder eines begin/end-Blockes wie in PASCAL).

Ein Programm, das von der Tastatur eine Zahl liest, dann power benutzt und schließlich das Ergebnis ausgibt, könnte so aussehen:

#include <iostream>
using std::cout;
using std::cin;

double power(double base, int exponent);  // declaration of 'power'

int main(){                               // definition of main
  double in;
  cin >> in;                              // read value from keyboard

  cout << "-3rd to 3rd power of " << in << ": ";
  for( int i= -3; i <= 3; i++ ){
    cout << power(in, i) <<  " ";         // call power and use return value
  }
  cout <<  "\n";
   
  return 0;                               // return to operating system
}
  
double power(double base, int exponent){  // definition of power
  double result = 1.;
  // ... program text as above

  return result; 
}

Die Definition einer Funktion ist die Festlegung des Programmtextes, der bei Aufruf der Funktion ausgeführt werden soll. Geht die Definition einer Funktion ihrer Benutzung voraus, so kann sie eine Deklaration ersetzen. Die Spezifikation des Programmsegmentes für die Funktion erfolgt innerhalb eines geschweiften Klammerpaares, das nicht durch ein Semikolon abgeschlossen wird.

Die Übergabe von Argumenten an eine Funktion erfolgt ``by value,'' d.h., daß in C vor dem Aufruf der Funktion Kopien der Argumente gemacht werden, die üblicherweise auf dem Stapel (Stack) abgelegt werden. Dann erfolgt der Aufruf der Funktion, die dann nur auf den Kopien dieser Variablen auf dem Stapel operiert. Es können so niemals die Werte der Variablen im aufrufenden Programm verändert werden. Möchte man dies erzielen, z.B. in Funktionen, die Werte aus einer Datei oder Benutzereingaben einlesen, so benutzt man Zeiger- oder Referenztypen als Argumente, die wir später in Abschnitt [*] besprechen werden.



Unterabschnitte
next up previous contents
Next: Funktionen ohne Argumente oder Up: Grundlagen von C++ Previous: switch-Anweisung
© R.Hilfer et al., ICA-1, Univ. Stuttgart
28.6.2002