Variablen & Datentypen
Typen in C++: primitive Typen, auto, const, references vs. values, und Standard-Library-Typen wie std::string und std::vector.
Inhaltsverzeichnis
Variablen & Datentypen
C++ ist statisch und stark typisiert - Typen werden zur Kompilierzeit festgelegt. Dank auto musst du Typen selten explizit ausschreiben.
Variablen deklarieren
int alter = 28;
double pi = 3.14159;
bool aktiv = true;
std::string name = "Anna";
Mit Initialisierungslisten (empfohlen)
int alter{28};
double pi{3.14159};
std::string name{"Anna"};
Diese {}-Syntax (Braced Init) verhindert Narrowing - etwa eine double in einen int zu stopfen und dabei Nachkommastellen zu verlieren:
int x = 3.7; // OK - wird 3 (Narrowing!)
int y{3.7}; // FEHLER - Narrowing verhindert
Mit auto
auto alter = 28; // int
auto pi = 3.14; // double
auto name = std::string{"Anna"}; // std::string
const, constexpr und consteval
const int MAX = 100; // Laufzeitkonstante
constexpr int SECONDS_PER_DAY = 86400; // Kompilierzeit-konstant
constexpr int square(int x) {
return x * x;
}
int arr[square(5)]; // OK - 25 ist zur Kompilierzeit bekannt
Faustregel: Wenn du den Wert zur Kompilierzeit kennst, nimm constexpr. Sonst const. Beide sind dem Compiler willkommen fuer Optimierung.
Primitive Typen
Ganzzahlen
int a = 42; // typischerweise 32-Bit
long b = 42L;
long long c = 42LL;
unsigned int d = 42U;
short e = 42;
Fuer groessenexakte Typen aus <cstdint>:
#include <cstdint>
int32_t x = 42;
int64_t y = 1'000'000'000LL;
uint8_t z = 255;
Die ' sind Ziffern-Trennzeichen seit C++14, reiner Lesekomfort.
Fliesskomma
float f = 3.14f;
double d = 3.14159;
long double ld = 3.14159L;
double ist der Standard (64 Bit).
Boolean
bool aktiv = true;
bool fertig = false;
Character
char c = 'A'; // 1 Byte
char16_t c2 = u'A'; // UTF-16
char32_t c3 = U'๐ฆ'; // UTF-32
Strings
Vermeide nackte char* oder char[] - nutze std::string:
#include <string>
std::string name = "Anna";
name += " Mueller"; // Verkettung
std::string gruss = "Hallo, " + name;
// Methoden
name.length(); // 12
name.substr(0, 4); // "Anna"
name.find("Mueller"); // Position
name.empty(); // false
String-Views (schnell, ohne Kopie)
#include <string_view>
void verarbeite(std::string_view text) {
// Keine Kopie, nur ein "Fenster" auf Original-Daten
}
std::string s = "Hallo";
verarbeite(s); // implizite Konvertierung
verarbeite("Welt"); // funktioniert auch mit const char*
Fuer Funktionsparameter, die nur lesen, ist std::string_view ideal.
Container aus der STL
std::vector - dynamisches Array
#include <vector>
std::vector<int> zahlen = {1, 2, 3, 4, 5};
zahlen.push_back(6); // anhaengen
zahlen[0] = 99;
std::cout << zahlen.size(); // 6
Gleichwertige moderne Alternative fuer int zahlen[5]. Nutze fast immer std::vector.
std::array - Array fester Groesse
#include <array>
std::array<int, 3> punkte = {10, 20, 30};
Bessere Variante als C-Arrays, mit size(), Iteration, etc.
std::map und std::unordered_map
#include <map>
#include <unordered_map>
std::map<std::string, int> alter = {
{"Anna", 28},
{"Max", 34}
};
std::cout << alter["Anna"]; // 28
alter["Leo"] = 22;
// Unordered ist schneller (Hash), aber unsortiert
std::unordered_map<std::string, int> counts;
std::pair
#include <utility>
std::pair<int, std::string> p = {1, "Anna"};
std::cout << p.first << ", " << p.second;
std::optional
Wenn ein Wert fehlen kann:
#include <optional>
std::optional<int> finde(int id) {
if (id > 0) return 42;
return std::nullopt; // "nicht vorhanden"
}
auto ergebnis = finde(1);
if (ergebnis) {
std::cout << *ergebnis;
}
References vs. Pointers
Value
void funktion1(int x) { ... } // Kopie - teuer bei grossen Objekten
Reference
void funktion2(int& x) { ... } // kann veraendern
void funktion3(const int& x) { ... } // kann nicht veraendern
Die const&-Variante ist der Standard fuer grosse Objekte:
void druckeName(const std::string& name) {
std::cout << name << "\n";
}
Pointer
int x = 42;
int* p = &x; // Pointer auf x
*p = 100; // Dereferenzieren und aendern
std::cout << x; // 100
Pointers koennen null sein, Referenzen nicht. Moderne C++-Empfehlung: bevorzuge Referenzen, nutze Pointer (oder Smart Pointer) nur wenn noetig.
Typ-Konvertierung
Implizit
int x = 5;
double d = x; // OK - int -> double
Explizit mit static_cast
double d = 3.7;
int x = static_cast<int>(d); // 3
static_cast ist der moderne Weg statt C-Style-Cast (int)d.
String zu Zahl
int zahl = std::stoi("42"); // wirft Exception bei Fehler
double d = std::stod("3.14");
// Sicherer mit <charconv> (C++17+)
#include <charconv>
int wert;
auto ergebnis = std::from_chars(str.data(), str.data() + str.size(), wert);
if (ergebnis.ec != std::errc{}) {
// Fehler
}
Enum Classes
Moderne, typsichere Enums:
enum class Richtung { Nord, Sued, Ost, West };
Richtung r = Richtung::Nord;
if (r == Richtung::Nord) {
std::cout << "Nordwaerts!\n";
}
Bevorzuge enum class gegenueber klassischem enum - keine Namenskonflikte, Typ-sicher.
Praktisches Beispiel
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main() {
struct Person {
std::string name;
int alter;
};
std::vector<Person> leute = {
{"Anna", 28},
{"Max", 34},
{"Leo", 22}
};
// Nach Alter sortieren
std::sort(leute.begin(), leute.end(),
[](const Person& a, const Person& b) {
return a.alter < b.alter;
});
for (const auto& p : leute) {
std::cout << p.name << " (" << p.alter << ")\n";
}
}
Zusammenfassung
- Braced Init (
int x{42}) verhindert Narrowing - nutze sie als Default autofuer Typ-Inferenz,const/constexprfuer Konstanten- Primitiv-Typen plus Standard-Library (
std::string,std::vector,std::map) const T&fuer Funktionsparameter, die nur lesenenum classstatt klassischeenumstatic_caststatt C-Style-Cast
Im naechsten Kapitel: Kontrollstrukturen.