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.
- 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 */
}
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");
}
}
- 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';
- 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') ;
}
- 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;
}
}
5.3 Vorzeitiger Abbruch und Sprünge
- 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 */
}
}
- 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);
}
}
- 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);
}
- 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 !!!