-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathkontrollstrukturen.tex
228 lines (216 loc) · 8.01 KB
/
kontrollstrukturen.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
\section{Kontrollstrukturen}
Bisher haben wir einfache Anweisungen kennen gelernt, die vom Rechner nacheinander ausgeführt werden.
Wir werden nun Kontrollstrukturen einführen, die es erlauben, den Fluss eines Programmes zu beeinflussen.
Beispielsweise kann man, in Abhängigkeit von Werten von Variablen entweder einen, oder einen anderen Block von Anweisungen ausführen.
Nehmen wir an, wir wollen den Absolutwert einer Variablen \verb|a| ausgeben.
Dafür kann man einen \verb|if-then-else| Ausdruck verwenden.
Der entsprechende Quelltext könnte so aussehen:
\begin{lstlisting}
#include <stdio.h>
int main()
{
int a = 4;
unsigned int absolutevalue = 0;
if (a > 0)
{
absolutevalue = a;
}
else
{
// falls a <= 0
absolutvalue = -a;
}
printf("Der Absolutwert von a ist %u\n", absolutevalue);
return (0);
}
\end{lstlisting}
In Abhängigkeit davon, ob \verb|a > 0| zu wahr ausgewertet wird oder nicht, wird in diesem Beispiel entweder der Codeblock nach dem \verb|if| oder der nach dem \verb|else| ausgeführt.
Im Beispiel haben wir die zwei Blöcke durch die geschweiften Klammern abgetrennt.
Das ist nur dann nicht nötig, falls der jeweilige Block aus nur einer Anweisung besteht.
Die Variable \verb|absolutevalue| is außerhalb beider Blöcke deklariert, und damit in beiden sichtbar.
Die Zuweisung, die \verb|absolutevalue| innerhalb der Blöcke bekommt ist damit auch nach Ende der Blöcke weiterhin erhalten.
Der logische Ausdruck kann prinzipiell alle Operatoren enthalten, bzw. auch verkettete Ausdrücke von Operatoren, die wir in Tabellen~\ref{vergoper} und \ref{vergoper2} zusammengestellt haben.
Da C intern einen logischen Ausdruck als ganze Zahl darstellt, bei dem $0$ falsch und $\neq 0$ wahr entspricht, kann man anstelle des logischen Ausdrucks auch einen ganzzahligen Ausdruck verwenden.
Im Allgemeinen hat das \emph{if-else} Konstrukt folgendes Aussehen:
\begin{lstlisting}{if-else Statement}
if (logischer Ausdruck)
{
// falls wahr
Anweisung1;
Anweisung2;
...;
}
else
{
// sonst
Anweisung3;
Anweisung4;
...;
}
\end{lstlisting}
Dabei kann \verb|Anweisung1| zum Beispiel auch wieder ein \emph{if-else} Ausdruck sein.
Man kann \emph{if-else} also beliebig schachteln.
Außerdem ist der \emph{else} Block optional.
Das ist nützlich, wenn man Code nur im Falle von \emph{wahr} oder nur im Falle von \emph{falsch} ausführen möchte.
Ein dem \emph{if-else} Konstrukt verwandtes Konstrukt ist das \emph{switch} Konstrukt.
Es erlaubt eine ganze Liste von Alternativen abzuarbeiten.
Im folgende Bespiel wird eine ganze Zahl von der Standardeingabe eingelesen, und zwar mit Hilfe der \verb|scanf| Funktion, die eine \verb|printf| sehr ähnliche Syntax hat.
Wir diskutieren die Details zu \verb|scanf| später.
Dann wird, in Abhängigkeit vom eingegebenen Wert eine Ausgabe auf dem Bildschirm gemacht.
\begin{lstlisting}
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
switch (n)
{
case 0:
printf("Der Eingabewert ist 0\n");
break;
case 1:
printf("Der Eingabewert ist 1\n");
case 2:
printf("Der Eingabewert ist 1 oder 2\n");
break;
case 3:
printf("Der Eingabewert ist 3\n");
break;
default:
printf("Der Eingabewert ist groesser als 3 oder kleiner als 0\n");
break;
}
return (0);
}
\end{lstlisting}
Das Konstrukt wird mit dem Schlüsselwort \verb|switch| eingeleitet.
Jede der Möglichkeiten beginnt mit dem Schlüsselwort \verb|case|, gefolgt vom möglichen Wert des Ausdruckes und einem Doppelpunkt.
Falls die entsprechende Möglichkeit realisiert ist, werden alle noch folgenden Anweisungen ausgeführt, bis ein \verb|break| Schlüsselwort kommt, oder der \verb|switch| Block zu Ende ist.
D.h., wenn $0$ eingegeben wird, wird Zeile $10$ ausgeführt.
Wenn $1$ eingegeben wird, wird Zeile $13$ und $15$ ausgeführt.
Und, wenn keines von $0,1,2,3$ eingegeben wird, also keine der Möglichkeiten passt, so wird der \verb|default| Zweig ausgeführt, und damit Zeile $21$.
Im Allgemeinen sieht das also so aus:
\begin{lstlisting}
switch (int)
{
case Wert1:
Anweisung1;
....;
break; // optional
case Wert2:
Anweisung2;
....;
break; // optional
....default : Anweisung3;
break; // optional
}
\end{lstlisting}
Eine wesentlich wichtigere Kontrollstruktur sind sogenannt \emph{for} Schleifen.
Nehmen wir an, wir möchten die ganzen Zahlen von $0$ bis $n-1$ aufsummieren.
Dann können wir das mit folgendem Quelltext machen:
\begin{lstlisting}
#include <stdio.h>
int main()
{
int n;
int summe = 0;
scanf("%d\n", &n);
if (n < 0)
{
printf("Die Eingabe muss groesser oder gleich 0 sein!\n");
return (-1);
}
for (int i = 0; i < n; ++i)
{
summe += i;
}
printf("Die Summe der Zahlen von 0 bis %d ist %d\n", n - 1, summe);
return (0);
}
\end{lstlisting}
Hierbei lesen wir zunächst den Wert von $n$ mit Hilfe von \verb|scanf| ein.
Wir erwarten eine ganze Zahl größer gleich $0$.
Damit das Programm sinnvolle Ergebnisse liefert, überprüfen wir das in den Zeilen $7-10$.
Falls $n<0$, wird eine Fehlermeldung ausgegeben und das Programm mit Hilfe von \verb|return| beendet.
Danach wird die Zeile
\begin{lstlisting}
summe += i;
\end{lstlisting}
die für $i=0,1,\ldots n-1$ nacheinander ausgeführt wird.
Diese Zeile wird also $n-1$--Mail ausgeführt, mit jeweils anderen Werten für \verb|summe| und \verb|i|.
Da \verb|summe| außerhalb der Schleife deklariert und initialisiert wurde, ist der entsprechende Wert auch nach der Schleife vergfügbar.
\verb|i| dagegen ist in diesem Beispiel nur innerhalb der Schleife verfügbar!
Allgemein sieht die \emph{for} Schleife wie folgt aus:
\begin{myalertblock}{For Schleife}
\begin{lstlisting}
for (Ausdruck1; Ausdruck2; Ausdruck3)
{
Anweisung1;
Anweisung2;
...;
}
\end{lstlisting}
\vspace{-1cm}
\begin{enumerate}
\item Zuerst wird Ausdruck1 ausgeführt.
\item Dann wird Ausdruck2 ausgeführt.
\item Wenn Ausdruck2 als wahr ausgewertet wird, werden die Anweisungen im Körper der Schleife ausgeführt.
\item Jetzt wird Ausdruck3 ausgeführt.
\item Starte wieder bei 2.
\end{enumerate}
\end{myalertblock}
Dabei ist Ausdruck1 der Deklarations- und/oder Initialisierungsschritt für die Schleifenvariable(n).
Ausdruck2 wird als logischer Ausdruck ausgewertet und stellt die Abbruchbedingung dar.
Ausdruck3 modifiziert die Schleifenvariable(n).
Interessanterweise dürfen auch alle drei Ausdrücke leer sein.
Dann wird die Schleife im Prinzip unendlich oft ausgeführt.
In einem solchen Fall kann man die Schleife mit Hilfe von \verb|break| explizit abbrechen, wie man im folgenden Beispiel sieht:
\begin{lstlisting}
#include <stdio.h>
int main()
{
int n;
int summe = 0;
int i = 0;
scanf("%d", &n);
if (n < 0)
{
printf("Die Eingabe muss groesser oder gleich 0 sein!\n");
return (-1);
}
for (;;)
{
if (i == n)
break;
summe += i;
i++;
}
printf("Die Summe der Zahlen von 0 bis %d ist %d\n", n - 1, summe);
return (0);
}
\end{lstlisting}
C kennt zwei weitere Schleifenkonstrukte, nämlich die \verb|while| und die \verb|do-while| Schleife.
Während die \verb|while| Schleife die Abbruchbedingung vor dem Ausführen des Schleifenkörpers überprüft und im Zweifel abbricht, wird bei der \verb|do-while| Schleife der Körper immer mindestens einmal ausgeführt.
Das macht den großen Unterschied zwischen den beiden aus, die im folgenden nocheinmal allgemein dargestellt sind.
\begin{myalertblock}{while Konstrukt}
\begin{lstlisting}
while (logischer Ausdruck)
{
Anweisungen;
}
\end{lstlisting}
\vspace{-0.5cm}
Die Anweisungen werden also so lange ausgeführt, wie der logische Ausdruck zu \emph{true} ausgewertet wird.
\end{myalertblock}
\begin{myalertblock}{do-while Konstrukt}
\begin{lstlisting}
do
{
Anweisungen;
}
while (logischer Ausdruck);
\end{lstlisting}
\vspace{-0.5cm}
Die Anweisungen werden so lange ausgeführt, wie der logische Ausdruck zu wahr ausgewertet wird, allerdings mindestens einmal.
\end{myalertblock}
\endinput