C++ Tutorial

 Verzweigungen und Schleifen

if-Verzweigung

Die if-Verzweigung wird immer dann eingesetzt, wenn in Abhängigkeit von einer Bedingung unterschiedliche Anweisungen auszuführen sind. Sie hat folgende Syntax:

if ([INIT;] AUSDRUCK)
   ANWEISUNG1  // IF-Zweig
[else
   ANWEISUNG2] // ELSE-Zweig

Ergibt die Auswertung von AUSDRUCK true, wird die Anweisung ANWEISUNG1 ausgeführt. Ergibt die Auswertung von AUSDRUCK false, wird der optionale else-Zweig oder nichts ausgeführt. Zusätzlich kann innerhalb der if-Klammer ein Ausdruck INIT stehen, der vor der Auswertung von AUSDRUCK ausgeführt wird.

Standardmäßig folgt auf ein if oder else nur eine Anweisung. Um mehrere Anweisungen auszuführen, sind die Anweisungen in einen Block {...} einzuschließen.

AUSDRUCK kann auch aus mehreren Bedingungen bestehen, die mit den entsprechenden Logikoperatoren (&&, || und !) verknüpft werden.

if ((var1 == 10) && (!done))
{
   var2 = 10;
   done = true;
}
else
   var1++;}

#include <iostream>

int main()
{
   // Einzulesender Wert
   short val;
   // Wert einlesen und pruefen ob Zahl positiv
   std::cout << "Geben Sie bitte eine Integer-Zahl ein: ";
   std::cin >> val;
   if (val>0)
   // Alternativ: Zahl einlesen und pruefen in einer Anweisung
   // if (std::cin >> val; val>0)
      std::cout << "Zahl ist positiv.\n";
   else
   {
      // Pruefen ob Null eingegeben wurde
      if (val == 0)
         std::cout << "Sie haben 0 eingegeben.\n";
      else // Es wurde eine negative Zahl eingeben
         std::cout << "Zahl ist negativ.\n";
   }
}

Bedingungsoperator und goto

Eine abgewandelte Form der if-Anweisung stellt der Bedingungsoperator dar, der folgende Syntax besitzt:

erg = (AUSDRUCK1) ? AUSDRUCK2 : AUSDRUCK3;

Liefert die Auswertung des Ausdrucks AUSDRUCK1 als Ergebnis true, wird AUSDRUCK2 ausgewertet und das Ergebnis der Variablen erg zugewiesen. Liefert AUSDRUCK1 dagegen false, wird das Ergebnis von AUSDRUCK3 der Variablen erg zugewiesen.

var1 = (var2 == 100)? 1: 0;

#include <iostream>
#include <format>

int main()
{
   // Variablen definieren
   int eingabe, ausgabe;
   // int-Wert einlesen
   std::cout << "Bitte einen Integer-Wert eingeben: ";
   std::cin >> eingabe;
   // Absolutbetrag der Eingabe berechnen
   ausgabe = (eingabe<0)?-eingabe:eingabe;
   // Eingabe und Absolutbetrag ausgeben
   std::cout << std::format("Eingabe war: {}, Ausgabe ist: {}\n",eingabe,ausgabe);
}

Nur der Vollständigkeit halber sei an dieser Stelle noch erwähnt, dass C++ auch eine goto-Anweisung kennt. Sie wird hier aber nicht weiter betrachtet, da ein 'sauberes' Programm ohne goto auskommt.

constexpr if Anweisung

Mithilfe der constexpr if Anweisung können alternativ zu übersetzende Anweisungen in Abhängigkeit von einer Bedingung defniert werden. D.h. der Compiler erzeugt nur dann den entsprechenden Code, wenn die Bedingung erfüllt ist.

if constexpr ([INIT;] BEDINGUNG)
   ANWEISUNG1;  // if-Zweig
[else
   ANWEISUNG2;] // else-Zweig

