Funktionen allgemein / call by value


Eine der wichtigsten Herangehensweise bei der Programmierung von Computern / Mikrocontrollern ist das Aufteilen des Programms in Haupt- und Unterprogramme.

Unterprogramme dienen dafür, öfters wiederkehrende Aufgabenstellungen in einem Programm (und nur diese) zu bearbeiten. Unterprogramme werden in C als function bezeichnet.

Zu jedem C-Compiler gehört ein Softwarepaket, den sogenannten Standardbibliotheken, die bereits eine Vielzahl von Funktionen zur Verfügung stellen (bspw. die Bibliothek math, die Funktionen für mathematische Aufgaben  zur Verfügung stellt).

Eine gute Unterteilung eines Programms in sinnvolle, selbst erstellte  Funktionen sollte in jedem Programm stattfinden, damit dieses gut wartbar und an evtl. geänderte Anforderungen anpassbar ist.

Grundsätzlich gibt es 2 Arten von Funktionen:
  • ohne Rückgabe eines Ergebniswertes
  • mit Rückgabe eines Ergebniswertes
Bei der Definition einer Funktion ist IMMER der Datentyp des Rückgabewertes anzugeben. Funktionen, die keinen Wert zurück geben haben den Datentyp void (engl. leere, nichts).

Beispiel für eine Funktion ohne Rückgabewert:

  /* ----------------------------------------------------------
       example_f01.c

       Beispiel zur Verwendung von Funktionen
   ---------------------------------------------------------- */
  #include "smallio.h"
  
  /* ------------------------------------------
                     tu_etwas
                 eine eigene Funktion
   ------------------------------------------ */
  void tu_etwas(void)                    // die Funktion heisst "tu_etwas"
  {
    printf("\n\r Ich tu ja schon was...\n\r");
  }
  
  /* ------------------------------------------
                        main
       auch "main" ist eine Funktion, sie ist
       die Hauptfunktion des Programmes
     ------------------------------------------ */
  int main(void) 
  {
    
    smallio_init();

    tu_etwas();                         // Aufruf der eigenen Funktion
  }

Das Beispiel macht nicht wirklich viel, es verdeutlich jedoch den Aufruf einer Funktion. Hat die Funktion wie im Fall oben keinerlei weitere Funktionsargumente, so ist als Parameter für die Funktion das Schluesselwort void (für "nichts") anzugeben.

Funktionen können optional ein oder mehrere Funktionsparameter enthalten, die innerhalb der Funktion ausgewertet werden. Für jeden Funktionsparameter ist der Datentyp anzugeben. Ein solcher Funktionsparameter ist, wenn nicht durch const eingeschränkt, auch als Variable innerhalb der Funktion verwendbar.

Werden Parameter angegeben, wird beim Funktionsaufruf Speicher für diese Parameter reserviert, die innerhalb der Funktion als Variable verwendet werden können. Nach Beendigung der Funktion wird dieser Speicher wieder freigegeben.

Gleiches gilt für Variable, die innerhalb einer Funktion angelegt werden (es sei denn, sie sind als static definiert). Für diese Variable wird beim Aufruf ebenfalls Speicher reserviert, der bei Beendigung der Funktion wieder frei gegeben wird.

Beispiel:


  /* ----------------------------------------------------------
       example_f02.c

       Beispiel zur Verwendung von Funktionen
     ---------------------------------------------------------- */
  
  #include "smallio.h"
  
  void print_add(uint16_t z1, uint16_t z2)
  {
    uint16_t ergeb;

    ergeb= z1 + z2;
    printf("\n\r %d + %d = %d \n\r", z1, z2, ergeb);
  }
  
  /* ------------------------------------------
                      main
     ------------------------------------------ */
  int main(void)
  {
    uint16_t zahl;                   // Variable, nur gueltig fuer main
  
    smallio_init();
  
    zahl= 42;
    print_add(zahl, 119);            // Aufruf der eigenen Funktion
}
  
Funktion mit Rückgabewert

Bei Funktionen, die ein Ergebnis zurück geben sollen, muss anstelle von void der Datentyp angegeben werden, den er zurueckliefern soll. Im nachfolgenden Beispiel ist dieses:

    int16_t addiere(int16_t zahl1, int16_t zahl2)
