C++-Programmierung: Variablen und Konstanten

Aus Wikibooks
Alte Seite
Diese Seite gehört zum alten Teil des Buches und wird nicht mehr gewartet. Die Inhalte sollen in das neue Buch einfließen: C++-Programmierung/ Inhaltsverzeichnis.
Eine aktuelle Seite zum gleichen Thema ist unter C++-Programmierung/ Einführung in C++/ Variablen, Konstanten und ihre Datentypen verfügbar.

Bei Variablen (variables) und Konstanten (constants) handelt es sich um Bereiche im Speicher, in denen Werte abgelegt werden, damit man diese später im Programm wieder verwenden oder (bei Variablen) auch verändern kann. Jede Variable und Konstante hat einen Namen (Bezeichner, identifier) und einen Typ (type).

Beispielprogramm[Bearbeiten]

Eine einfache Addition zweier Zahlen:

#include <iostream>
using namespace std;
int main(int argc, char** args)
{
  int a = 3;
  int b = 5;
  int ergebnis;
  ergebnis = a + b;
  cout << ergebnis << endl;  //8
  ergebnis = ergebnis + 5;
  cout << ergebnis << endl;  //13
  cin.get();
  return 0;
}

Wir deklarieren zuerst die Variablen a und b vom Typ int und weisen ihnen die Werte 3 bzw. 5 zu. Dieser Vorgang der Wertzuweisung heißt Initialisierung. Eine Variable muss nicht sofort mit einem Wert initialisiert werden. Es ist auch möglich, sie zunächst nur zu definieren und ihr später einen Wert zuzuweisen, so wie es im Beispiel mit der Variablen ergebnis geschieht.

In der Fachsprache wird zwischen Deklaration und Definition unterschieden. Eine Deklaration legt den Namen und den Typ einer Variablen fest, während eine Definition darüberhinaus Speicherplatz für die Variable reserviert. (Jede Definition ist also eine Deklaration, aber nicht umgekehrt, wie wir später sehen werden.)

Im Beispiel wird ergebnis der Wert a + b zugewiesen. Das Gleichheitszeichen = heißt auch Zuweisungsoperator; dass das Pluszeichen + für die Addition steht, wird Sie nicht überraschen. Dann wird ergebnis ausgegeben, 5 hinzuaddiert und das Resultat wiederum ausgegeben.

Bei einer Deklaration wird immer zuerst der Typ, dann der Name der Variablen angegeben. In ein und derselben Anweisung können, durch Komma getrennt, mehrere Variablen gleichen Typs deklariert und bei Bedarf auch initialisiert werden. Wir hätten also auch schreiben können

  int a = 3, b = 5;

Am Ende steht natürlich ein Semikolon ; wie am Ende jeder Anweisung. Da der Compiler am Semikolon und nicht etwa am Zeilenende erkennt, dass die Anweisung abgeschlossen ist, könnten wir auch mehrere Anweisungen in eine Zeile schreiben. Allerdings verbessert das die Lesbarkeit des Quelltextes nicht.

Typen[Bearbeiten]

Jede Variable besitzt einen Typ. Variablen gleichen Typs können einander in jedem Fall zugewiesen werden. Bei Variablen unterschiedlichen Typs ist die Zuweisung nicht immer möglich. Innerhalb der nachfolgend aufgeführten Basis-Datentypen gibt es jedoch keine Probleme, da der Compiler ggf. automatische Typ-Umwandlungen durchführt. Einige Compiler geben in solchen Fällen eine Warnung aus, zumindest dann, wenn es dabei zu einer Änderung des Wertes kommen kann (z.B. bei Zuweisung von float an int, bei der ein eventueller Nachkommateil wegfällt).

C++ hat acht Basis-Datentypen:

  • einen booleschen Typen (bool)
nimmt lediglich die booleschen Werte wahr (true) und falsch (false) an; bei Umwandlung in eine Zahl werden die beiden Wahrheitswerte als 1 bzw. 0 dargestellt
  • Zeichentypen (char)
speichert typischerweise einzelne Zeichen wie z.B. 'A' oder '#', wobei es neben dem unspezifischen char auch die vorzeichenlose Variante unsigned char und die vorzeichenbehaftete signed char gibt; streng genommen handelt es sich bei diesem Typ um „sehr kleine Zahlen“ (z.B. mit dem Wertebereich -128...+127 oder 0...255)
  • drei ganzzahlige Typen (int, short und long)
speichern je nach Typ ganze Zahlen in verschiedenen Wertebereichen; ohne nähere Angabe oder mit signed sind die Werte vorzeichenbehaftet, mit unsigned hingegen vorzeichenlos
  • drei Fließkommatypen (float, double und long double)
dienen zur Speicherung von Fließkommazahlen mit verschiedener Genauigkeit (z.B. double=doppelte Genauigkeit)

Häufig entspricht int entweder einem long oder einem short, d.h. die Größe ist systemabhängig und kann durch sizeof(int) ermittelt werden. Prinzipiell können auch alle ganzzahligen Typen gleich groß sein. Garantiert ist lediglich, dass short niemals größer als long ist.

Der ISO-Standard für C++ sieht folgende Mindestgrößen vor:

  • char 8 Bit
  • short 16 Bit
  • int 16 oder 32 Bit
  • long 32 Bit

Auf 64-Bit-Hardware kann long auch 64 Bit groß sein. Festgelegt ist dies aber nicht und einige Compiler bleiben in diesem Fall bei 32 Bit Größe für long und bieten als Erweiterung den Typ long long mit 64 Bit Größe an.