Die Bedingung muss ein konstanter Ausdruck sein, der ein boolsches Ergebnis liefert. Sehen wir uns dies an einem Beispiel an. Je nach Wert der Konstanten DEBUG_LEVEL sollen während der Entwicklungsphase einer Anwendung verschiedene Ausgaben zur Verfolgung des Programmablaufs ausgegeben werden.

#include <iostream>

// Debug-Level festlegen
const int DEBUG_LEVEL = 1;

int main()
{
   if constexpr (DEBUG_LEVEL == 1)
   {
      std::cout << "Einfache Debug-Ausgabe.\n";
   }
   if constexpr (DEBUG_LEVEL == 2)
   {
      std::cout << "Detaillierte Debug-Ausgabe!\n";
   }
}

switch-Verzweigung

Sollen je nach Inhalt eines ganzzahligen oder char-Ausdrucks verschiedene Anweisungen durchlaufen werden, wird hierfür die switch-Verzweigung eingesetzt. Sie hat folgende Syntax:

switch ([INIT;] AUSDRUCK)
{
case K1:
   AKTION1
   [break;]
   ...
case Kx:
   AKTIONx
   [break;]
[default:
   AKTIONy]
}

Der Ablauf der switch-Verzweigung ist folgender:

  • Ist ein optionaler Initialisierungsausdruck INIT vorhanden, wird dieser zunächst ausgewertet.
  • Danach wird der Ausdruck der switch-Anweisung ausgewertet. Dieser Ausdruck muss entweder ein ganzzahliges oder char-Ergebnis liefern.
  • Anschließend wird das Ergebnis des Ausdrucks mit den Literalen verglichen, die auf das Schlüsselwort case folgen. Stimmt das Ergebnis mit einem der aufgeführten Literale überein, so werden die Anweisungen nach der entsprechenden case-Anweisung bis zur optinalen break-Anweisung ausgeführt. Mehrere Anweisungen müssen nicht einem Klammerpaar {...} eingeschlossen sein.
  • Stimmt das Ergebnis mit keinem der aufgeführten Literale überein, so werden die Anweisungen nach der optionalen default-Anweisung ausgeführt.

Die break-Anweisung innerhalb eines switch-Blocks bewirkt ein unmittelbares Verlassen des Blocks, d.h. nach dem break wird als Nächstes die Anweisung ausgeführt, die nach der geschweiften Klammer zu folgt. Ohne eine break-Anweisung werden alle nach der Einsprungsmarke (case Kx:) folgenden Anweisungen bis zum Ende des switch-Blocks oder bis zum Erreichen eines break ausführt.

Sollen für verschiedene Werte die gleichen Anweisungen ausgeführt werden, können mehrere case-Zweige unmittelbar aufeinanderfolgen. Die Reihenfolge der case-Anweisungen ist dabei beliebig.

#include <iostream>

int main()
{
   // Variable fuer die Eingabe definieren
   char eingabe;
   // Buchstaben einlesen
   // Das Einlesen erfolgt im INIT-Ausdruck der switch-Anweisung
   // Je nach Eingabe wird ein anderer Text ausgegeben, wobei
   // nicht nach Klein-/Grossschreibung unterschieden wird
   std::cout << "Bitte geben Sie einen Buchstaben ein: ";
   switch (std::cin >> eingabe; eingabe)
   {
   case 'e':
   case 'E':
      std::cout << "Sie haben e oder E eingegeben!\n";
      break;
   case 'a':
   case 'A':
      std::cout << "Sie haben a oder A eingegeben.\n";
      break;
   default:
      std::cout << "Sie haben weder ein a noch ein e eingegeben.\n";
   }
}

#include <iostream>
#include <format>

int main()
{
   float operand1, operand2;  // Operanden definieren
   float result = 0.0f;       // Ergebnis des Ausdrucks
   char opera;                // Operator definieren

   // Formel einlesen
   std::cout << "Bitte Formel eingeben: ";
   std::cin >> operand1 >> opera >> operand2;
   // Operator auswerten und Ergebnis berechnen
   switch(opera)
   {
   case '+':
      result = operand1 + operand2;
      break;
   case '-':
      result = operand1 - operand2;
      break;
   case '*':
      result = operand1 * operand2;
      break;
   case '/':
      result = operand1 / operand2;
      break;
   default:
      // Eingabe war kein +, -, * oder /
      std::cout << "Falsche Operand! ";
      break;
   }
   // Ergebnis ausgeben
   std::cout << std::format("Ergebnis: {}\n",result);
}

