C++-Programmierung: Variablen und Konstanten
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
BearbeitenEine 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
BearbeitenJede 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 unspezifischenchar
auch die vorzeichenlose Varianteunsigned char
und die vorzeichenbehaftetesigned 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
undlong
)
- speichern je nach Typ ganze Zahlen in verschiedenen Wertebereichen; ohne nähere Angabe oder mit
signed
sind die Werte vorzeichenbehaftet, mitunsigned
hingegen vorzeichenlos
- drei Fließkommatypen (
float
,double
undlong 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 Bitshort
16 Bitint
16 oder 32 Bitlong
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
BearbeitenVariablen 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
BearbeitenEine 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 = Π //normaler Zeiger auf konstante Variable
float* const cptr_Pi = Π //konstanter Zeiger auf normale Variable
const float* const cptr_cPi = Π //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.