Parameter der Dokumentation in C
Das in dieser Lektion vermittelte Verständnis von Parameterbeschreibungen aus der Dokumentation erschließt die Möglichkeit zum Nutzung einer Vielzahl vordefinierter Funktionen.
Typerwartungen
Der Aufrufausdruck »floor( 2.7 )« besteht aus einem Rahmen »floor( … )« und einem an Stelle der Lücke »…« eingesetztem Argumentausdruck »2.7«.
Für diese Lücke »…« darf jedoch im allgemeinen nicht irgendein beliebiger Wertausdruck eingesetzt werden. Das folgende Programm zeigt, daß ein Ausdruck vom Typ »char *« beispielsweise zu einer Fehlermeldung führt.
main.c
#include <stdio.h>
#include <math.h>int main( void )
{ printf
( "%g\n", floor( "2.7" ) ); }- Konsole
main.c: In function 'main':
main.c:4:1: error: incompatible type for argument 1 of 'floor'
{ printf
( "%g\n", floor( "2.7" ) ); }
^In file included from main.c:2:0:
c:\program files (x86)\dev-cpp\mingw64\x86_64-w64-mingw32\include\math.h:154:18: note: expected 'double' but argument is of type 'char *'
double __cdecl floor(double _X);
^- Konsole (übersetzt)
main.c: In Funktion 'main':
main.c:4:1: Fehler: inkompatibler Typ von Argument 1 von 'floor'
{ printf
( "%g\n", floor( "2.7" ) ); }
^In Datei inkludiert von main.c:2:0:
c:\program files (x86)\dev-cpp\mingw64\x86_64-w64-mingw32\include\math.h:154:18: Hinweis: erwartet 'double', aber Argument ist vom Typ 'char *'
double __cdecl floor(double _X);
^
Die Fehlermeldung drückt aus, daß ein Ausdruck vom Typ »double« erwartet wurde, während tatsächlich (“actual ”) ein Ausdruck vom Typ »char *« gefunden wurde.
Der genaue Wortlaut der Fehlermeldungen hängt von der verwendeten C -Implementation ab.
Dokumentation von Typerwartungen
Die Lücken in den Argumentklammern werden auch Parameter genannt (männliches Substantiv mit Betonung auf der zweiten Silbe). Ein Parameter drückt die Erwartung eines Argumentes aus.
Beispiel einer Dokumentation
- Dokumentation einer Funktion mit einem Parameter (nach N1570, überarbeitet, vereinfacht und übersetzt)
- 7.12.9.2 Die Funktion »floor«
- Synopse
#include <math.h>
double floor( double x );- Beschreibung
- Diese Funktion berechnet die größte ganze Zahl, welche nicht größer als »x« ist.
- Ergebniswert
- Diese Funktion ergibt ⌊x⌋ als Gleitkommazahl dargestellt.
In der obenstehenden Dokumentation wird die Schreibweise »⌊x⌋« verwendet, welche die mathematische Schreibweise für den Wert der Bodenfunktion an der Stelle »x« ist.
Parametertyp
Um zu beschreiben, daß bestimmte Lücken in Rahmen nur Ausdrücke bestimmter Typen zulassen, ordnet man Parametern einen Typ zu, den man auch als Parametertyp bezeichnen kann. Zunächst akzeptiert ein Parameter dann Argumente des Parametertyps.
Ein Parameter vom Typ »char *« akzeptiert also ein Argument vom Typ »char *«, nicht jedoch vom Typ »int« oder »double«. Umgekehrt akzeptiert ein Parameter vom Typ »int« oder »double« kein Argument vom Typ »char *«. [Siehe auch N1570: 6.5.2.2p2, Function calls, Constraints und 6.5.16.1p1, Simple assignment, Constraints.]
(Ein Verstoß gegen die genannte Typerwartungen ist eine Einschränkungsverletzung (constraint violation), welche eine Meldung der Implementation verlangt. Da Implementationen Einschränkungsverletzung tolerieren können, muß die Übersetzung des Programms aber nicht unbedingt abgebrochen werden. Dennoch ist ein Programm mit einer Einschränkungsverletzung kein korrektes C -Programm mehr.)
Parameternamen
Damit man sich besser auf einen Parameter beziehen kann, hat ein Parameter auch einen Namen, den Parameternamen. Der Parametername ist eine Bezeichnung für einen Wert (wie beispielsweise eine Zahl), welcher dann erst durch die Angabe eines Argumentausdrucks konkret bestimmt wird. Ein Parametername hat jedoch für einen Aufruf einer Funktion keine Bedeutung. Er erleichtert es nur, sich in der Dokumentation einer Funktion mit Hilfe seines Namens auf den Parameter zu beziehen.
Man erkennt den Parametername bei den Funktionen in diesem Kapitel des Kurses daran, daß er in der Dokumentation in den runden Klammern in der Synopse auf die Angabe eines Typs folgt.
Parameter
In der obenstehenden Dokumentation wird in der Zeile »double floor( double x );« ein Parameter mit dem Typ »double« und dem Namen »x« dokumentiert. Die Funktion kann also mit einem Argument vom Typ »double« aufgerufen werden. In dem Text der Beschreibung der Funktion wird mit »x« auf den Argumentwert bezug genommen.
Das folgende Beispielprogramm zeigt einen der Dokumentation entsprechenden Aufruf mit einem Argumentausdruck vom Typ »double«.
main.c
#include <stdio.h>
#include <math.h>int main( void )
{ printf
( "%g\n", floor( 2.7 )); }stdout
2
In der Dokumentation einer Funktion, die einen Parameter hat, findet man also eine Beschreibung (wie beispielsweise »double x«) dieses Parameters, die aus einem Typ und manchmal einem Namen besteht.
⚠ Die Dokumentation einer Funktion erklärt dem Leser die Eigenschaften und die Bedeutung dieser Funktion. Sie ist nicht dafür gedacht in ein C -Programm kopiert zu werden. In der Dokumentation steht beispielsweise »double floor( double a )«, ein korrekter Aufruf dieser Funktion ist beispielsweise »floor( 2.7 )«. Die Parameterbeschreibung »double a« aus der Dokumentation gehört also nicht in den Quelltext.
Parameter und Argumente
Parameterbeschreibungen und Argumentausdrücke werden manchmal miteinander verwechselt: Parameterbeschreibungen finden sich in der Dokumentation als Beschreibung einer Lücke, sie drücken das Fehlen eines bestimmten Wertes aus, die Erwartung eines Ausdrucks im Quelltextes beziehungsweise eines Wertes eines bestimmten Datentyps zur Laufzeit. Argumentausdrücke finden sich im Quelltext innerhalb mancher Ausdrücke und geben den zur Ermittlung des Parameterwerts zu nutzenden Ausdruck an, beispielsweise ein Numerale. Da Parameterbeschreibungen das Fehlen eines Wertes ausdrücken und Argumentausdrücken einen Wert, sind Argumentausdrücke gewissermaßen das Gegenstück von Parameterbeschreibungen.
Leere Parameterlisten
Wenn die Klammern hinter dem Funktionsnamen in der Dokumentation nur das Wort »void« enthalten, dann hat die dokumentierte Funktion keine Parameter, und muß entsprechend auch mit leeren Klammern (also ohne Argument ) aufgerufen werden.
- Dokumentation von »rand()« (gekürzt, überarbeitet und eingedeutscht)
- 7.22.2 Funktionen, die Zufallszahlen erzeugen
- 7.22.2.1 Die Funktion »rand«
- Synopse
#include <stdlib.h>
int rand( void );- Ergebniswert
- Diese Funktion ergibt eine Pseudo-Zufallszahl zwischen »0« (einschliesslich) und »RAND_MAX« (einschliesslich).
double-Parameter und int-Argument
Das Literal »2« bezeichnet offensichtlich dieselbe Zahl wie das Literal »2.«, nämlich die Zahl Zwei. Der Datentyp von »2« ist aber »int«, während der Datentyp von »2.« »double« ist. Obwohl »2« und »2.« beide dieselbe Zahl Zwei bedeuten, sieht man in C in beiden zunächst zwei verschiedene Werte, denn sie unterscheiden sich im Datentyp. Man kann aber jedem int -Literal ein gleichwertiges double -Literal zuordnen, indem man an das int -Literal noch einen Punkt anfügt. Dementsprechend kann man jeden int -Wert einen gleichwertigen double -Wert zuordnen. Damit sind die int -Werte praktisch alle im Datentype »double« „enthalten“.
Diese „Einbettung“ der int -Werte in den Datentyp »double« macht es es verständlich, daß ein int -Argumentausdruck auch bei einem double -Parameter akzeptiert wird. Der int -Wert wird dabei in den ihm gleichwertigen double -Wert umgewandelt (N1570:6.3.1.4 und N1570:6.5.2.2p7).
Das folgende Programm zeigt die Verwendung des int-Arguments »2« bei einer Funktion mit einem Parameter vom Typ »double«.
main.c
#include <stdio.h>
#include <math.h>int main( void )
{ printf
( "%g\n", floor( 2 ) ); }stdout
2
Das folgende Programm zeigt den Unterschied zwischen Argumentausdruck und Argumentwert : Der Argumentausdruck ist »rand()« und kann durch Lesen des Quelltextes in Erfahrung gebracht werden. Der Argumentwert kann dem Quelltext nicht entnommen werden und ist »41«.
main.c
#include <stdio.h> /* printf */
#include <stdlib.h> /* rand */
#include <math.h> /* floor */int main( void )
{ printf
( "%g\n", floor( rand() ) ); }stdout
41
int-Parameter und double-Argument
Es ist ebenfalls möglich, einen double-Argumentausdruck für einen int-Parameter anzugeben. Dabei werden die Nachkommastellen des double-Wertes abgeschnitten.
Die Funktion des folgenden Beispiels hat einen int-Parameter, sie akzeptiert auch ein Argument vom Typ »double«.
- Dokumentation der Funktion »abs« (nach N1570, überarbeitet, vereinfacht und übersetzt)
- 7.22.6 Ganzzahlige arithmetische Funktion
- 7.22.6.1 Die Funktion »abs«
- Synopsis
#include <stdlib.h>
int abs( int j );- Ergebniswert
- Diese Funktion ergibt den Betrag ihres ganzzahligen Argumentwertes.
Der Betrag einer Zahl ist der Abstand dieser Zahl zu der Zahl 0. Der Betrag einer Zahl ist nie negativ. Beispielsweise ist der Betrag von »2« gleich »2« und der Betrag von »-2« ebenfalls gleich »2«. Der Betrag von »0« ist »0«.
- Betrag von -2 und +2 als Abstand von -2 beziehungsweise +2 zu 0
2 2
|<------------->|<------------->|...---[-3]-----[-2]-----[-1]-----0-----[+1]-----[+2]-----[+3]---...
Das folgende Programm zeigt den Aufruf der Betragsfunktion für int-Werte mit einem double-Wert. Der Wert »2.7« wird dabei zuerst in den Parametertyp »int« gewandelt, indem die Nachkommastellen abgeschnitten werden, dadurch ergibt sich der int-Wert »2«. Anschließend wird dann von der Funktion »abs« der Betrag von »2« berechnet und als Wert des Ausdrucks »abs( 2.7 )« festgelegt.
main.c
#include <stdio.h>
#include <stdlib.h>int main( void )
{ printf
( "%d\n", abs( 2.7 )); }stdout
2
Dies kann auch verwendet werden, um eine nicht zu große nicht-negative double-Zahl nach »int« zu wandeln.
Typerzwingung
Wenn ein int-Argument an der Stelle eines double-Parameter verwendet wird, oder umgekehrt, wird der Wert des Ausdrucks in einen entsprechenden Wert des Parametertyps gewandelt. Wir nennen dies auch eine Typerzwingung (type coercion /taɪpkoˈɚʃən/) (eine spezielle Form einer Typwandlung).
Parameter- und Argumenttypen
Die folgende Tabelle zeigt, welche Argumenttypen für bestimmte Parametertypen zulässig sind. Sie enthält dabei nur die bisher im Kurs schon vorgestellten Typen.
- Tabelle
Parametertyp erlaubter Argumenttyp
double double, int
int double, int
char * char *
Teilausdrücke und Hauptfunktionen
Unter einem Teilausdruck verstehen wird ab jetzt einen Operanden oder ein Argument.
Falls es in einem Ausdruck einen Aufruf gibt, der nicht in einem Teilausdruck vorkommt, so ist die damit aufgerufene Funktion die Hauptfunktion jenes Ausdrucks.
Beispielsweise ist in »floor( rand() )« der Ausdruck »rand()« ein Teilausdruck und »floor« die Hauptfunktion.
Weiteres Beispiel einer Funktionsdokumentation: »tolower«
- Druckbare Zeichen des ASCII -Codes (Das »m« hat die Kennzahl 109)
dezimal 111111111111111111111111111 · 100
33333333444444444455555555556666 66666677777777778888888888999999 9999000000000011111111112222222 · 10
23456789012345678901234567890123 45678901234567890123456789012345 6789012345678901234567890123456 · 1 !"#$%&'()*+,-./0123456789:;<=>? @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ `abcdefghijklmnopqrstuvwxyz{|}~- Dokumentation der Funktion »tolower« (nach N1570, überarbeitet, vereinfacht und übersetzt)
- 7.4.2 Character case mapping functions
- 7.4.2.1 Die Funktion »tolower«
- Synopse
#include <ctype.h>
int tolower( int c );- Ergebniswert
- Diese Funktion ergibt die Kennzahl des kleinen Buchstaben (der Minuskel), welcher zu dem großen Buchstaben (der Majuskel) gehört, dessen Kennzahl ihr als Argumentwert übergeben wurde.
Wenn das Argument die Kennzahl einer Majuskel (eines „großen Buchstabens“, wie „A“, „B“, oder „C“) ist, dann ist das Ergebnis der Funktion "tolower" die Kennzahl der entsprechenden Minuskel (eines „kleinen Buchstabens“, wie „a“, „b“, oder „c“).
Das folgende Beispielprogramm gibt den Wert dieser Funktion für das Schriftzeichen mit der Kennzahl »65« aus.
main.c
#include <stdio.h>
#include <ctype.h>int main( void )
{ printf
( "%d\n", tolower( 65 )); }stdout
97
Das Ergebnis ist 97 – die Kennzahl des kleinen A.
- Zeichentabelle
Zahl Zeichen Beschreibung
65 A Das große A (Majuskel)
97 a Das kleine A (Minuskel)
Die Ausgabe dieses Programms hängt allerdings von der C -Implementation ab, auf der es läuft. Auf einer C -Implementation mit einer anderen Zeichenkodierung als der Zeichenkodierung »ASCII« könnte der Wert »65« oder »97« für ein anderes Schriftzeichen stehen und die Ausgabe des Programms könnte dann auch anders sein.
Übungsfragen
? Ausdrücke lesen (0)
- Synopsen
#include <math.h>
double floor( double x );#include <stdlib.h>
int rand( void );
Welcher der folgenden Aufrufe ist nach »#include <stdlib.h>« und »#include <math.h>« erlaubt?
- »rand( 1 )«
- »rand( 1.0 )«
- »rand( "1.0" )«
- »floor( 1 )«
- »floor( 1.0 )«
- »floor( "1.0" )«
? Ausdrücke lesen (1)
- Dokumentation der Funktion »sqrt« (nach N1570, überarbeitet, vereinfacht und übersetzt)
- 7.4.2.1 Die Funktion »sqrt«
- Proklamation
#include <math.h>
double sqrt( double x );- Prosa
- Diese Funktion ergibt die nicht-negative Wurzel des Argumentwertes.
Können Sie – ohne ein C -Programm zu starten – den ungefähren Wert des folgenden Ausdrucks (nach »#include <math.h>«) vorhersagen?
- »sqrt( sqrt( 16 ))«
? Quelltext beurteilen
Ist das folgende Programm korrekt oder nicht? Begründen Sie Ihre Antwort!
main.c
#include <stdio.h>
#include <math.h>int main( void )
{ printf
( "%g\n", double floor( double x ) ); }
Hinweise zu Übungsaufgaben
- Allgemeine Hinweise zu Übungen in diesem Kurs
- A Ausdruckrahmen — Bis auf weiteres soll der Ausdruckrahmen weiterhin verwendet werden, es sollte dabei kein Bestandteil des Ausdruckrahmens verändert werden, außer um #include-Direktiven, die Umwandlungsspezifikation (wie beispielsweise »%d«) oder den auszugebenden Wert (hinter dem Komma) festzulegen.
- B Beispielprogramm — Oft kann ein vorangehendes Beispielprogramm als Ausgangspunkt einer Lösung dienen. Zuerst einmal sollte versucht werden, dies zu übersetzen und zu starten, um sicherzustellen, daß es auch fehlerfrei ist. Dann kann es oft schrittweise verändert werden, um zur Lösung einer Aufgabe zu gelangen.
- D Dokumentation — Die Dokumentation sollte nicht in das Programm kopiert werden!
- F Freiwilligkeit — Wer möchte, kann den Kurs auch lesen bzw. an ihm teilnehmen, ohne sich mit den Aufgaben zu beschäftigen.
- G Gruppenarbeit — Übungen können auch gemeinsam mit dem Sitznachbarn bearbeitet werden, wenn dies von beiden Teilnehmern gewünscht wird. Falls die Arbeitsgeschwindigkeit der beiden Teilnehmer aber so unterschiedlich ist, daß der eine nur zusieht, während der andere alles erledigt, ist es wahrscheinlich besser, wenn beide die Aufgaben getrennt voneinander bearbeiten.
- K Kleine Schritte — Nicht versuchen, ein Programm auf Anhieb vollständig richtig einzugeben, sondern vielmehr in kleinen Schritten arbeiten: Zunächst nur einen Teil der Lösung so programmieren, daß das Programm voraussichtlich übersetzt und gestartet werden kann. Dann prüfen, ob es auch wirklich übersetzt und gestartet werden kann und ob es auch das erwartete Verhalten zeigt. Falls nicht, entsprechend korrigieren. Erst danach den nächsten Schritt beginnen.
- L Lesen — Erst einmal die Aufgabenstellung langsam, vollständig und nötigenfalls wiederholt lesen, bis sichergestellt ist, daß verstanden wurde, was verlangt ist. Falls dazu nötig, Begriffe nachlesen. Oft sind Lösungen unvollständig oder falsch, weil die Aufgabenstellung nicht vollständig oder richtig wahrgenommen wurde. Das vollständige Verständnis der Aufgabenstellung ist oft schon die Hälfte des Aufwands bis zur Lösung.
- N Nachfragen — Falls die Aufgabenstellung unklar ist oder Probleme Sie an der Bearbeitung hindern, rufen Sie den Dozenten zu sich. Vielleicht kann er Ihnen helfen, ohne gleich schon die Lösung zu verraten.
- O Ohne Vorgriffe — Die Übungsaufgaben sind so gestaltet, daß sie mit dem bisher im Kurs Behandelten gelöst werden können. Wer schon Vorkenntnisse hat und deswegen Lösungsmöglichkeiten mit Mitteln sieht, die bisher im Kurs noch nicht behandelt wurden, sollte trotzdem versuchen, eine Lösung zu finden, welche sich auf die bisher behandelten Mittel beschränkt. (Nur, falls dies zu schwierig ist, kann auch die Vorkenntnisse zurückgegriffen werden, um wenigstens überhaupt eine Lösung zu haben.) Dies bezieht sich aber nur auf Operatoren sowie Datentypen und Arten von Anweisungen, aber nicht auf Teile der Bibliothek (wie Funktionen) oder für eine Aufgabe benötigtes Wissen über die Welt (wie die Höhe der Mehrwertsteuer) – diese sollten bei Bedarf recherchiert werden.
- P Papier — Die Lösungen vieler Aufgaben könn(t)en auch auf Papier geschrieben, ohne daß eine C -Entwicklungsumgebung benötigt wird. Allerdings hilft eine C -Entwicklungsumgebung dabei, Fehler zu finden.
- Q Quelltext — Falls der Dozent beurteilen soll, ob eine Lösung, bei der etwas programmiert werden soll, richtig ist, sollte der Quelltext und nicht die Ausgabe des Programms gezeigt werden, denn an Hand der Ausgabe eines Programms läßt sich meist nicht beurteilen, ob ein Programm eine richtige Lösung einer Aufgabenstellung ist.
- R Recherchen — Es darf bei der Bearbeitung einer Übung auch noch einmal etwas in diesem Kurs oder in Büchern nachgelesen oder im Web recherchiert werden. Einige Übungsfragen und Übungsaufgaben setzen sogar eigenständige Recherchen voraus. Wenn die Ausgabe eines Programms durch Lesen des Quelltexts vorhergesagt werden soll, dann sollte dieses Programm allerdings noch nicht gestartet werden – andere Recherchen sind dabei aber erlaubt.
- S Schwierigkeitsgrade — Es gibt im Kurs leichtere und schwierigere Aufgaben. Es ist normal, daß nicht immer jeder alle Aufgaben bewältigen kann.
- T Teil-Lösungen — Falls eine Aufgabe nicht bewältigt werden kann, sollte versucht werden, sich die Aufgabe zu vereinfachen, indem etwa eine bestimmte Anforderung ignoriert wird oder nur ein Teil der Aufgabe gelöst wird (in einer Prüfung würden Teillösungen auch schon einige Punkte bringen). Falls auch das nicht geht, könnte versucht werden wenigstens, eine andere, ähnliche selbstgestellte Aufgabe zu lösen.
Übungsaufgaben
/ Aufrufe schreiben
Diese Übungsaufgabe soll dabei helfen, das selbständige Schreiben von Aufrufen von Funktionen mit einem Parameter an Hand der Dokumentation üben.
Schreiben Sie ein Programm, welches das Ergebnis eines Aufrufs der Funktion »strerror« ausgibt.
Denken Sie daran, nichts aus der Dokumentation in das Programm zu kopieren!
- Dokumentation (nach N1570, überarbeitet und übersetzt)
- 7.24.6.2 Die Funktion »strerror«
- Synopse
#include <string.h>
char * strerror( int errnum );- Ergebniswert
- Diese Funktion ergibt den Text zu der als Argumentwert angegebenen Fehlernummer.
/ Mathematische Aufrufe schreiben
Berechnen Sie mit Hilfe von Funktionen zur Direktive »#include <math.h>«:
Schreiben Sie möglichst kurze Ausdrücke, die den folgenden sprachlichen Bezeichnungen entsprechen, ohne dabei den Wert des Ausdrucks schon selber im Kopf auszurechnen! Die Werte der Ausdrücke sollten den mathematischen Werten der vorgegebenen Terme möglichst nahe kommen. (Passende Funktionen können in der Dokumentation zur Direktive »#include <math.h>« gefunden werden.)
- Der Kosinus von Null
- Die Wurzel aus (3² + 4²)
- 1,5625, auf zwei Nachkommastellen gerundet
Reserveaufgaben
/ Aufrufe schreiben (1)
(Diese Reserveaufgabe wird erst nach der Nachbesprechung der ersten obenstehenden Aufgabe bearbeitet, falls diese Aufgabe noch nicht gelöst werden konnte.)
Schreiben Sie ein Programm, welches das Ergebnis eines Aufrufs der Funktion »ceil« (/sil/) ausgibt (welche Werte dabei genau verwendet werden, ist egal.)
- Dokumentation (nach N1570, überarbeitet und übersetzt)
- 7.12.9 Funktionen zur Ermittlung der naheliegendsten ganzen Zahl
- 7.12.9.1 Die Funktion »ceil«
- Synopse
#include <math.h>
double ceil( double x );- Ergebniswert
- Diese Funktion ergibt den kleinsten ganzzahligen Wert, der nicht kleiner als der Argumentwert ist.
/ Aufrufe schreiben (2)
(Diese Reserveaufgabe wird erst nach der Nachbesprechung der ersten obenstehenden Aufgabe bearbeitet, falls diese Aufgabe noch nicht gelöst werden konnte.)
Schreiben Sie ein Programm, welches das Ergebnis eines Aufrufs der Funktion »round« ausgibt (welche Werte dabei genau verwendet werden, ist egal.)
- Dokumentation (nach N1570, überarbeitet, vereinfacht und übersetzt)
- 7.12.9.6 Die Funktion »round«
- Synopse
#include <math.h>
double round( double x );- Ergebniswert
- Diese Funktion ergibt den gerundete Wert zu dem Argumentwert (den nächstliegenden ganzzahligen Wert, dargestellt als Wert vom Typ »double«).