for-Schleife

Die for-Schleife wird hauptsächlich eingesetzt, wenn bereits vor dem Eintritt in die Schleife die Anzahl der Schleifendurchläufe bekannt ist. Sie hat folgende Syntax:

for (AUSRUCK1; AUSDRUCK2; AUSDRUCK3)
   ANWEISUNG;

AUSDRUCK1 wird vor dem Eintritt in die Schleife ausgewertet und initialisiert i.d.R. einen Schleifenzähler. AUSDRUCK2 bestimmt das Abbruchkriterium und ist üblicherweise ein vergleichender Ausdruck. Ergibt die Auswertung von AUSDRUCK2 false, wird die Schleife beendet. AUSDRUCK3 wird nach dem Ausführen der Schleifenaktion ANWEISUNG ausgewertet; er inkrementiert bzw. dekrementiert für gewöhnlich den Schleifenzähler. Alle 3 Ausdrücke sind optional. So erzeugt eine for-Schleife ohne Abbruchkriterium eine Endlosschleife.

Die Schleifenaktion ANWEISUNG besteht standardmäßig aus einer Anweisung. Sollen mehrere Anweisungen in der Schleife ausgeführt werden, sind die Anweisungen in einem Block {...} einzuschließen.

for (int index=0; index<5; index++)
{
   auto res = index * 10;
   std::cout << res << '\n';
}

#include <iostream>
#include <format>

int main()
{
   // Einzulesendes Datum
   short val;
   // Wert einlesen, dessen Faktualtaet berechnet werden soll
   std::cout << "Wert eingeben (1...20): ";
   std::cin >> val;
   // Unzulaessige Eingabe abfangen
   if ((val<1) || (val>20))
   {
     std::cout << "Nur Werte zwischen 1...20 zulaessig!\n";
   }
   else
   {
      // Ergebnis vorbelegen
      unsigned long erg = 1UL;
      // Fakultaet berechnen 1*2*3..*val;
      for (int index=1; index<=val; index++)
         erg *= index;
      // Und Ergebnis ausgeben
      std::cout << std::format("Fakultaet von {} ist {}\n",val,erg);
   }
}

while-Schleife

Die while-Schleife wird in erster Linie eingesetzt, wenn sich die Abbruchbedingung für die Schleife erst während eines Schleifendurchlaufs ergibt. Sie hat folgende Syntax:

while (AUSDRUCK)
   ANWEISUNG;

Die Schleife wird solange durchlaufen, wie die Auswertung von AUSDRUCK true ergibt. Und auch hier besteht die Schleifenaktion ANWEISUNG standardmäßig nur aus einer Anweisung. Mehrere Anweisungen sind ebenfalls in einem Block {...} einzuschließen.

auto done = false;
while(!done)
{
   // hier done irgendwann auf true setzen
}

#include <iostream>
#include <format>
// Header-Dateien fuer den Zufallszahlengenerator
#include <cstdlib>
#include <ctime>

