B.6 Antworten und Lösungen zu Kapitel 7
-
Bei einer Vorausdeklaration wird nur der Funktionskopf mit abschließendem Semikolon vor dem Aufruf deklariert (ein Funktionsprototyp). Dem Compiler reicht es hierbei aus, nur den Rückgabetyp, den Bezeichner und die Typen der formalen Parameter zu kennen. Bei einer solchen Deklaration müssen Sie nicht den Anweisungsblock der Funktion definieren. Durch eine Vorwärtsdeklaration kann sich die Definition (wo dann Speicherplatz für die Funktion reserviert wird) irgendwo im Programm befinden.
-
Mit der Call-by-Value-Methode werden Daten als Argumente an eine Funktion übergeben. Diese Daten werden dabei kopiert, indem sie auf dem Stack zwischengespeichert werden. Somit besteht keine Verbindung mehr zwischen dem Aufrufer der Daten und der Funktion. Eine Änderung der Daten in der Funktion hat damit keine Auswirkung auf die Daten des Aufrufers. Der Nachteil bei diesem Verfahren ist, dass bei umfangreichen Daten, die durch das Kopieren an die Funktion übergeben werden, das Laufzeitverhalten des Programms ungünstig verändert wird – es wird quasi ausgebremst.
-
Einen Wert an den Aufrufer können Sie mit der return-Anweisung zurückgeben. Hierbei sollten Sie beachten, dass der mit return zurückgegebene Datentyp mit dem Datentyp des Rückgabewertes der Funktionsdefinition übereinstimmt.
-
Für gewöhnlich werden alle wichtigen Daten für einen Funktionsaufruf im Stack-Segment abgelegt. Wird eine Funktion aufgerufen, wird also auf dem Stack ein Datenblock angelegt, in dem die Rücksprungadresse zum Aufrufer, die Funktionsparameter und die lokalen Variablen der Funktion gespeichert werden. Wird die Funktion wieder verlassen, werden diese Daten freigegeben und sind, wenn keine Zeiger als Funktionsparameter verwendet werden, unwiderruflich verloren.
-
Eine Rekursion bezeichnet eine Funktion, die sich immer wieder selbst aufruft. Wichtig bei solchen sich selbst aufrufenden Funktionen ist eine Abbruchbedingung, die verhindert, dass sich die Rekursion endlos wiederholt. Nach Möglichkeit sollten Sie allerdings, wegen des enormen Speicherverbrauchs auf dem Stack-Segment, auf Rekursionen verzichten und einen iterativen Lösungsansatz verwenden.
-
Eine lokale Variable wird immer innerhalb eines Anweisungsblocks definiert und ist nach außen hin nicht sichtbar. Wird der Anweisungsblock beendet, verliert auch die lokale Variable ihren Wert. Globale Variablen werden hingegen außerhalb der Anweisungsblöcke und Funktionen definiert und sind im kompletten Programm sichtbar. Außerdem werden globale Variablen, im Gegensatz zu lokalen Variablen, bei der Definition initialisiert.
-
Verwenden Sie den Speicherklassen-Spezifizierer static, ist eine Variable oder eine Funktion nur noch in der aktuellen Quelldatei sichtbar.
-
Entweder verwenden Sie eine globale Variable (schlechtere Lösung), oder Sie kennzeichnen eine Variable im Funktionsblock mit dem Spezifizierer static.
-
In diesem Beispiel wurde die Vorausdeklaration der Funktion multi() vergessen:
00 // kap007/loesung001.c
01 #include <stdio.h>
02 #include <stdlib.h>
03 float multi(float);
04 int main(void) {
05 float fval = multi(3.33);
06 printf("%.2f\n", fval);
07 return EXIT_SUCCESS;
08 }
09 float multi(float f) {
10 return (f*f);
11 } -
In diesem Beispiel wurde vergessen, das Ergebnis der Berechnung mittels return zurückzugeben:
00 // kap007/loesung002.c
01 #include <stdio.h>
02 #include <stdlib.h>
03 float volumen_Rect(float l, float b, float h) {
04 float volumen = l*b*h;
05 return volumen;
06 // oder gleich: return l*b*h;
07 }
08 int main(void) {
09 float vol = volumen_Rect(10.0, 10.0, 12.5);
10 printf("Volumen: %f\n", vol);
11 return EXIT_SUCCESS;
12 } -
Hierzu eine mögliche Lösung, die Fakultät ohne eine Rekursion zu berechnen:
00 // kap007/loesung003.c
01 #include <stdio.h>
02 long fakul( long n ) {
03 long val = n;
04 while(--val ) {
05 n*=val;
06 }
07 return n;
08 }
09 int main(void) {
10 printf("Fakultät von 6: %ld\n", fakul(6));
11 printf("Fakultät von 8: %ld\n", fakul(8));
12 return 0;
13 }