3. Variablen
  In unserem ersten Programm im Kapitel Einführung sind a,
  b und summe veränderliche Daten und
  heißen Variablen. Sie sind Objekte eines vordefinierten Grunddatentyps für
  ganze Zahlen (int, Kurzform für integer).
  Der Begriff "Variable" wird für ein veränderliches Objekt gebraucht.
  Dabei bestehen Variablen im Wesentlichen aus zwei Teilen: Aus einem Wert
  und aus einer Adresse, an der der Wert gespeichert wird. Zusätzlich
  haben Variablen einen Datentyp und können (müssen aber nicht!)
  einen Namen haben.
  
3.1. Deklaration von Variablen
  Variablen müssen deklariert werden. Die Zeile
  int summe, a, b;
  ist eine Deklaration. Unter Deklaration wird verstanden, dass der Variablenname dem
  Compiler bekannt gemacht wird. Wenn dieser Name später im Programm versehentlich
  falsch geschrieben wird, kennt der Compiler den Namen nicht und gibt eine Fehlermeldung
  aus. Damit dienen Deklarationen der Programmsicherheit.
  
3.2. Definition von Variablen
  Damit Variablen benutzt werden können, müssen sie auch definiert werden. Die
  gleiche Zeile wie oben
  int summe, a, b;
  ist auch gleichzeitig eine Definition der drei Variablen. Unter Definition wird
  verstanden, dass für die Variablen ein Speicherbereich reserviert wird. Variablen
  belegen damit Bereiche im Arbeitsspeicher des Computers, deren Inhalte während des
  Programmlaufs verändert werden können. Die Variablennamen sind also symbolische
  Adressen, unter denen der Wert gefunden wird und über die auf den Inhalt, also auf
  den Wert zugegriffen werden kann.
  Deklaration und Definition werden unterschieden, weil es auch Deklarationen ohne
  gleichzeitige Definition geben kann, doch davon später mehr (im Kapitel
  Funktionen). Zunächst sind die Deklarationen zugleich Definitionen.
  Wenn beispielsweise für a eine 100 und für b
  eine 2 eingegeben wird, sieht der Speicher nach dem Programmlauf wie folgt aus. Dabei sind die
  Adressen willkürlich gewählt.
  
| Adresse | Variablenname | Inhalt | 
| 10120 | 0 | |
| 10124 | 17 | |
| 10128 | a | 100 | 
| 10132 | b | 2 | 
| 10136 | summe | 102 | 
| 10140 | 4009 | 
  Wichtig: Vor C99 mussten Variablen immer am Anfang einer Funktion deklariert und definiert
  werden.
  
3.3. Initialisierung von Variablen
  Variablen haben nach der Definition einen beliebigen Wert (je nachdem, was vorher in dieser
  Speicherzelle stand). Sie können vor der Benutzung initialisiert werden, d.h.
  sie erhalten einen definierten Anfangswert. Dies geschieht grundsätzlich bei der
  Definition der Variablen.
  Beispiel:
  Definition der Variablen a, b, c
  mit gleichzeitiger Initialisierung der Variablen a und b
  auf die Werte 2 bzw. 3. Auch die Variable c wird initialisiert mit dem
  Ergebnis der Rechenoperation a + b.
  int a = 2, b = 3, c = a + b;
  Von der Ausführung her ist dies auf den ersten Blick dasselbe wie die folgenden Zeilen:
  
  int a, b, c;
  a = 2;
  b = 3;
  c = a + b;
  Im letzten Fall werden die Variablen a, b und
  c aber nicht initialisiert, sondern die Werte werden den Variablen
  zugewiesen! Eine Zuweisung ist also keine Initialisierung und umgekehrt, obwohl in beiden
  Fällen das Gleichheitszeichen als Operator verwendet wird.
  Eine Initialisierung kann nur bei der gleichzeitigen Definition (also der Erzeugung)
  einer Variablen auftreten, eine Zuweisung setzt immer ein schon vorhandenes Objekt
  voraus!
  Werden dagegen die Variablen a und b nicht
  initialisiert, ist das Ergebnis von c nicht vorhersehbar. Im allgemeinen
  geben die Compiler dabei eine Warnung aus, dass nicht initialisierte Variablen im Programm
  verwendet werden.
  
