5. Kontrollstrukturen

5.1 Auswahl

5.1.1 "if" Anweisung

5.1.2 "switch" Anweisung

5.2 Schleifen

5.2.1 "while" Anweisung

5.2.2 "do-while" Anweisung

5.2.3 "for" Anweisung

5.3 Vorzeitiger Abbruch und Sprünge

5.3.1 "continue" Anweisung

5.3.2 "break" Anweisung

5.3.3 exit() Funktion

5.3.4 Sprünge

Kontrollstrukturen dienen dazu, ein Problem übersichtlich und strukturiert zu formulieren. Die wichtigsten Kontrollstrukturen sind die Auswahl (Entscheidungen) und die Schleifen. Dazu kommen noch einige andere Kontrollanweisungen.

5.1 Auswahl

5.1.1 "if" Anweisung

- die "if"-Anweisung dient zur Auswahl unter genau zwei Möglichkeiten

- sie hat folgenden Aufbau

if (Ausdruck)
   Anweisung(en)1
else
   Anweisung(en)2

- der else Teil ist optional, kann also auch fehlen

- hinter (Ausdruck) steht kein Semikolon

- mehrere abhängige Anweisungen müssen in geschweifte Klammern eingeschlossen werden (Blockbildung)

- Ausdruck wird, wenn es sich nicht um eine Bedingung handelt, numerisch bewertet (also gleich 0 = FALSCH und ungleich 0 = WAHR), daher sind folgende 2 if Konstruktionen äquivalent, bei der Entscheidung, welche man verwenden will, sollte man auf gute Dokumentation und leichte Lesbarkeit achten

if (i%k)
   printf("Division mit Rest\n");
if (i%k != 0)
   printf("Division mit Rest\n");

- noch 2 Beispiele zur Verwendung von if und if-else:

if (punkte > 50)
   printf ("Bestanden\n");
if (punkte > 50)
   printf ("Bestanden\n");
else
   printf ("Nicht Bestanden\n");

- es können auch else-if Ketten gebildet werden, else gehört dabei immer zum jeweils vorangehenden if, ggf. müssen daher Anweisungen mittels geschweifter Klammern zusammengefaßt werden

if (punkte > 50)
   printf("Note 1\n");
else if (punkte > 40)
   printf("Note 2\n");
else if (punkte > 30)
   printf("Note 3\n");
else if (punkte > 20)
   printf("Note 4\n");
else
   printf("Nicht Bestanden\n");

Im folgenden Programmstück steckt ein Fehler:

if (n > 0)
   for (i=0; i > n; i++)
      if (s[i] > 0) {
         printf("...");
         return (i);
      }
else     /* hier ist ein Fehler */
   printf("Fehler - n ist kleiner gleich 0\n")

Hier ist es nun richtig:

if (n > 0) {
   for (i=0; i > n; i++)
      if (s[i] > 0) {
         printf("...");
         return (i);
      }
}
else     /* jetzt ist es richtig */
   printf("Fehler - n ist kleiner gleich 0\n")

Beispielprogramm P5-1.C

binary(x,v,n)     /* binäres Suchen von x im sortierten 
                     Feld v[0] ... v[n-1] */
int x,v[],n;
{
   int low, high, mid;
   low = 0;
   high = n-1;
   while (low <= high) {
      mid = (low + high) / 2;
      if (x < v[mid])
         high = mid - 1;
      else if (x > v[mid])
         low  = mid + 1;
      else      /* gefunden */
         return (mid);
   }
   return (-1);    /* Fehlerkennung */
}

5.1.2 "switch" Anweisung

Zur Mehrfachauswahl ist es anstelle von else-if Ketten oft günstiger die Kontrollstruktur, die für eine solche Mehrfachauswahl vorgesehen ist, zu verwenden. In C heißt diese Kontrollstruktur switch-case. Sie hat folgenden Aufbau:

switch (Ausdruck) {
   case Konstante1 : Anweisung(en)1
   case Konstante2 : Anweisung(en)2
   case Konstante3 : Anweisung(en)3
                .
                .
                .
   default:          Anweisung(en)
} 

- die Konstanten müssen ganzzahlig bzw. Zeichenkonstanten sein

- default ist optional und wird durchlaufen, wenn keine der anderen Bedingungen zutrifft.

- es können beliebig viele case-Teile vorhanden sein

- die Abarbeitung und Überprüfung geht vom ersten case-Teil bis zum letzten

- nach der 1. Übereinstimmung wird der gesamte Rest der switch-Anweisung durchlaufen, insbesondere auch alle Anweisungen der nachfolgenden case-Teile !!!