int main()
{
   // Zufallszahlengenerator initialisieren
   std::srand(std::time(nullptr));
   // Zufallszahl erzeugen und auf den Bereich
   // 1..20 begrenzen
   const unsigned int MAXWERT = 20;
   unsigned int zahl = rand()%MAXWERT + 1;
   // Merker, ob gesuchte Zahl gefunden wurde
   bool found=false;
   // Anzahl der maximalen und des aktuellen Versuchs
   const unsigned int MAXVERSUCHE = 4;
   unsigned int aktVersuche = 1;
   std::cout << std::format("Raten Sie eine Zahl zwischen 1...{}\n"
                "Sie haben dazu maximal {} Versuche\n", MAXWERT,MAXVERSUCHE);
   // Rateschleife, wird beendet wenn gesuchte Zahl
   // gefunden wurde (found=true) oder die maximale
   // Anzahl der Rateversuche erreicht ist (MAXVERSUCHE>=aktVersuche)
   while(!found && (MAXVERSUCHE>=aktVersuche))
   {
      // Einzulesende Zahl
      unsigned int wert;
      // Zahl einlesen
      std::cout << std::format("{}. Versuch: ",aktVersuche);
      std::cin >> wert;
      // Eingabe pruefen ob zulassig
      if ((wert<1) || (wert>MAXWERT))
         std::cout << "Eingabe ausserhalb des erlaubten Wertebereichs!\n";
      else
      {
         // Falls Zahl gefunden, Schleife beenden (found=true)
         if (wert==zahl)
         {
            std::cout << "Sie haben die gesuchte Zahl gefunden!\n";
            found = true;
         }
         else
         {
            // Meldung ausgeben, ob eingegebene Zahl zu klein
            // oder zu gross ist
           std::cout << "Leider nix. Ihre Zahl war zu ";
           if (wert<zahl)
              std::cout << "klein.\n";
           else
              std::cout << "gross.\n";
           // Anzahl der Versuche inkrementieren
          aktVersuche++;
         }
       }
    }  // Ende while-Schleife
}

do-while-Schleife

Auch diese Schleife wird zumeist verwendet, wenn sich die Abbruchbedingung erst während eines Schleifendurchlaufs ergibt. Sie hat folgende Syntax:

do
   ANWEISUNG;
while (AUSDRUCK);

Auch hier wird die Schleife solange durchlaufen, wie die Auswertung von AUSDRUCK true ergibt und mehrere Anweisungen in der Schleife sind ebenfalls in einem Block {...} einzuschließen.

Der Unterschied zur vorherigen while-Schleife liegt darin, dass die Abbruchbedingung bei der while-Schleife vor dem Eintritt in die Schleife ausgewertet wird, während dies bei der do-while-Schleife erst nach einem Schleifendurchlauf erfolgt.

auto var = 0;
do
{
   // hier var irgendwann auf 10 setzen
} while(var != 10);

#include <iostream>
#include <format>

int main()
{
   int sum;           // Summe der eingegebenen Werte
   int anzWerte = 0;  // Anzahl der eingegebenen Werte
   bool done;         // Merker fuer Schleifenende
   // Einlese-Schleife
   do
   {
      int wert;      // Einzulesender Wert
      std::cout << "Bitte einen Wert eingeben (0=Ende): ";
      std::cin >> wert;
      // Fertig, wenn der Wert 0 eingegeben wurde
      done = (wert == 0);
      // Wenn nicht fertig, Wert aufaddieren und
      // Anzahl der Werte inkrementieren
      if (!done)
      {
         sum += wert;
         anzWerte++;
      }
   } while(!done);
   if (anzWerte != 0)
      std::cout << std::format("Mittelwert: {}\n",sum/anzWerte);
   else
      std::cout << "Sie haben keine Werte eingegeben!\n";
}

break und continue Anweisung

Sehen wir uns noch die restlichen zwei Anweisungen an, die bei Schleifen zum Einsatz kommen können.

Die break-Anweisung darf nur innerhalb einer Schleife oder eines case-Zweigs in der switch-Verzweigung stehen. Sie bewirkt das sofortige Verlassen der Schleife bzw. der switch-Verzweigung.

Die continue-Anweisung ist nur innerhalb einer Schleife (for, while, do-while) gültig. Sie bewirkt, dass die restlichen, auf die continue-Anweisung folgenden Anweisungen, übersprungen werden. Die Schleife selbst wird aber nicht beendet. Allerdings sollte ein gut strukturiertes Programm ohne break- oder continue-Anweisungen auskommen, mit Ausnahme des break in der switch-Verzweigung.


Copyright 2021 © Wolfgang Schröder
Impressum & Datenschutz