Kapitel elf - Mehr über Typen und Variablen

Globale Variablen, Typdefinitionen, Aufzählungen und Strukturen

In diesem Kapitel werden einige der fortgeschritteneren Themen zur Verwendung von Variablen und Typen behandelt, einschließlich des Unterschieds zwischen lokalen und globalen Variablen, der Definition neuer Typen und der Verwendung von Aufzählungen und Datenstrukturen.

Wenn wir in den Beispielen in diesem Buch Variablen verwendet haben, werden diese immer in Funktionsdefinitionen eingefügt. Dies sind daher lokale Variablen. Das heißt, Variablen, die für diese Funktionen lokal sind und außerhalb der Funktion keine Bedeutung haben.

Globale Variablen

C erlaubt auch globale Variablen. Das heißt, Variablen, die außerhalb aller Funktionen definiert sind. Diese haben einen globalen Geltungsbereich, d.h. sie können von jeder Funktion innerhalb des Programms aus gelesen und geschrieben werden. Schauen wir uns ein Beispiel an:

#include <stdio.h> int result; void add (int a, int b) { result = a + b; } void main (void) { add (3, 4); printf ("Das Ergebnis ist %d\n", result); }

In diesem Beispiel ist die Variable result global. Sie kann daher sowohl in der add Funktion als auch in der main Funktion gelesen oder geschrieben werden. Wie Sie sehen, schreiben wir einen Wert in add und lesen ihn in main. Daher müssen wir keinen Wert aus add zurückgeben.

[VERSCHIEDENE NAMEN VERWENDEN] Es ist zwar durchaus gültig, einer lokalen Variablen denselben Namen wie einer globalen Variablen im selben Programm zu geben, aber tun Sie es nicht! Wenn Sie eine globale und eine lokale Version mit dem selben Namen haben, wird die lokale Version in der Funktion verwendet, in der sie deklariert ist, und die globale Version wird überall verwendet. Dies kann zu unerwartetem Verhalten führen.

In mancher Hinsicht sieht das doch einfacher aus, als überall Werte weiterzugeben, oder? Warum tun wir das also nicht einfach die ganze Zeit? Die Antwort ist Speicher. Lokalen Variablen in Funktionen wird vorübergehend Speicherplatz zugewiesen, während die Funktion ausgeführt wird, und der Speicher wird freigegeben, sobald die Funktion endet. Globalen Variablen wird jedoch beim Programmstart Speicherplatz zugewiesen, und dieser Speicherplatz wird erst freigegeben, wenn das Programm endet. Wenn Sie genug davon zuweisen, kann auf einigen Systemen der Speicher ausgehen.

Es gibt eine bessere Möglichkeit, jeder Funktion viele Daten zur Verfügung zu stellen, auf die wir später noch eingehen werden …

Typdefinitionen

In einem früheren Kapitel haben wir uns den Bereich der Variablentypen in C angesehen: char, int, float usw. Mit C können Sie auch Ihre eigenen Typen definieren, die als typedef bezeichnet werden. Ein typedef ist eine Zeile im Format typedef <vorhandener Typ> <neuer Name>, die normalerweise am Anfang eines Programms steht.
Beispielsweise:

typedef unsigned char BYTE;

Dies definiert einen neuen Typ namens BYTE, der ein anderer Name für ein vorzeichenloses Zeichen ist. Beachten Sie, dass benutzerdefinierte Typen üblicherweise in Großbuchstaben benannt werden. Dies ist nicht obligatorisch, hilft jedoch beim Lesen des Codes, sie von Variablen zu unterscheiden.

Wenn wir sagen, dass dies einen neuen Typ definiert, wird tatsächlich ein Alias für einen vorhandenen Typ erstellt. Dies scheint ein bisschen sinnlos, aber es kann auf zwei Arten helfen. Erstens kann es deutlicher machen, was Ihr Code tut, wenn Sie die Typnamen spezifisch für die Daten Ihres Programms festlegen. Zweitens können Sie durch Definieren bestimmter Typen vom Compiler gewarnt werden, wenn Sie den falschen Typ für ein Funktionsargument oder eine Variable verwenden.

Es gibt einige spezielle Fälle, in denen typedefs besonders nützlich sind. Dies sind aufgezählte Typen und Datenstrukturen.

Spezifizierte Typen