- daher wird man normalerweise immer eine break-Anweisung am Ende eines case-Teils verwenden

- hier ist noch einmal das Beispiel mit der else-if Kette von oben, jetzt aber mittels switch gelöst:

punkte = ((punkte-1)/10)*10;  /* erzeugt: 0, 10, 20, 30 .. */
switch (punkte) {
   case 50: 
      printf("Note 1\n");
      break;
   case 40: 
      printf("Note 2\n");
      break;
   case 30: 
      printf("Note 3\n");
      break;
   case 20: 
      printf("Note 4\n");
      break;
   default: 
      printf("Nicht bestanden\n");
} 

Beispielprogramm P5-2.C

main()       /* ein Menuegeruest */
{
int c;
printf("     HAUPTMENUE\n\n");
printf("A    Assembler\n");
printf("C    C-Compiler\n");
printf("D    DBASE III\n");
printf("T    Turbo-PASCAL\n");
printf("\nBitte geben Sie Ihre Wahl ein: ");
switch (c=getchar()) {
   case 'a': 
   case 'A': 
      printf("\nSie haben Assembler gewählt\n");
      break;
   case 'c': 
   case 'C': 
      printf("\nSie haben den C-Compiler gewählt\n");
      break;
   case 'd': 
   case 'D': 
      printf("\nSie haben DBASE III gewählt\n");
      break;
   case 't': 
   case 'T': 
      printf("\nSie haben Turbo-PASCAL gewählt\n");
      break;
   default:
      printf("\nFalsche Wahl !!! \07\n");
} 
}

zurück zum Inhaltsverzeichnis

5.2 Schleifen

5.2.1 "while" Anweisung

- die while-Anweisung realisiert eine Schleife in der meist benötigten Art mit der Prüfung der Schleifenbedingung vor jedem (auch dem ersten) Schleifendurchlauf

- sie sieht so aus:

while (Ausdruck) 
   Anweisung(en)

- die Schleife wird solange wiederholt, wie der Ausdruck WAHR d.h. ungleich 0 ist

- eine (so natürlich nicht sinnvolle) unendliche Schleife wäre:

while(1) 
   Anweisung(en)

Beispiele für die Verwendung von while-Schleifen:

int c;
while ((c=getchar()) != EOF) 
   printf("Zeichen war nicht EOF %c\n",c);
printf("Zeichen war EOF\n");
int c;
char s[80];
i=0;
while ((c=getchar()) != EOF && i < 80-1) {
   s[i]=c;           /* oder: s[i++]=c;   das erspart
   i++;                 die geschweiften Klammern */
} 
s[i]='\0';

5.2.2 "do-while" Anweisung

- die do-while Schleife überprüft die Schleifenbedingung nach jedem einzelnen Schleifendurchlauf

- eine solche Schleife wird also immer mindestens einmal durchlaufen

- dieser Anwendungsfall ist selten im Vergleich mit der while-Schleife (nur etwa 5% der Schleifen sind do-while-Schleifen)

- die Struktur der "do-while" Anweisung ist wie folgt:

do
   Anweisung(en)
while (Ausdruck) ;

- beachten Sie das Semikolon

Beispiel:

main()     /* "Lobmaschine" */
{
int c;
do {
   printf("\nDas hast Du prima gemacht !");
   printf("\nNochmal wiederholen (J/N) ?");
   c=getchar(); }
while (c=='j' || c=='J') ;
}

5.2.3 "for" Anweisung

- eine in C sehr häufig verwendete Schleife ist die for-Schleife

- sie entspricht einer while-Schleife mit Initialisierung und Abschlußanweisung(en)

- die Struktur der Anweisung sieht so aus:

for (Ausdruck1; Ausdruck2; Ausdruck3) 
   Anweisung(en)

- Ausdruck1 stellt die Initialisierung dar, er wird nur einmal vor dem ersten Schleifendurchlauf abgearbeitet

- Ausdruck2 ist die Schleifenbedingung, die vor jedem Schleifendurchlauf bewertet wird

- Ausdruck3 ist die Reinitialisierung der Schleife, er wird am Ende der Schleife unmittelbar vor der Bewertung der Bedingung ausgeführt

- jeder der 3 Ausdrücke kann fehlen, der Weglasswert für den Ausdruck2 ist WAHR!

- Ausdrücke können auch Ausdruckslisten (Kommaoperator) sein

- äquivalent zur for-Schleife ist folgende Konstruktion mit while:

Ausdruck1;
while(Ausdruck2) {
   Anweisung(en)
   Ausdruck3;
}

- die folgende for-Anweisung realisiert eine unendliche Schleife:

for (;;)
   Anweisung(en)