Die Funktion addiere liefert hier einen Wert vom Datentyp int16_t zurück, dessen Ergebnis einer Variablen vom selben Typ zugewiesen werden kann.

Das Ergebnis, das eine solche Funktion zurückliefert, wird durch die Angabe von
    return wert;
erreicht. return beendet auch die Funktion (unabhängig davon, ob im Quelltext weitere Anweisungen folgen oder nicht).

Beispiel:


  /* ----------------------------------------------------------
       example_f03.c

       Beispiel zur Verwendung von Funktionen mit Rueckgabewert
     ---------------------------------------------------------- */

#include "smallio.h" int16_t addiere(int16_t zahl1, int16_t zahl2) { int16_t ergeb; ergeb= zahl1 + zahl2; return ergeb; } /* ------------------------------------------ main ------------------------------------------ */ int main(void) { int16_t z1, z2, summe; // Variable nur gueltig fuer main smallio_init(); z1= 42; z2= 121; summe= addiere(z1, z2); printf("\n\r %d + %d = %d \n\r", z1, z2, summe); summe= addiere(128, 384); printf("\n\r %d + %d = %d \n\r", 128, 384, summe); }
Erklärungen:

Mit addiere wird eine Funktion definiert (programmiert), die zwei Zahlen
miteinander addiert und die Summe hiervon als Rückgabewert der Funktion
liefert.

Im Hauptprogramm main sind Variable z1, z2 und summe definiert. z1 und z2 werden Werte zugewiesen und diese Variable der Funktion addiere als Funktionsparameter übergeben.

Das Ergebnis der Funktion wird der Variable summe zugewiesen und ein anschliessendes printf gibt das Ergebnis der Addition aus.

Ein zweiter Aufruf von addiere erfolgt dieses mal nicht mit Variablen, sondern mit konstanten Werten. Auch diese werden von der Funktion addiere verarbeitet (und anschliessend ausgegeben).


call by reference



Wird einer Funktion anstelle eines Wertes (value) die Speicheradresse (reference) einer Variable übergeben (nicht die Variable selbst) die den Wert beinhaltet, so wird der Aufruf einer solchen Funktion als "call by reference" bezeichnet. Die Übergabe der Speicheradresse wird mittels Zeigervariable (Pointer) vorgenommen.

Das nachfolgende Beispielprogramm beinhaltet zwei "call by reference" Funktionen:

  • "myprint" gibt einen Text aus
  • " searchreplace" sucht nach einem Zeichen in diesem Text und ersetzt alle vorkommenden Zeichen durch ein anderes

Beispielprogramm:

 
 /* ----------------------------------------------------------
       example_f04.c

       Beispiel fuer "call by reference"
     ---------------------------------------------------------- */      
     
 #include "smallio.h"
 	
 void myprint(char *mytext)     // mytext beinhaltet Adresse des Textes
 {
   char   ch;
 
   while(*mytext)               // wiederhole solange, bis das Zeichen
   {                            // auf das *mytext zeigt > 0 ist und
                                // somit keine Endekennung ist.
     ch= *mytext;
     putchar(ch);
     mytext++;                  // Zeiger auf naechstes Element zeigen
                                // lassen
   }
 }
 
 void searchreplace(char search, char replace, char *mytext)
 {
   while(*mytext)
   {
     if (*mytext == search)      // bei Uebereinstimmung des Zeichens
     {
       *mytext = replace;        // an dieselbe Stelle das Ersatz-
     }                           // zeichen setzen
     mytext++;                   // naechstes Element
   }
 }
 
 int main(void)
 {

   char   mytext_dt[] = "Mein Name ist Hase\n\r";
   char   meldung[]   = "\n\rErsetze Buchstaben a durch einen Punkt .\n\n\r";

   smallio_init();              
 
   myprint(&mytext_dt[0]);      // myprint-Funktion wird die Adresse von
                                // mytext_dt mit dem ersten Element ueber-
                                // geben.
   myprint(&meldung[0]);        // dto. mit Meldungstext
 
   searchreplace('a','.', &mytext_dt[0]);
   myprint(&mytext_dt[0]); 
 }
Ausgabe:
  Mein Name ist Hase

  Ersetze Buchstaben a durch einen Punkt .

  Mein N.me ist H.se