Bei den Fließkommazahlen steigen Genauigkeit und Wertebereich meist ebenfalls von float über double zu long double an. Sofern die Hardware den IEEE-Standard für Fließpunktzahlen unterstützt, werden i.d.R. die dort üblichen Größen (4, 8 und 10 Byte) verwendet, jedoch schreibt der ISO-Standard für C++ dies nicht vor.

C++ ist eine streng typisierte Programmiersprache: jede Variable hat ihren festen Typ, der nicht geändert werden kann. Durch die Typisierung ist bereits beim Kompilieren bekannt, wie eine Variable zu behandeln ist - vor allem wieviel Platz sie im Speicher einnimmt und welche Maschinenbefehle zu ihrer Verarbeitung zu verwenden sind. Das bringt einerseits Geschwindigkeitsvorteile (es muss nichts zur Laufzeit ermittelt werden) und andererseits mehr Sicherheit für den Programmierer: Viele Typfehler (z.B. der Versuch, die Modulo-Operation auf Gleitkommavariablen anzuwenden) werden bereits vom Compiler erkannt und nicht erst zur Laufzeit. Andere Programmiersprachen - vor allem Skriptsprachen - haben keine Typenunterscheidung.

Dennoch kann es mitunter zu Überraschungen kommen. Die Division zweier Ganzzahlen liefert z.B. stets wieder eine Ganzzahl. Das ändert sich auch dann nicht, wenn das Ergebnis an eine Variable mit Fließkommatyp zugewiesen wird. (Damit bei einer Division ein evtl. Nachkommateil berechnet wird, muss bereits einer der Operanden einen Fließkommatyp haben. Ein späteres Beispiel demonstriert dies.)

Gültigkeitsbereiche[Bearbeiten]

Variablen können entweder lokal oder global deklariert werden. Lokale Variablen sind automatisch, d.h. sie werden gelöscht, sobald ihr Bezugsrahmen verlassen wird. Den Bezugsrahmen (Block), z.B. Rumpf einer Funktion oder einer Schleife, begrenzen die geschweiften Klammern {}. Beispiel:

#include <iostream>
using namespace std;
int main(int argc, char** args)
{
  int a = 3;  //Initalisierung
  cout << a << endl;  
  cin.get();
  return 0;
}  // a nicht länger verfügbar (Speicherplatz wird freigegeben)

Es können in verschiedenen Bezugsrahmen die gleichen Variablennamen benutzt werden, wobei der Compiler jeweils auf die „lokalste“ Variable zugreift:

#include <iostream>
using namespace std;
int main(int argc, char** args)
{
  int a = 3;            //a (in Bezugsrahmen von main) 
  cout << a << endl;    //Ausgabe 3  
  if (a == 3) {
    int a = 10;         //inneres a (überdeckt jetzt äußeres a)
    cout << a << endl;  //Ausgabe 10
  }                     //Bezugsrahmen endet, inneres a
                        //nicht länger verfügbar
  cout << a << endl;    //Ausgabe 3 (wieder äußeres a)
  cin.get();
  return 0;
}                       //äußeres a nicht länger verfügbar

Um eine Variable in verschiedenen Bezugsrahmen, z.B. in verschiedenen Funktionen, gebrauchen zu können, muss man sie global deklarieren. Dies erreichen Sie, indem Sie die entsprechende Deklaration im Quelltext außerhalb aller Funktionen platzieren. Eine globale Variable ist für alle Funktionen sichtbar, ihr Wert geht erst verloren, wenn das Programm beendet wird.

Größere Programme werden modularisiert, d.h. auf mehrere Quelltextdateien verteilt. Wenn man auf eine globale Variable eines anderen Moduls zugreifen möchte, deklariert man sie mit dem Schlüsselwort extern:

 extern int a;

Dies ist eine Deklaration, aber keine Definition - denn der für die Variable a nötige Speicherplatz wird ja im anderen Modul reserviert.

Konstanten[Bearbeiten]

Eine Konstante wird behandelt wie eine Variable, man sollte ihr nur einmal, bei ihrer Deklaration, einen Wert zuweisen. Um bekannt zu geben, dass es sich um eine Konstante handelt, muss vor die Variablendefinition das Schlüsselwort const gestellt werden:

const float Pi = 3.14159f;

Das Schlüsselwort const teilt dem Compiler mit, dass ein deklariertes Objekt, oder eine deklarierte Variable nicht veränderbar ist. Bei Zeigern muss man zwei Fälle von const unterscheiden.

const float* ptr_cPi = &Pi; //normaler Zeiger auf konstante Variable
float* const cptr_Pi = &Pi; //konstanter Zeiger auf normale Variable
const float* const cptr_cPi = &Pi; //beides kombiniert

Ein konstanter Wert oder Zeiger kann durch eine Typumwandlung modifizierbar gemacht werden. (siehe const_cast)

Wenn Sie sich bereits mit der Programmiersprache C auskennen, wundern Sie sich vielleicht darüber, dass Konstanten in C++ nicht mehr wie in C ausschließlich mit der Präprozessor-Direktive #define festgelegt werden. Diese "Konstanten" sind jedoch Textersetzungen des Präprozessors und haben keinen Typ und Gültigkeitsbereich. Die Verwendung von const garantiert auch für Konstanten, dass Typ und Bezugsrahmen vom Compiler geprüft werden. Eine Konstante im falschen Kontext zu verwenden, wird dadurch verhindert. Allerdings ist es immer noch möglich mit unbedacht platzierten, konstanten Zuweisungen schwer überblickbare Folgefehler zu erzeugen.