In C# integrierte Datentypen
Zu Teil 2: Erste Schritte in C#
Zu Teil 3: Ablaufsteuerung in C#
Teil 4: In C# integrierte Datentypen
Wir haben in den vorherigen Kapiteln bereits den Datentyp int
für Ganzzahlen kennen gelernt. Tatsächlich stellt C# bereits eine Reihe von Datentypen bereit, die wir direkt verwenden können. Die integrierten Datentypen können wir dabei in die folgenden Kategorien einteilen: Wahrheitswerte, ganzzahlige Werte, Gleitkommazahlen sowie Zeichen bzw. Zeichenketten.
Wahrheitswerte
Wahrheitswerte können in C# mit dem Datentyp bool
dargestellt werden. Der Datentyp bool
kennt nur zwei mögliche Werte: true
und false
. Implizit haben wir den Datentyp bool
bereits zuvor verwendet, nämlich bei den Bedingungen für das if-else
-Konstrukt und den Schleifen.
Eine Variable vom Typ bool können wir also dazu verwenden, um das Resultat einer Bedingungsprüfung zu speichern:
bool b = 5 > 6;
Im Beispiel hätte die Variable b
nun den Wert false, da 5 nicht größer als 6 ist. Wir können einer boolschen Variable auch direkt einen der Werte true oder false zuweisen oder innerhalb der Bedingung auf andere Variablen zugreifen.
bool b1 = false;
int a = 10;
bool b2 = a < 25;
Im Beispiel hätte die Variable b2
den Wert true
, da die Variable a
den Wert 10 enthält und dieser kleiner als 25 ist.
Ganzzahlige Werte
Datentyp | Wertebereich | Beispiel |
---|---|---|
sbyte | -128 bis 127 | 12 |
short | -32768 bis 32767 | 30000 |
int | -2147483648 bis 2147483647 | -200000 |
long | -9223372036854775808 bis 9223372036854775807 | 4147483648 |
ushort | 0 bis 65535 | 40000 |
uint | 0 bis 4294967295 | 4000000000 |
ulong | 0 bis 18446744073709551615 | 4147483648 |
In C# existieren verschiedene Typen, mit denen man ganzzahlige Werte abspeichern kann. Diese Typen unterscheiden sich in ihrem Wertebereich. Typen mit kleinerem Wertebereich verbrauchen daher weniger Speicher als Typen mit einem größeren Wertebereich. Um möglichst speicherplatzeffiziente Programme zu schreiben, sollten wir also immer den kleinstmöglichen Typ wählen, der den für den konkreten Zweck benötigten Bereich abdeckt.
Am häufigsten werden int
-Variablen verwendet, weil der Wertebereich von unter -2 Milliarden bis über +2 Milliarden die meisten Anwendungsfälle abdeckt. Mit long können dagegen noch einmal sehr viel größere Ganzzahlen dargestellt werden.
Zusätzlich gibt es noch die sogenannten unsigned
-Datentypen. Die Namen dieser Datentypen entstehen durch das Voranstellen des Buchstabens u
an den Namen des jeweiligen gewöhnlichen Datentypen. Unsigned-Datentypen können ausschließlich nicht-negative Zahlen darstellen, die untere Grenze der Wertebereiche ist also immer 0.
Unser C#-Tutorial
Lesen Sie hier die ersten 4 Kapitel kostenlos!
Die Datentypen haben also alle unterschiedliche Wertebereiche, jedoch gibt es keinen Datentyp mit unendlichem Wertebereich. Es gilt auch, aufzupassen, dass man nicht einen Datentyp wählt, der für den beabsichtigten Zweck zu klein ist. Betrachten wir dazu das folgende Beispiel:
int a1 = 2147483647;
a1 = a1 + 1;
Wir erstellen zunächst eine Variable a1
vom Typ int
und initialisieren diese mit dem größtmöglichen Wert, den eine int
-Variable speichern kann. Danach inkrementieren wir die Variable. Durch das Inkrementieren geschieht an dieser Stelle ein sogenannter Überlauf, da nun die eigentlich vorgesehenen Grenzen des Datentypen überschritten werden. Bei einem Überlauf wird einfach am anderen Ende des Wertebereichs "weiter gemacht", d.h. die Variable hat nun den kleinstmöglichen int
-Wert -2147483648.
Ein solches Verhalten möchte man in der Regel vermeiden, daher ist es ratsam, den verwendeten Datentyp immer sehr sorgsam auszuwählen. Im Zusammenhang mit den unsigned
-Datentypen gilt es hier, besonders achtsam zu sein. Der Wertebereich von unsigned
-Datentypen umfasst lediglich nicht-negative Werte, d.h. die untere Grenze des Wertebereiches ist immer 0. Wenn Sie nun zum Beispiel eine rückwärts laufende Schleife mit einer unsigned
-Zählvariable erstellen, kann es leicht vorkommen, dass Sie versehentlich eine Endlosschleife (also eine Schleife, die niemals terminiert) kreieren:
for (uint i = 10; i >= 0; i--)
{
...
}
Im gezeigten Fall wird in der Bedingung geprüft, ob die Zählvariable i
noch größer oder gleich 0 ist. Tatsächlich ist das aber immer der Fall: wenn die Zählvariable 0 erreicht hat und erneut dekremeniert wird, geschieht ein Überlauf und die Variable erhält nun den maximalen uint
-Wert 4294967295. Bei einer rückwärts laufenden Schleife ist es also ratsam, immer den normalen signed
-Datentyp für die Zählvariable zu verwenden.
Programmieren mit C# - Einige unserer Empfehlungen
Gleitkommazahlen
Datentyp | Wertebereich | Beispiel |
---|---|---|
float | -3.402823 E38 bis 3.402823 E38 | 3.8 |
double | -1.79769313486232 E308 bis 1.79769313486232 E308 | 21652430000000000 |
decimal | +/- 1,0 E-28 bis +/- 7,9 E28 | 0.1000012345 |
Gleitkommazahlen werden dann verwendet, wenn man Zahlen mit Nachkommastellen benötigt. Außerdem haben Gleitkommazahlen einen deutlich größeren Wertebereich als ganzzahlige Werte. Auf den ersten Blick erscheint es daher naheliegend, einfach grundsätzlich Gleitkommazahlen zu verwenden. In der Realität sind Gleitkommazahlen dagegen noch problematischer als die ganzzahligen Werte. Bei ganzzahligen Werten kennen wir bereits das Problem des Überlaufs an den Grenzen des Wertebereichs. Bei den Gleitkommazahlen gibt es dagegen zusätzlich noch das Problem mit der Genauigkeit.
Eine Gleitkommazahl in C# kann nämlich ebenfalls nur eine begrenzte Anzahl an Werten abdecken. Tatsächlich gibt es aber unendlich viele Gleitkommazahlen. Bestimmte tatsächlich existierende Gleitkommazahlen können also nicht in einer Gleitkomma-Variable innerhalb von C# gespeichert werden. Die Gleitkommatypen können nur Werte mit einer begrenzten Genauigkeit aufnehmen. Konkret bedeutet das, das weiter hinten stehende Stellen ignoriert und damit zu 0 werden.
Beispiel: Eine float
-Variable, die mit dem Wert 0.1000012345
initialisiert wird, hat tatsächlich den Wert 0.1000012
. Die drei letzten Stellen können mit der begrenzten Genauigkeit nicht mehr gespeichert werden. Die Genauigkeit von double
-Variablen ist wesentlich höher, aber letztendlich ebenfalls begrenzt. Der Datentyp decimal
bietet dagegen eine wesentlich höhere Genauigkeit und sollte daher für finanzmathematische Anwendungen verwendet werden. Hierbei sollte bedacht werden, dass die erhöhte Genauigkeit durch einen im Vergleich zu double
-Variablen doppelt so hohen Speicherverbrauch erkauft wird. Der Datentyp decimal
sollte daher nur dort verwendet werden, wo die höhere Genauigkeit tatsächlich benötigt wird.
Besonders aufpassen muss man auch beim Rechnen mit den Gleitkommazahlen. Hier kann es zu Ungenauigkeiten kommen - und das schon bei relativ gewöhnlichen Zahlenwerten. Beispiel:
double a = 69.82;
double b = 69.2 + 0.62;
Console.WriteLine(a == b);
Console.WriteLine(a-b);
Auf den ersten Blick würden wir vermuten, dass in den Variablen a
und b
derselbe Wert gespeichert ist und die Abfrage a == b
dementsprechend true
liefert. Das ist aber nicht der Fall. Wenn wir die Differenz der beiden Werte ausgeben lassen, stellen wir fest, dass die Differenz nicht 0 ist, sondern -1,4210854715202 x 10^-14 (also sehr klein). Diese Ungenauigkeit ist in der Art begründet, wie Gleitkommazahlen intern gespeichert werden. Die Details brauchen uns nicht zu interessieren - wir müssen nur wissen: Gleitkommazahlen können ungenau sein.
Bei Operationen, bei denen die Genauigkeit wichtig ist, sollten wir uns nicht auf die Typen float
und double
verlassen, sondern stattdessen den wesentlich genaueren Typen decimal
verwenden. Insbesondere Gleichheitsprüfungen zwischen Gleitkommazahlen der Typen float
und double
sind gefährlich, da diese (wie zuvor gezeigt) unerwartete Resultate liefern können. Wenn eine Gleichheitsprüfung bei Gleitkommazahlen durchgeführt werden muss, sollte also entweder eine kleine Toleranz erlaubt werden oder der genauere Datentyp decimal
verwendet werden.
Zeichen
Zum Speichern von einzelnen Unicode-Zeichen wie z.B. 'a' oder 'ß' gibt es den Datentyp char
. Ein Zeichen wird dabei innerhalb eines Paares von einzelnen Hochkommas angegeben, also
char c = 'a';
Intern werden Zeichen dabei als Ganzzahlwerte gespeichert, z.B. im Bereich von 0 - 255 gemäß des ASCII-Code. Wir werden später noch sehen, inwiefern das nützlich ist.
Zudem gibt es einige spezielle Zeichen, die sich nicht so einfach darstellen lassen. Das trifft z.B. auf den Zeilenumbruch oder den Tabulator zu. Um solche Zeichen darzustellen, gibt es sogenannte Escape-Sequenzen. Escape-Sequenzen beginnen immer mit einem einfachen Backslash. Die Escape-Sequenz \n symbolisiert z.B. den Zeilenumbruch. Um einen tatsächlichen Backslash als Zeichen darzustellen, benötigt man ebenfalls eine Escape-Sequenz. Ein einzelner Backslash würde nämlich immer als Einleitung einer Escape-Sequenz angesehen. Der einzelne Backslash wird daher über die Escape-Sequenz \\ dargestellt.
char backslash = '\\';
Zeichenketten
Ein weiterer sehr wichtiger Datentyp in C# sind die Zeichenketten. Eine Zeichenkette ist eine sortierte Liste von einzelnen Zeichen. Man kann in einer Zeichenkette also Wörter oder Sätze speichern. Der Datentyp, mit dem Zeichenkette in C# repräsentiert werden, heißt string
. Einen string
können Sie ähnlich erzeugen wie einen einfachen char
-Wert, statt eines einfachen Hochkommas müssen jedoch doppelte Anführungszeichen verwendet werden:
string myString = "Hallo Welt";
Innerhalb von Zeichenketten können auch Escape-Sequenzen verwendet werden, z.B. zur Darstellung von Zeilenumbrüchen:
string myString = "Hallo \n Welt";
Soll innerhalb einer Zeichenkette selbst ein Anführungszeichen verwendet werden, muss dafür die Escape-Sequenz \" genutzt werden:
string myString = "Harry sagt:\"Oh, wie schoen.\" ";
Würden wir hier nicht die Escape-Sequenz verwenden, würde der C#-Compiler das normale Anführungszeichen als Ende-Begrenzung der Zeichenkette interpretieren.
Variablen anlegen
Wir haben bereits mehrfach gesehen, dass man Variablen nach folgender Syntax deklarieren kann:
Typ Variablenname;
Die Zuweisung erfolgt nach der Syntax
Variablenname = <Ausdruck>;
und die Kombination von Deklaration und Zuweisung nach folgender Syntax:
Typ Variablenname = <Ausdruck>;
Wichtig: der Wert einer Variable darf nicht ausgelesen werden, bevor erstmalig ein Wert zugewiesen wurde. Versucht man dies doch, resultiert dies in einem Compiler-Fehler (d.h. das Programm wird garnicht erst in Maschinencode übersetzt).
Beispiel:
int i1;
int i2 = i1 + 1;
Der Code führt zu einem Compilerfehler, da man versucht, den Wert der Variable i1
auszulesen, bevor der Variable ein initialer Wert zugewiesen wurde.
Man kann außerdem innerhalb einer einzelnen Anweisung mehrere Variablen eines Typs anlegen. Die allgemeine Syntax hierfür lautet:
MeinTyp Variablenname1, Variablenname2, Variablenname3;
Es würden also die drei Variablen Variablenname1, Variablenname2, Variablenname3 vom Typ MeinTyp
angelegt. Man kann in diesem Zusammenhang auch Deklaration und Zuweisung kombinieren:
int var1, var2 = 5, var3;
Im Beispiel werden drei int
-Variablen var1
, var2
und var3
angelegt. Die Variable var2
wird mit dem Wert 5 initialisiert, die beiden anderen Variablen erhalten dagegen zunächst keinen Wert zugewiesen.
Implizit typisierte Variablen
In manchen Fällen kann aus der direkten Initialisierung einer Variablen abgeleitet werden, von welchem Typ die Variable sein muss. In solchen Fällen kann man die Angabe des Typs bei der Deklaration durch das Schlüsselwort var
ersetzen.
var i1 = 1;
var zeichenkette = "hallo";
Im Beispiel wäre die Variable i1
vom Typ int
sowie die Variable zeichenkette
vom Typ string
. Diese implizite Typisierung darf nur verwendet werden, wenn eine Variable direkt initialisiert wird und sich der Typ direkt daraus ableiten lässt.
Typumwandlung
Variablen eines Types können gegebenenfalls auch in Variablen eines anderen, kompatiblen Typen umgewandelt werden. Man nennt die Typumwandlung bzw. Typecasting. Offensichtlich ist diese Möglichkeit zum Beispiel bei den verschiedenen Ganzzahlwerten.
Hierbei gilt: wenn eine Variable eines "kleineren" Typen in einen größeren Typen umgewandelt werden soll, kann dies implizit geschehen. Implizit bedeutet dabei, dass man keinerlei Konvertierung vornehmen muss, sondern einfach die neue Variable wie gewünscht zuweist.
Beispiel:
int int1 = 6000;
long intAsLong = int1;
Im Beispiel wird zunächst eine int
-Variable int1
angelegt und mit dem Wert 6000 initialisiert. Danach wird eine neue Variable intAsLong
erstellt und diese mit dem Wert von int1
initialisiert. Wir haben nun also eine long
-Variable intAsLong
, die den Wert 6000 besitzt.
Allerdings geht das auch umgekehrt: man kann eine Variable eines "größeren" Typs in eine Variable eines kleineren Typs umwandeln. In diesem Fall muss man jedoch eine explizite Typumwandlung durchführen. Dies geschieht durch Voranstellen des Zieltyps innerhalb eines Klammerpaares:
long long1 = 6000;
int longAsInt = (int) long1;
In diesem Beispiel haben wir nun also schlussendlich eine int
-Variable longAsInt
, die den Wert 6000 besitzt.
Allerdings gibt es ein Problem: wenn der Wertebereich des Quelltyps größer ist als der Wertebereich des Zieltyps, kann man auch versuchen, einen Wert in eine Variable zu konvertieren, die diesen Wert garnicht speichern kann.
Beispiel:
long bigLong = 3000000000;
int bigLongAsInt = (int) bigLong;
Zur Erinnerung: Der Wertebereich von int
reicht nur bis etwa 2,1 Milliarden. Da aber in der long-Variable bigLong
der Wert 3 Milliarden gespeichert ist, kann der Wert nicht in eine int
-Variable passen. Bei einer solchen Typumwandlung tritt wieder der bereits zuvor beschriebene Überlauf auf. long
intmax wird zu int
intmax. long
intmax + 1 wird zu int
intmin. long
intmax + 2 wird zu int
intmin + 1, usw. Demnach wird long
3000000000 zu int
-1294967296. Die Variable bigLongAsInt
enthält also am Ende den Wert -1294967296.
Eine Typumwandlung kann aber auch zwischen char
-Werten und Ganzzahlwerten erfolgen: wie zuvor erwähnt werden char
-Werte intern von Ganzzahlwerten repräsentiert. Man kann also gemäß dem ASCII-Code eine char-Variable mit dem Wert 'A' auch auf folgende Weise anlegen:
char ch = (char) 65;
65 ist der ASCII-Code für das Zeichen 'A'.
Ebenso kann man den ASCII-Code eines Zeichens bestimmen:
int ascii = (int) 'A';
Die Variable ascii
hat nun den Wert 65.
Im übrigen kann man auf char
-Variablen auch gewöhnliche arithmetische Operationen durchführen. Da char
-Variablen intern durch Ganzzahlen repräsentiert werden, werden die arithmetischen Operationen auf den zugrunde liegenden Ganzzahlen durchgeführt.
char A = 'A';
A++;
Console.WriteLine(A);
Im Beispiel wird eine char
-Variable, die das Zeichen 'A' beinhaltet, angelegt. Intern wird die Variable durch den ASCII-Code 65 von 'A' repräsentiert. Nun wird die Variable inkrementiert, d.h. es ist nun ein ASCII-Wert von 66 hinterlegt. In der Variable A
ist daher nun das Zeichen 'B' gespeichert, da 66 der ASCII-Code von 'B' ist.
Über diesen Kurs
Dieses Tutorial richtet sich an Einsteiger, die C# programmieren lernen wollen. Die ersten 4 Kapitel des Tutorials, in denen die Grundlagen erklärt werden, können Sie bereits auf der Webseite lesen.
Die Einführung für Anfänger umfasst unverzichtbare Elemente der Programmiersprache wie Bedingungen und Schleifen, Variablen und Datentypen.
Die komplette Version des Tutorials kann in Buchform erworben werden. Sie steht sowohl als gedrucktes Buch als auch als eBook zur Verfügung. In diesem erweiterten C#-Tutorial für Einsteiger, die Programmieren lernen wollen, werden viele weitere Themen wie Operatoren, Ausdrücke, Klassen und Vererbung anfängergerecht präsentiert. Zudem werden auch fortgeschrittene Themen wie die Erstellung von grafischen Benutzeroberflächen mit der Windows Presentation Foundation (WPF) und Netzwerkprogrammierung angeschnitten. Des weiteren enthält enthält das Komplett-Tutorial umfangreiche Begleitmaterialien wie eine Download-Möglichkeit des Beispielcodes, Übungen und Lösungsvorschläge für die Übungen.
Ab 6 Euro
Zufriedenheitsgarantie: Sie können sich den Kaufpreis über Amazon erstatten lassen, wenn Sie mit dem Tutorial nicht zufrieden sind.
Zu Amazon
Zu Teil 2: Erste Schritte in C#
Zu Teil 3: Ablaufsteuerung in C#
Teil 4: In C# integrierte Datentypen
Eine ausführliche Liste unserer Buchempfehlungen für C# finden Sie hier.
Unsere Buchempfehlungen
Oder sehen Sie sich die vollständige Liste der Empfehlungen für C# an.Wir haben auch eine Empfehlung für einen C#-Fernkurs parat.