Oft wird eine Variable verwendet, die nur einen von wenigen möglichen Werten annehmen kann. C stellt zu diesem Zweck einen Typ namens enum bereit, der eine Ganzzahl mit einem festen Satz benannter Werte definiert. Hier ein Beispiel:

#include <stdio.h> typedef enum { false, true } BOOLEAN; void main (void) { BOOLEAN b_var; b_var = false; if (b_var == true) { printf ("TRUE\n"); } else { printf ("FALSE\n"); } }

Wie Sie sehen können, werden die benannten Werte des Aufzählungstyps anstelle von Zahlen für Zuweisungen und Vergleiche verwendet. Dies kann das Verständnis von Code erheblich erleichtern und ist eine sehr gute Möglichkeit, Fehler zu vermeiden, da eine aufgezählte Variable immer nur auf einen gültigen Wert gesetzt werden kann.

[NUMMERIERTE ENUMS] Wenn Sie eine Aufzählung erstellen, weist der Compiler jedem der möglichen Werte einen numerischen Wert zu. Standardmäßig wird der erste in der Liste als 0 nummeriert und von dort aus hochgezählt. Sie können dies überschreiben, indem Sie nach jedem benannten Wert ein Gleichheitszeichen setzen und es auf den gewünschten Wert setzen.

Strukturen

Das andere wirklich nützliche, was Sie mit einem typedef tun können, ist es, damit eine Datenstruktur zu definieren. Dies ist eine Sammlung einzelner Variablen, die zusammen gruppiert sind, sodass Sie die Struktur zwischen Funktionen und nicht zwischen den einzelnen Variablen übergeben können.

Hier ein Beispiel:

#include <stdio.h> typedef struct { int inval1; int inval2; int outval; } MY_DATA; void add (MY_DATA *d) { d->outval = d->inval1 + d->inval2; } void main (void) { MY_DATA data; data.inval1 = 5; data.inval2 = 7; add (&data); printf ("Die Summe von %d und %d ist %d\n", data.inval1, data.inval2, data.outval); }

Hier verwenden wir ein typedef, um einen Datentyp namens MY_DATA zu erstellen. Die Definition der Struktur besteht aus dem Schlüsselwort struct mit einer Liste von Variablen in geschweiften Klammern. In diesem Fall besteht die Struktur aus drei ganzzahligen Variablen.

In der Hauptfunktion deklarieren wir eine Instanz der Struktur als Variable namens data vom Typ MY_DATA. Wir greifen dann auf die einzelnen Elemente der Struktur zu, indem wir den Namen der Strukturvariablen (data), einen Punkt (.) und den Namen des spezifischen Elements angeben. Die Zeile data.inval1 = 5 setzt also den Wert des Elements inval1 von data auf 5 und so weiter.

Die Funktion add verwendet als einziges Argument einen Pointer auf eine MY_DATA Struktur. Wie immer kann eine Funktion die Werte ihrer Argumente nicht ändern, aber sie kann die Werte ändern, auf die ihre Argumente zeigen, sodass wir einen Pointer anstelle der Struktur selbst übergeben.

[. VS ->] Stellen Sie beim Zugriff auf die Elemente einer Struktur sicher, dass Sie das richtige Symbol verwenden. Ein . wird verwendet, wenn Ihre Variable eine Instanz der Struktur selbst ist. a-> wird verwendet, wenn Ihre Variable ein Pointer auf eine Instanz der Struktur ist. Wenn Sie das falsche verwenden, wird normalerweise ein Fehler vom Compiler ausgegeben.

Um von einem Pointer auf die Elemente einer Struktur zuzugreifen, ersetzen wir den Punkt durch einen Pfeil, der aus einem Minuszeichen und einem Größer-als Zeichen (->) besteht. Die add-Funktion liest also die Werte von inval1 und inval2 in der Struktur, auf die d zeigt, und schreibt das Ergebnis dann in derselben Struktur nach outval zurück. Die Hauptfunktion druckt dann das Ergebnis aus der Struktur.

Strukturen sind sehr nützlich, wenn Sie viele Daten zwischen Funktionen weitergeben müssen. Sie können viel speichereffizienter sein als eine große Anzahl globaler Variablen, da Sie die Struktur nur nach Bedarf erstellen müssen, anstatt ständig Speicherplatz zu beanspruchen.

Zurück zum Inhalt Vorige Seite Nächste Seite