- die übliche Schleife für die Abarbeitung eines eindimensionalen Feldes (Vektor) sieht so aus:

for (i=0; i<N; i++) 

- rückwärts:

for (i=N-1; i>=0; i--) 

Beispielprogramm P5-3.C (siehe auch P4-8.C)

atoi(s)     /* Ziffern der Zeichenkette s in int wandeln */
char s[];
{
   int i,n,sign;
   for (i=0; s[i]==' ' || s[i]=='\n' || s[i]=='\t'; i++) 
      ;     /* führende Zwischenräume überlesen */
   sign = 1;
   if (s[i]=='+' || s[i]=='-')     /* Vorzeichen */
      sign = (s[i++]=='+') ? 1 : -1;
   for (n=0; s[i] >='0' && s[i] <='9'; i++) 
      n = 10*n + s[i] - '0';
   return (sign*n);
}

Beispielprogramm P5-4.C

shell(v,n)   /* Shell Sort (aufsteigend) für den Vektor v */
int v[],n;
{
   int gap, i, j, temp;
   for (gap=n/2; gap > 0; gap /=2) 
      for (i=gap; i<n; i++) 
         for (j=i-gap; j>=0 && v[j]>v[j+gap]; j-=gap) {
            temp = v[j];
            v[j] = v[j+gap];
            v[j+gap] = temp;
         } 
}

Beispielprogramm P5-5.C

reverse(s)     /* Vektor s umkehren */
char s[];
{
   int c, i, j;
   for (i=0,j=strlen(s)-1; i<j; i++,j--) {
      c    = s[i];
      s[i] = s[j];
      s[j] = c;
   } 
}

zurück zum Inhaltsverzeichnis

5.3 Vorzeitiger Abbruch und Sprünge

5.3.1 "continue" Anweisung

- dient zum vorzeitigen Abbruch eines Schleifendurchlaufes der innersten while-, do-while- oder for-Schleife

- bei while und do-while wird dann sofort die Schleifenbedingung geprüft, bei for wird die Reinitialisierung vorgenommen

- die "continue" Anweisung ist für C nicht unbedingt notwendig, ihre Wirkung kann immer auch ohne continue durch eine andere Schachtelung erreicht werden

Beispiel:

/* mit continue */
for (i=0; i<N; i++) {
   if (a[i] < 0)     /* negative Elemente überspringen */
      continue;
   ...               /* nicht negative Elemente bearbeiten */
}
/* ohne continue */
for (i=0; i<N; i++) {
   if (a[i] > 0) {   /* negative Elemente überspringen */
   ...               /* nicht negative Elemente bearbeiten */
   }
}

5.3.2 "break" Anweisung

- diese Anweisung haben wir schon im Zusammenhang mit der switch-Anweisung kennengelernt

- sie dient zum Verlassen der innersten while-, do-while- oder for-Schleife, bzw. der switch-Anweisung

Beispielprogramm P5-6.C

#define MAXLINE 1000
main()     /* entfernt Zwischenraeume am Zeilenende */
{
int n;
char line[MAXLINE];
while ((n=getline(line,MAXLINE)) > 0) {
   while (--n >= 0)
      if (line[n] != ' ' && line[n] != '\t'
          && line[n] != '\n')
         break;
   line[n+1] = '\0';
   printf("%s\n",line);
}
}

5.3.3 exit() Funktion

- die exit() Funktion dient zum Verlassen (Beenden) des gesamten Programmes

- sie hat die Form:

exit (Parameter) ;

- Parameter muß vom Typ int sein, der Zahlenwert wird vom Betriebssystem bzw. allgemeiner vom Vaterprozeß ausgewertet (bei MS-DOS mit ERRORLEVEL)

- es gilt die Konvention: Parameter = 0 ==> Programmlauf okay, sonst Parameter gleich Fehlernummer

Beispielprogramm P5-7.C

main()     /* Ja-Nein Abfrage */
{
int c;
printf("\nWeitermachen (J/N) ? ");
c = getchar();
if (c=='j' || c=='J')
   exit(0);
else
   exit(1);
}

5.3.4 Sprünge

- in seltenen Fällen kann es angebracht sein, Sprünge zu verwenden

- C stellt dazu eine Sprunganweisung zur Verfügung:

goto  marke;         oder            marke: 
   .                                        .
   .                                        .
   .                                        .
marke:                               goto  marke;

- marke ist ein frei gewählter Name

- das Sprungziel muß sich in derselben Funktion wie die Sprunganweisung befinden

- vor jeder Anweisung dürfen beliebig viele Sprungmarken stehen

- Sprünge sollten vermieden werden !!!

zurück zum Inhaltsverzeichnis