if, switch & Schleifen
Kontrollstrukturen in C++: klassisches if, moderne Init-Statements, switch, Schleifen und range-for. Plus break, continue und das neue if constexpr.
Inhaltsverzeichnis
Kontrollstrukturen in C++
C-aehnlich, aber mit einigen modernen Erweiterungen, die den Alltag angenehmer machen.
if / else
int alter = 18;
if (alter >= 18) {
std::cout << "Volljaehrig\n";
} else if (alter >= 16) {
std::cout << "Fast volljaehrig\n";
} else {
std::cout << "Zu jung\n";
}
Regeln:
- Klammern
()um die Bedingung sind Pflicht - Geschweifte Klammern
{}technisch optional, aber immer empfohlen - Bedingung wird zu
boolkonvertiert (0 = false, alles andere = true)
if mit Init-Statement (C++17)
Du kannst eine Variable direkt in der if-Bedingung deklarieren - sie lebt nur im if/else-Block:
if (auto ergebnis = berechne(); ergebnis > 0) {
std::cout << "Positiv: " << ergebnis << "\n";
} else {
std::cout << "Nicht positiv: " << ergebnis << "\n";
}
// ergebnis existiert hier nicht mehr
Praktisch fuer temporaere Werte, die nur fuer den Check gebraucht werden.
Ternaerer Operator
auto text = (alter >= 18) ? "volljaehrig" : "minderjaehrig";
Standard-C-Syntax.
switch
int tag = 3;
switch (tag) {
case 1:
std::cout << "Montag\n";
break;
case 2:
case 3:
case 4:
std::cout << "Mitte der Woche\n";
break;
case 5:
std::cout << "Freitag\n";
break;
default:
std::cout << "Wochenende\n";
}
Wichtig: break; am Ende jedes Case, sonst Fall-Through zum naechsten.
Fall-Through explizit markieren (C++17)
switch (n) {
case 1:
std::cout << "Eins\n";
[[fallthrough]];
case 2:
std::cout << "Zwei oder eins\n";
break;
default:
break;
}
Das [[fallthrough]]-Attribut macht klar: โDer Fall-Through ist gewollt, nicht vergessen.โ
switch mit Init-Statement
switch (auto wert = berechne(); wert) {
case 0: /* ... */ break;
case 1: /* ... */ break;
}
while und do-while
int n = 10;
while (n > 0) {
std::cout << n << "\n";
n--;
}
// mindestens einmal ausfuehren
int eingabe;
do {
std::cin >> eingabe;
} while (eingabe != 0);
Klassische for-Schleife
for (int i = 0; i < 5; i++) {
std::cout << i << "\n";
}
Range-for (C++11, bevorzugt)
Der moderne Weg, ueber Sammlungen zu iterieren:
#include <vector>
#include <string>
std::vector<std::string> namen = {"Max", "Anna", "Leo"};
for (const auto& name : namen) {
std::cout << name << "\n";
}
const auto&- lesen, keine Kopieauto&- lesen und aendern, keine Kopieauto- Kopie
Mit Initialisierung
for (auto name : std::vector{"a", "b", "c"}) {
std::cout << name << "\n";
}
Index bekommen
C++ hat kein eingebautes โenumerateโ - aber du kannst Zaehler nutzen:
int i = 0;
for (const auto& name : namen) {
std::cout << i++ << ": " << name << "\n";
}
Oder mit std::ranges::views::enumerate (C++23):
#include <ranges>
for (auto [i, name] : std::views::enumerate(namen)) {
std::cout << i << ": " << name << "\n";
}
break und continue
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) continue; // gerade ueberspringen
if (i > 7) break; // abbrechen bei > 7
std::cout << i << "\n"; // 1, 3, 5, 7
}
Labels (C++ hat keine)
Wenn du aus verschachtelten Schleifen ausbrechen willst:
bool abbruch = false;
for (int x = 0; x < 10 && !abbruch; x++) {
for (int y = 0; y < 10; y++) {
if (finde(x, y)) {
abbruch = true;
break;
}
}
}
Oder die Schleife in eine Funktion auslagern und return nutzen - oft sauberer.
if constexpr (C++17)
Das ist ein Compile-Zeit-if fuer Templates:
template <typename T>
void print(const T& wert) {
if constexpr (std::is_integral_v<T>) {
std::cout << "Int: " << wert << "\n";
} else if constexpr (std::is_floating_point_v<T>) {
std::cout << "Float: " << wert << "\n";
} else {
std::cout << "Anderer Typ\n";
}
}
Der Zweig, der nicht passt, wird nicht einmal kompiliert - das ist maechtig fuer generische Programmierung. Fuer Anfaenger erst mal nicht wichtig, aber gut zu wissen, dass es das gibt.
Structured Bindings
Destrukturierung fuer Tuples, Paare, Structs:
#include <map>
#include <string>
std::map<std::string, int> alter = {{"Anna", 28}, {"Max", 34}};
for (const auto& [name, jahre] : alter) {
std::cout << name << ": " << jahre << "\n";
}
Und bei std::pair:
auto [min, max] = std::minmax({3, 1, 4, 1, 5, 9, 2});
Sehr praktisch bei Map-Iteration oder Funktionen, die mehrere Werte zurueckgeben.
Praktisches Beispiel
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int main() {
std::vector<int> zahlen = {3, 1, 4, 1, 5, 9, 2, 6};
// Maximum finden (klassisch)
int max = zahlen[0];
for (const auto& z : zahlen) {
if (z > max) max = z;
}
std::cout << "Max: " << max << "\n";
// Einfacher mit <algorithm>
auto maxIt = std::max_element(zahlen.begin(), zahlen.end());
std::cout << "Max: " << *maxIt << "\n";
// Alle geraden Zahlen
for (const auto& z : zahlen) {
if (z % 2 != 0) continue;
std::cout << z << " ";
}
std::cout << "\n";
}
Zusammenfassung
if/elsemit optionalem Init-Statement (C++17)switchmit explizitem[[fallthrough]]- Range-for ist der idiomatische Weg fuer Schleifen
auto&,const auto&,auto- bewusst waehlen- Structured Bindings fuer elegante Destrukturierung
std::max_element,std::sort, etc. sparen Handarbeit
Im naechsten Kapitel: Funktionen und References.