3.4. Unveränderliche Variablen und Konstanten
  Eine unveränderliche Variable wird mit dem Schlüsselwort
  const (wird daher auch häufig fälschlicherweise als Konstante
  bezeichnet) definiert. Dieses Schlüsselwort gibt es erst seit dem C89-Standard.
  Unveränderliche Variablen müssen bei der Definition sofort initialisiert werden.
  Denn zu einem späteren Zeitpunkt darf die unveränderliche Variable nicht mehr
  verändert werden - weder per Zuweisung noch durch Inkrementator oder Dekrementator.
  Der Compiler prüft dies, um sicherzustellen, dass der Programmierer nicht ausversehens
  eine unveränderliche Variable ändert. Einige Compiler - wie z.B. gcc - geben
  allerdings nur eine Warnung aus.
  Das Schlüsselwort const kann dabei wahlweise vor oder nach dem
  Datentypen geschrieben werden. Während  die Schreibweise mit const
  vor dem Datentypen häufig zu sehen ist, wäre die andere Schreibweise deutlich besser
  für die Lesbarkeit des Programms.
  Beispiel:
  
  const int a = 37;
  int const b = 25;
  a = 5;   /* Fehler! */
  b++;     /* Fehler! */
  Konstanten werden z.B. durch den Präprozessor-Befehl #define
  (siehe Kapitel Präprozessor-Befehle) definiert. Konstante haben nur einen Namen
  und einen Wert; anders als (unveränderliche) Variablen, die zusätzlich noch eine
  Adresse (einen Speicherort) haben, und anders als Literale, die nur einen Wert haben.
  Desweiteren sind die Namen von Arrays und Funktionen auch Konstanten, denn ihre Werte geben an, an
  welcher Adresse das Array bzw. die Funktion steht, aber sie haben selber keine Adresse.
  
3.5. Ausdrücke und Werte
  Ein Ausdruck ist eine syntaktische Größe - z.B. eine Variable oder ein Literal.
  Ein Wert ist eine semantische Größe, die während der Programmausführung
  ermittelt oder berechnet wird.
  Werte werden immer durch Ausdrücke beschrieben oder anders herum gesagt: Ein Ausdruck
  bezeichnet einen Wert (der unter Umständen erst errechnet werden muss).
  
