C-Entwicklung unter Linux - Funktionen - V.
Einführung
Die C-Standardbibliothek bietet eine Vielzahl von Funktionen für viele übliche Aufgaben. Es gibt auch viele Bibliotheken für zusätzliche Funktionen, wie das GUI-Design (GTK +) oder die Datenbankschnittstelle (libpq). Wenn Sie jedoch in der C-Programmierwelt vorankommen, werden Sie bald feststellen, dass Sie dieselben Anweisungen immer wieder in derselben Reihenfolge wiederholen, was zeitaufwändig und ineffizient wird. Sie können also einfach alle diese Anweisungen in eine Funktion einbinden und diese Funktion bei Bedarf aufrufen . Folgendes lernen Sie, wenn Sie diesen Artikel lesen, sowie einige nützliche Tipps, die Ihnen das Leben erleichtern.
Erstellen Sie Ihre Funktionen
Angenommen, Sie möchten einen Taschenrechner schreiben. Wir werden uns nicht auf die Benutzeroberfläche konzentrieren (GUI vs curses vs slang vs CLI), da wir uns für die Interna interessieren. Es wäre umständlich, nicht für jede Operation, die Sie unterstützen möchten , eine Funktion zu erstellen, es sei denn, es gibt bereits eine Funktion wie pow (), die in math.h definiert ist und das Ergebnis einer Basis zurückgibt, die auf eine Potenz angehoben wurde. Zum Beispiel haben Sie zum Hinzufügen eine Funktion namens add (), die zumindest vorerst zwei Argumente akzeptiert und das Ergebnis zurückgibt . Wenn der Benutzer die von ihm eingegebenen Nummern hinzufügt, rufen Sie einfach andie Funktion mit den vom Benutzer eingegebenen Nummern und Sie brauchen sich um nichts anderes zu kümmern. Diese drei Begriffe, die ich kursiv geschrieben habe, sind für das Verständnis von Funktionen von wesentlicher Bedeutung. Eine Funktion nimmt normalerweise (aber nicht immer) etwas, führt eine Reihe von Operationen an diesem etwas aus und spuckt das Ergebnis aus. "Nicht immer", da main (), wie Sie zuvor sehen konnten, ohne Argumente aufgerufen werden kann, und es gibt auch andere Beispiele. Aber jetzt konzentrieren wir uns auf unsere Beispiele. Die Zahlen, die addiert werden müssen, sind die Argumente, dass "etwas" Sie die Funktion für die Verarbeitung geben. Der Verarbeitungsteil befindet sich im Hauptteil der Funktion, wenn Sie ihn anweisen, die Zahlen zu addieren. Danach wird der Teil "Ausspucken" als Rückgabe eines Wertes bezeichnet, der in unserem Fall das Ergebnis der Addition ist.
Mal sehen, worüber wir in einem praktischen Beispiel gesprochen haben:
#include /* this contains the definition of printf()*/ double add(double x, double y); int main() { float first, second; printf("Please enter the first number.\n"); scanf("%F",&first); printf("Please enter the second number.\n"); scanf("%F",&second); double add(double a, double b) { return a + b; } printf("The result of the addition is %F\n", add(first, second)); return 0; }
Der obige Code ist zwar bestenfalls simpel, hilft uns jedoch, genau darauf hinzuweisen, worüber wir zuvor gesprochen haben. Zuerst deklarieren wir die Funktion vor main (), und der Zweck besteht darin, den Namen, den Typ der Argumente und den Typ zu kennen, den die Funktion zurückgibt. Diese Zeile wird auch als Definition des Funktionsprototyps bezeichnet. Wie Sie sehen können, müssen die Namen der Argumente aus der Deklaration nicht mit den in der Definition verwendeten übereinstimmen. Wenn Sie dies jedoch stört, verwenden Sie ein konstantes Namensschema. Bevor wir die Funktion verwenden, müssen wir sie definieren, um der Welt zu sagen, was genau sie tut. Auch wenn der Körper der Funktion wie in unserem Beispiel einzeilig ist, verwenden Sie am besten Klammern, um die Lesbarkeit und die Gewohnheit zu verbessern. Hier gibt die Funktion lediglich das Ergebnis der Addition zwischen zwei Zahlen zurück.
Wir empfehlen Ihnen, Namen für Funktionen, Argumente und gewöhnliche Variablen oder Konstanten zu verwenden, die widerspiegeln, was sie tun, wiederum aus Gewohnheit und um den Programmierern, die Ihren Code lesen, die Versuche zu ersparen, zu erraten, welche Variable "xyzgth" tut oder wofür sie verwendet wird. Außerdem nutzen Kommentare . Auch wenn Kommentare im obigen Code übertrieben erscheinen, sind sie es nicht. Wenn Sie sich den Code zwei Monate später ansehen, haben Sie keine Ahnung, woran Sie gedacht haben, als Sie den Code geschrieben haben. Verwenden und missbrauchen Sie Kommentare, sie werden Sie retten, vertrauen Sie mir.
Übung
Es gibt Funktionen, die eine variable Anzahl von Argumenten akzeptieren können, wie z. B. printf (). Sie dürfen Google verwenden, um zu sehen, was sie tun, und versuchen, die Funktion add () neu zu schreiben, um mehr als zwei Argumente zu akzeptieren, oder eine andere Funktion zu erstellen. Sie können auch "man 3 printf" verwenden.
Wir haben Ihnen bereits gesagt, dass main () ohne Argumente aufgerufen werden kann. Das heißt natürlich, dass es auch mit Argumenten aufgerufen werden kann. Wann ist das sinnvoll? In einfachen Programmen wie unserem sind die Klammern von main () leer, da wir sie ohne Argumente aufrufen. Wenn Ihre Programme jedoch komplexer werden, insbesondere wenn sie befehlszeilenorientiert sind, müssen Sie die Funktionalität von Argumenten hinzufügen, z. B. das Flag -v von gcc, mit dem die Version gedruckt wird. Wenn eine solche Funktionalität gewünscht wird, muss main () Argumente haben, zwei, um genau zu sein. Die Hauptfunktion wird
int main(int argc, char **argv) { .... }
Bevor Sie über die kryptischen Namen und die doppelten Sternchen ausflippen, warten Sie, bis Sie die Erklärung erhalten, die eigentlich einfach ist. Das erste Argument ist eine Ganzzahl namens argc, und der Name stammt von "ARGument Count". Ein bisschen besser, oder? Über das zweite Argument ... nun, der Name steht offiziell für "ARGument Vector" und ist ein Zeiger auf einen Zeiger auf ein Zeichen. Während argc auf Englisch die Anzahl der Argumente speichert, speichert argv die Argumente als eine Reihe von Zeichenfolgen. Der Teil "Zeiger auf ..." wird im nächsten Teil des Artikels erläutert. Im Moment müssen Sie lediglich wissen, dass der Index Null von argv lautet, wenn der Benutzer beispielsweise drei Argumente für das Programm eingibt Der Name des Programms selbst, Index 1 speichert das erste Argument für das Programm und so weiter.Auf diese Weise können Sie mit einem Schalter / Fall nach den Argumenten suchen, die an Ihre Programme übergeben wurden. Bevor wir Ihnen ein kurzes Beispiel geben, müssen wir Ihnen sagen, dass main zwei Argumente hat, wie sie im Standard definiert sind, und so wird es auf den meisten Linux- und Unix-Systemen verwendet. Wenn Sie jedoch unter Windows oder Darwin arbeiten, wird main () ein oder zwei weitere Argumente haben, die jedoch systemabhängig sind und daher vom Standard nicht definiert oder verlangt werden. "Char ** argv" kann auch als "char * argv []" geschrieben werden. Sie sehen beide, je nach Präferenz des Entwicklers.Wenn Sie unter Windows oder Darwin arbeiten, hat main () ein oder zwei weitere Argumente, die jedoch systemabhängig sind und daher vom Standard nicht definiert oder verlangt werden. "Char ** argv" kann auch als "char * argv []" geschrieben werden. Sie sehen beide, je nach Präferenz des Entwicklers.Wenn Sie unter Windows oder Darwin arbeiten, hat main () ein oder zwei weitere Argumente, die jedoch systemabhängig sind und daher vom Standard nicht definiert oder verlangt werden. "Char ** argv" kann auch als "char * argv []" geschrieben werden. Sie sehen beide, je nach Präferenz des Entwicklers.
Sie werden sich vielleicht erinnern, dass wir Ihnen im ersten Teil unserer Serie erzählt haben, wie wir das Yest-Programm von Kimball Hawkins als Beispiel verwenden werden. Es ist Zeit, dass wir anfangen. So gehen Sie mit einem Teil der möglichen Benutzereingaben um:
if ( strncmp( argv[i], "--help", 6 ) == 0 || strncmp( argv[i], "-?", 2 ) == 0 || strncmp( argv[i], "?", 1 ) == 0 || strncmp( argv[i], "help", 4 ) == 0 ) yest_help(); /* help requested, display it */ if ( strncmp( argv[i], "--version", 9 ) == 0 || strncmp( argv[i], "--license", 9 ) == 0 ) yest_version(); /* version/license information requested */
Sie können in diesem Code sehen, wie Kimball seinen Code kommentiert, obwohl der Name der Funktionen, die er aufruft - yest_help () und yest_version () - ziemlich selbsterklärend sind. Die Standardfunktion strncmp () in string.h vergleicht zwei Zeichenfolgen, in unserem Fall argv [i] und "help", aber nur die ersten x Zeichen (4 in der Zeile "help") und Gibt Null zurück, wenn die erste Zeichenfolge mit der zweiten übereinstimmt.
Übung
Wie würden Sie mit switch / case prüfen, ob das erste Argument "--help" und das zweite "--version" ist? Können diese Optionen zusammen verwendet werden? Wie würde sich der Code unterscheiden?
Dinge, die Sie beachten sollten
Mit C können Sie keine Funktion innerhalb einer anderen definieren, mit der Ausnahme main (), die, wie wir sehen können, etwas Besonderes ist. Beachten Sie auch, dass das, was Sie in einer Funktion definieren, nur in einer Funktion "lebt". Sie können also eine Variable mit dem Namen "a" in drei verschiedenen Funktionen ohne Probleme definieren lassen. Dies kann jedoch zu Problemen in größeren Programmen führen. Wir empfehlen sie daher nicht.
Benutzerdefinierte Header-Dateien
Da Ihre Programme immer größer werden, müssen Sie sie aufteilen. Sie können mehr als eine Quelldatei haben, aber Sie können auch Ihre eigenen Header schreiben. Wenn Sie also zu unserem Additionsprogramm zurückkehren, können Sie einen Header mit dem Namen Operations.h erstellen, der die Zeile "double add (double x, double y);" enthält, sodass Ihr Programm nur die Definition behandelt, den Teil, in dem Sie sagen das add () gibt a + b zurück. Das Einfügen Ihres benutzerdefinierten Headers erfolgt genauso wie das Einfügen von vom System installierten Headern, mit einer wichtigen Ausnahme: Denken Sie daran, doppelte Anführungszeichen anstelle von spitzen Klammern zu verwenden, wie folgt: "#include" operation.h "". Dieser Header kann in dem Verzeichnis abgelegt werden, in dem die anderen Quelldateien gespeichert sind, oder in einem anderen Pfad, der als Argument für gcc angegeben wird, damit er weiß, wo er suchen muss.Header-Dateien können auch Konstantendefinitionen (mit #define) oder andere Deklarationen enthalten, sofern Sie wissen, dass sie in jeder Quelldatei des Programms verwendet werden. Es ist nicht obligatorisch, es ist nur eine gute Praxis. Wie würden Sie also einen Taschenrechner schreiben, der sich nur mit den grundlegenden arithmetischen Operationen befasst und Überschriften verwendet?
Rekursive Funktionen
Da wir erwarten, dass Sie Programmierkenntnisse haben, sind wir sicher, dass Sie wissen, was rekursive Funktionen sind und wie / wann Sie sie verwenden sollen. Aus diesem Grund ist dieses Unterkapitel kürzer als normalerweise. Kurz gesagt, man sagt über eine Funktion, die rekursiv sein soll, wenn sie sich selbst aufruft. Obwohl das Konzept für neue Programmierer entmutigend sein mag, kann eine einfachere, realistische Rekursion erklärt werden: Versuchen Sie, zwischen zwei Spiegeln zu sitzen, die sich gegenüberstehen. Der Effekt, den Sie sehen, ist eine visuelle Darstellung der Rekursion. Wir geben Ihnen jedoch ein kurzes Beispiel, damit Sie besser verstehen, wann und wie Sie es verwenden. Sie erinnern sich wahrscheinlich an die Schule, als Sie über Fakultäten unterrichtet wurden. Eine Fakultät ist das Produkt aller ganzen Zahlen, die kleiner oder gleich sind, solange sie größer als Null sind. Die Notation dafür ist ein Ausrufezeichen, also 6!= 6 * 5 * 4 * 3 * 2 * 1 = 720. Wie können wir dies in C am effizientesten tun? Natürlich mit Rekursion.
int factorial(int number) { if(number <= 1) return 1; else return number * factorial(number-1) }
Fazit
Wir empfehlen, dass Sie Funktionen so oft wie möglich verwenden und ihre Prototypen so oft in Header-Dateien ablegen, da Ihr Code besser organisiert ist und Ihre Arbeit einfacher wird. Apropos Header, wir überlassen es Ihnen als letzte Übung, die Header-Datei zu lesen, in der mathematische Operationen (math.h) definiert sind, um eine Vorstellung davon zu bekommen, wie sie aussieht und was sie enthält. Verwenden Sie es dann, um den Rechner mit einigen verbesserten Funktionen zu verbessern, die über die Grundlagen hinausgehen.
Folgendes können Sie als Nächstes erwarten:
- I. C-Entwicklung unter Linux - Einführung
- II. Vergleich zwischen C und anderen Programmiersprachen
- III. Typen, Operatoren, Variablen
- IV. Ablaufsteuerung
- V. Funktionen
- VI. Zeiger und Arrays
- VII. Strukturen
- VIII. Grundlegende E / A.
- IX. Codierungsstil und Empfehlungen
- X. Erstellen eines Programms
- XI. Verpackung für Debian und Fedora
- XII. Ein Paket in den offiziellen Debian-Repositories erhalten