3.6. L-Werte und R-Werte
  Jede Variable besitzt einen L-Wert und einen R-Wert. Dabei ist die Adresse der
  Variablen der L-Wert und der Wert der Variable der R-Wert. Die Buchstaben L und R stehen
  für Links und Rechts und sind relativ zum Zuweisungsoperator zu verstehen. Ein L-Wert
  steht demnach immer links und ein R-Wert immer rechts vom Zuweisungsoperator.
  Beispiel:
  
  int Zahl1 = 1, Zahl2 = 2;
  Zahl1 = Zahl2;
  Bei dieser Zuweisung wird der Wert der Variablen Zahl2 (also der R-Wert)
  an der Adresse der Variablen Zahl1 (also der L-Wert) gespeichert.
  Ausdrücke, die L-Werte beschreiben, werden L-Ausdrücke und
  Ausdrücke, die R-Werte beschreiben, werden R-Ausdrücke genannt.
  Zum Beispiel ist der Name einer Variablen ein L-Ausdruck, während ein Literal ein
  R-Ausdruck ist.
  Ein L-Ausdruck ist dabei mehr als ein R-Ausdruck, denn ein L-Ausdruck beinhaltet L- und R-Werte,
  während R-Ausdrücke nur R-Werte liefern können. Ein L-Ausdruck liefert
  automatisch immer dann einen L-Wert, wenn er links vom Zuweisungsoperator steht, und immer dann
  einen R-Wert, wenn er rechts vom Zuweisungsoperator steht. Im obigen Beispiel sind beide
  Variablen Zahl1 und Zahl2 L-Ausdrücke. Die Variable
  Zahl1 steht links vom Gleichheitszeichen, daher wird hier der L-Wert
  verwendet; die Variable Zahl2 steht aber rechts vom Gleichheitszeichen,
  daher wird hier der R-Wert verwendet.
  R-Ausdrücke sind vor allem Literale, Ausdrücke, die sich mit Operatoren zusammensetzen
  (außer der verkürzten if-Abfrage ?:
  (siehe Kapitel Kontrollstrukturen) und dem Variablen-Operator (siehe Kapitel
  Zeiger), sowie Funktionsaufrufe.
  Achtung:
  Der Name einer jeden Variablen ist wohl ein L-Ausdruck, aber nicht jeder Name von Variablen
  darf links vom Zuweisungsoperator stehen: Unveränderlichen Variablen (z.B.
  const int u;) dürfen keine Werte zugewiesen werden. Trotzdem sind
  die Namen von unveränderlichen Variablen L-Ausdrücke, da auch unveränderliche
  Variablen eine Adresse (L-Wert) und einen Wert (R-Wert) haben.
  
3.7. Gültigkeitsbereich
  Der Gültigkeitsbereich (engl. scope) ist der Bereich im C-Quelltext, in dem
  eine deklarierte Variable sichtbar bzw. bekannt ist. Es wird zwischen folgenden
  Gültigkeitsbereichen unterschieden (weitere Gültigkeitsbereiche werden im Laufe des
  Skriptes vorgestellt):
  Globale Variablen werden außerhalb von Funktionen - also auch außerhalb der
  main-Funktion - deklariert (Top Level). Sie sind vom Deklarationspunkt
  (siehe Abschnitt Deklarationspunkt) bis zum Ende des C-Quelltextes bekannt.
  Lokale Variablen (manchmal auch Block-Variablen genannt) werden innerhalb von Funktionen
  bzw. innerhalb eines Blockes deklariert. Sie sind vom Deklarationspunkt bis zum Ende der Funktion
  bzw. des Blockes bekannt.
  Beispiel:
   kap03_01.c
  kap03_01.c
  
  01 int Global;        /* globale Variable */
  02 
  03 int main()
  04 {
  05    int Lokal;      /* lokale Variable
  06                       innerhalb von main*/
  07    {
  08       int Block;   /* lokale Variable
  09                       innerhalb des Blocks */
  10       Block = 9;
  11    } /* Ende des Gültigkeitsbereiches
  12         für die Variable Block! */
  13 
  14    Lokal = 5;
  15    Global = 7;
  16    Block = 3;      /* Fehler! */
  17 
  18    return 0;
  19 } /* Ende des Gültigkeitsbereiches
  20      für die Variable Lokal! */
  21 
  22 /* Ende des Gültigkeitsbereiches
  23    für die Variable Global! */
  
  Damit dieses Programm ohne Fehler compiliert werden kann, muss die Zeile 16 auskommentiert werden!
  
3.8. Deklarationspunkt
  Eine Variable kann im Normalfall immer erst dann verwendet werden, wenn sie komplett deklariert
  ist. Um festzulegen, wann eine Variable komplett deklariert ist, wird ein sogenannter Deklarationspunkt
  definiert: Eine Variable ist komplett deklariert nach dem letzten Token des Variablennamens. Danach - also
  auch innerhalb der gleichen Zeile - kann die Variable verwendet werden.
  Beispiel:
  
  int intsize = sizeof(intsize);
  /*         ^
     Deklarationspunkt
  */
  In diesem Beispiel kann die Variable intsize mit ihrer eigenen Größe
  initialisiert werden, da die Initialisierung hinter dem Deklarationspunkt liegt.
  
3.9. Sichtbarkeit
  Eine Deklaration einer Variable ist überall innerhalb seines Gültigkeitsbereiches
  sichtbar. Die Sichtbarkeit kann aber durch eine Deklaration einer weiteren, gleichnamigen
  Variable überlappen, so dass die erste Variable nicht mehr sichtbar ist; sie ist
  sozusagen versteckt. Voraussetzung ist, dass die zweite Variable innerhalb eines Blocks
  deklariert wird, der im Gültigkeitsbereich der ersten Variable liegt.
  Beispiel:
  
  int Var;        /* globale Variable */
  int main()
  {
     float Var;   /* damit wird die obige
                     Variable "versteckt" */
     ...
  }
  Eine Variable ist immer erst ab der Stelle gültig, an der sie deklariert wird - und nicht
  ab Beginn des Blockes, in dem sie deklariert ist. Dadurch kann es - wie im folgenden Beispiel -
  zu Situationen kommen, in denen innerhalb eines Blockes gleichnamige Variablen auf
  unterschiedliche Deklarationen zurückzuführen sind. Nach Standard-C ist dies
  durchaus korrekt, aber die Verwendung gleichnamiger Variablen innerhalb eines Blockes ist ein
  schlechter Programmierstil!
  Beispiel:
   kap03_02.c
  kap03_02.c
  
  01 #include <stdio.h>
  02 
  03 int Var;        /* globale Variable */
  04 
  05 int main()
  06 {
  07    Var = 1;     /* gemeint ist die
  08                    globale Variable */
  09    printf("globale Variable Var = %i\n", Var);
  10 
  11    float Var;   /* lokale Variable  */
  12 
  13    Var = 1.5;   /* jetzt ist die
  14                    lokale Variable gemeint */
  15    printf("lokale Variable Var = %f\n", Var);
  16 
  17    return 0;
  18 }
  
3.10. Speicherklassen
  Die Angabe einer Speicherklasse bestimmt den Gültigkeitsbereich mit und gibt ferner an,
  ob die deklarierte Variable auch für den Linker bekannt sein soll. Es gibt die folgenden
  fünf Speicherklassen:
  
| auto | 
     Kann nur bei der Deklaration von Variablen innerhalb von Funktionen und
     Blöcken verwendet werden. Die deklarierte Variable ist dadurch eine lokale
     (automatische) Variable und ist nur innerhalb des Blockes gültig, in dem sie
     deklariert wurde (vom Deklarationspunkt bis zum Ende des Blockes). Da diese
     Speicherklasse der Standard ist, kann das Schlüsselwort auto
     auch weggelassen werden - das ist auch der Grund, warum dieses Schlüsselwort nur
     selten in C-Programmen zu finden ist. | 
| extern | Kann für globale oder lokale Variablen verwendet werden. Durch dieses Schlüsselwort wird angegeben, dass die deklarierte Variable in einer anderen C-Quelltextdatei deklariert und definiert ist. Erst beim Linken wird die deklarierte Variable mit der definierten Variable (aus einer anderen C-Quelltextdatei) verbunden. Standardmäßig werden externe Variablen als globale Variablen deklariert und sind daher innerhalb der ganzen Quelltextdatei (vom Deklarationspunkt bis zum Ende der Quelltextdatei) gültig. Als lokale Variablen sind externe Variablen auch nur innerhalb des Blockes gültig, in dem sie deklariert wurden. Einige C-Compiler, die sich nicht ganz an das Standard-C halten, sehen alle externen Variablen als globale Variablen. | 
| register | Kann nur bei der Deklaration von lokalen Variablen oder bei Funktions-Parametern verwendet werden. Der Compiler bekommt damit den Hinweis, dass diese Variable häufig genutzt wird und dass die Variable - wenn möglich - so definiert werden sollte, dass die Zugriffszeit möglichst gering ist. Der schnellste Zugriff wird erreicht, wenn die Variable in einem Register des Prozessors definiert wird. | 
| static | 
     Kann für globale oder lokale Variablen verwendet werden. Statische
     Variablen sind wohl nur innerhalb des Blockes (lokal) bzw. innerhalb der Quelltextdatei
     (global) sichtbar, in denen sie deklariert wurden; sie sind dann aber bis zum Ende des
     Programms gültig! D.h. am Ende des Gültigkeitsbereiches von normalen Variablen
     werden statische Variablen nicht vernichtet und behalten sogar ihren Wert bei. Statische
     Variablen mit Initialisierung werden dadurch auch nur beim einmaligen Anlegen initialisiert;
     wird der Block mit der statischen Variablen-Deklaration erneut aufgerufen, existiert diese
     Variable bereits und die Initialsierung wird nicht durchgeführt. 
     01 #include <stdio.h> 
     Der Anweisungsblock der Schleife wird fünf Mal durchlaufen; dabei werden folgende
     Werte ausgegeben: | 
| typedef | 
     Anders als bei den anderen vier Speicherklassen wird mit diesem Schlüsselwort ein
     neuer Datentyp aus vorhandenen Datentypen definiert. Anstelle eines Variablennamens
     wird der Name des neuen Datentyps angegeben. | 
3.11. volatile
  Mit dem Schlüsselwort volatile (engl. für flüchtig)
  bei der Variablendefinition wird dem C-Compiler mitgeteilt, dass der Wert dieser Variable
  auch von außerhalb des Programms - also von anderen Programmen bzw. von der Hardware -
  geändert werden kann. Solche Variablen werden bei der Optimierung des Quellcodes vom
  Compiler nicht berücksichtigt.
  Am häufigsten wird dieser Typspezifizierer beim Zugriff auf Speicheradressen der
  Computer-Hardware verwendet, da die Hardware den Wert der Speicheradresse unabhängig
  vom Programm ändern kann (z.B. Ein- und Ausgabepuffer sowie Kontrollregister).
  
  Voriges Kapitel: 2. Zeichen, Zeichensätze und Tokens
  
Nächstes Kapitel: 4. Datentypen in C

