Twitter und Facebook-Anbindung
X
Tweet Follow @twitterapi
!!! Anbindung an twitter und facebook öffnen !!!

Wenn Ihnen mein Online-Buch gefällt,
dann bedanken Sie sich doch mit einer kleinen Spende...

3 Entscheidungen

3 Entscheidungen

Eine Programmiersprache bringt einem nicht viel, wenn man keine Fallunterscheidungen treffen kann. Dafür stehen in C und C++ zwei Mechanismen zur Verfügung. Zum einen die if Anweisung, bei der ein einfaches "Entweder oder ansonsten" reicht oder die switch Anweisung für eine komplexe Fallunterscheidung.

Bedingungen können zum einen boolesche Variablen und Integer (0 = false, alles andere true) sein oder logische Ausdrücke. Es gibt folgende Vergleichsoperatoren:

Bedingungen können auch logisch miteinander verknüpft werden. Dafür stehen folgende Operatoren zur Verfügung:

Leider gibt es in C und C++ kein XOR, also das entweder oder aus dem Sprachgebrauch, welches verlangt, dass eines von beiden zutreffen muss, aber nicht beide. Dies kann aber durch geschickte Kombination erreicht werden.

(Ausdruck 1 oder Ausdruck 2) und (Ausdruck 1 ungleich Ausdruck 2)
(a || b) && (a != b)

Die Klammersetzung ist hier ganz entscheidend, da das UND (vergleichbar mit einer Multiplikation) stärker bindet als das ODER (vergleichbar mit der Addition). Das Negationszeichen besitzt die stärkste Bindung und wirkt sich ohne Klammern nur auf den Ausdruck aus, vor welchem es steht.

Wie Sie in den Tabellen eben sehen konnten, besitzen auch Zahlen einen booleschen Wert, wobei nur die 0 als falsch und alle anderen Zahlen, auch negative, als wahr interpretiert werden.

Zum Seitenanfang
Zum Inhaltsverzeichnis

3.3 Das switch case Statement

3.3 Das switch case Statement

Möchte man eine komplexere Fallunterscheidung treffen, ist die switch Anweisung geeigneter und wesentlich übersichtlicher, da man nicht so viele if Anweisungen ineinander zu verschachteln braucht.

Das Schema sieht so aus: switch (<Ganzzahlausdruck>) { (case <Ganzzahlkonstante>: [<Anweisung> ... [break]]) ... [default: <Anweisung> ...] }

Zudem gibt es die Möglichkeit, einen Standardfall, den "default" zu definieren. Er ist optional und verhält sich wie ein Else-Block. Er wird ausgeführt, wenn keine der Fälle zutrifft.

Strukturgramm einer Switch-Anweisung

Allerdings gibt es da zwei Sachen, die Sie beachten sollte. Man kann erstens nur eine Unterscheidung von ganzen Zahlen oder einzelnen Zeichen machen und zweitens sollte jede Fallunterscheidung mit einer "break" Anweisung abgeschlossen werden, da ansonsten der nächste Fall auch ausgeführt wird. Dies kann sogar manchmal gewollt sein, ist aber dennoch die häufigste Fehlerursache bei Anfängern, die sich wundern, warum mehr passiert als gewollt. Im Nachstehendem PAP habe ich dieses Verhalten einmal aufgezeigt.

PAP einer switch Anweisung (mit und ohne "break")

Nachstehend sehen Sie zwei Quelltexte, in welchen ich den Umgang mit der switch Anweisung demonstriere. Ersteres benutzt die "break" Anweisung und letzteres nicht.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
					
int iZahl	= 0;

// Je nachdem, welche Zahl vorliegt
switch (iZahl) {
	case 0:	// da hier kein break steht, wird case 1 benutzt
	case 1:	// da hier kein break steht, wird case 2 benutzt
	case 2:	// da hier kein break steht, wird case 3 benutzt
	case 3:	// iZahl = 3
		printf("iZahl ist kleiner gleich 3");
		break;
		
	case 10:	
		printf("iZahl = 10");
		break;
		
	default:
		printf("iZahl ist weder kleiner 0, noch kleiner gleich 3, noch 10");
		// break braucht hier nicht zu stehen, da nach default nichts mehr kommen darf
} // end of switch
					

Ausgabe:

iZahl ist kleiner gleich 3
		

oder

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
					
int iBasis			= 5;
int iExponent			= 3;
int iErgebnis			= 1;

// Je nachdem, welche Zahl vorliegt
switch (iExponent) {
	case 5:
		iErgebnis	*= iBasis;
	case 4:
		iErgebnis	*= iBasis;
	case 3:
		iErgebnis	*= iBasis;
	case 2:
		iErgebnis	*= iBasis;
	case 1:
		iErgebnis	*= iBasis;
} // end of switch

printf("iErgebnis = %i", iErgebnis);
					

Ausgabe:

iErgebnis = 125
		

Wie Sie an der letzten Ausgabe sehen, habe ich hier gezielt den Effekt genutzt, dass die anderen Fälle durchlaufen werden, denn sonst würde nicht 125 ausgegeben werden, sondern 5. Ein sinnvoller Anwendungsfall für ein solches Verhalten wäre z.B. eine Rechtevergabe mit zunehmenden Rechten. Man prüft z.B. was für eine Art Person vorliegt und fängt dann mit der Person an, die am meisten darf und dann die, die immer weniger dürfen. Besucher dürfen z.B. nur etwas lesen, interne Mitarbeiter etwas lesen und umbenennen und nur der Chef darf alles, also lesen, umbenennen und löschen. Ist der Fall Chef der erste, bekommt er sein Sonderrecht + das Recht des Mitarbeiters und noch das Recht des Besuchers.

Zum Seitenanfang
Zum Inhaltsverzeichnis

3.1 Das if else Statement

3.1 Das if else Statement

Die if Anweisung ist der einfachste Weg, um zu Prüfen, ob etwas zutrifft. Ist dem so, wird der Nachstehende Befehl ausgeführt. Optional kann man auch einen Else-Block definieren, der ausgeführt wird, wenn die Bedingung nicht zutrifft. Der Befehl für das Zutreffen der Bedingung muss immer vorhanden sein. Falls man mehr wie einen Befehl ausführen will, muss man entsprechende Befehle mittels geschweifter Klammern zu einem Block zusammen fassen. Jener Block stellt dann quasi ein Befehl dar. Aus Gründen der Übersichtlichkeit, benutze ich immer geschweifte Klammern, auch wenn ich nur einen Befehl ausführen will.

Strukturgramm der if Anweisung

Links im Strukturgramm sehen Sie eine if Anweisung ohne und rechts mit else Block.

Programmablaufplan einer if Anweisung

Links im Programmablaufplan (PAP) sehen Sie eine if Anweisung ohne und rechts mit else Block

Das Schema sieht so aus: if (<Bedingungen>) <Anweisung> [else <Anweisung>]

Hier mal ein ganz kleines Beispiel, welches entscheidet, ob eine Zahl größer als 5 ist oder nicht.

 1
 2
 3
 4
 5
 6
 7
 					
int iZahl = 10;

if (iZahl > 5) {
	// iZahl ist > 5.
} else {
	// iZahl ist <= 5.
} // end of if
					

Gerade für Anfänger empfiehlt es sich allerdings, die geschweiften Klammern in eine extra Zeile zu schreiben, da man so schneller erkennen kann, wo evtl. eine Klammer vergessen wurde. Dies sieht dann für obiges Beispiel wie folgt aus.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 					
int iZahl = 10;

if (iZahl > 5)
{
	// iZahl ist > 5.
}
else
{
	// iZahl ist <= 5.
} // end of if
					

Aus Gründen der Platzersparnis, werde ich im weiteren Verlauf dieses Tutorials, die platzsparende Schreibweise benutzen. Sie sollten für Sich selbst entscheiden, welche Schreibweise Sie angenehmer finden und diese dann konsequent anwenden. Wenn Sie sich aber angewöhnen, erst "if ( ) { }" zu schreiben und anschließend etwas in die Klammern packen, gehen Sie von Anfang an fehlenden Klammern aus dem Weg und Sie können getrost die gekürzte Schreibweise verwenden. Das ist wie gesagt Geschmackssache. Viel wichtiger ist allerdings, dass Sie wirklich innerhalb der geschweiften Klammern einrücken, wie Sie das an den Kommentaren sehen können.

Wenn man Bedingungen angibt, das trifft auch später auf die Schleifen zu, muss man nicht zwangsläufig zwei Variablen/Werte miteinander vergleichen. Mann muss nur dafür sorgen, dass der Ausdruck entweder wahr oder falsch ist. Man kann genauso gut eine boolesche Variable angeben bzw. eine Funktion aufrufen, welche einen solchen Wert zurück gibt oder auch nur schlicht eine Zahl (ist der Wert 0, wird dies als "false" angesehen, wobei jeder andere Wert als "true" interpretiert wird).

Nun habe ich mir auch angewöhnt, hinter die letzte geschlossene geschweifte Klammer noch den Kommentar "end of if" zu schreiben. Dies ist auf keinen Fall notwendig. Es dient mir nur dazu, zu erkennen, was genau die geschlossene Klammer beendet. Wenn ich Ihnen dann noch Schleifen zeige und dann darin noch if Anweisungen einbaue, welche wiederum Schleifen beinhalten, verliert man schnell den Überblick. Ein Kommentar kann dann sehr hilfreich sein. Nun könnten Sie noch berechtigt einwerfen, dass ich eigentlich hätte "end of else" schreiben müssen. Nun, dies kann man machen, aber der Kommentar soll weniger sagen, dass hier das Else zu Ende ist, als dass der ganze Block zu Ende ist. Wie oder ob Sie das überhaupt machen, ist auch wieder Geschmackssache. In meiner jahrelangen Erfahrung als Programmierer, hat sich allerdings dieser Stiel für mich am günstigsten heraus kristallisiert.

An dieser Stelle möchte ich Ihnen aber noch erklären, warum man überhaupt diese geschweiften Klammern setzen muss. Normalerweise kann der Compiler nicht wissen, wann eine if Anweisung zu Ende ist. Im Fall des ersten Blockes mag dies vielleicht nochg ehen, da man ja ein "else" hat, welches als klare Abtrennung fungieren könnte. Nun muss es aber zum einen keinen "else" Zweig geben und zum anderen muss man ja auch das Ende des "else" Zweiges signalisieren. Spätestens jetzt sollte klar sein, warum Sie die geschweiften Klammern setzen müssen. Aber es gibt auch Fälle, in welchen man auf sie verzichten kann. Immer dann, wenn ein Block nur aus einer Anweisung besteht, können die Klammern weggelassen werden und dann kann man wieder etwas Platz sparen, was folgender Quelltext demonstrieren soll.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
					
int	iZahl1				= 50;
int	iZahl2				= 50;
bool	bAllesOk			= true;

// Wenn iZahl1 kleiner oder größer ist als iZahl2
if ((iZahl1 < iZahl2) || (iZahl1 > iZahl2))
	if (iZahl1 < iZahl2)
	 	printf("%i < %i", iZahl1, iZahl2);
	else
		// Wenn sie erst gleich waren dürfen sie nicht auf einmal gleich sein
		if (iZahl1 == iZahl2)
			bAllesOk	= false;
		else
			printf("%i > %i", iZahl1, iZahl2);
else
	printf("Beide Zahlen sind gleich");

// Wenn ein Fehler aufgetreten ist
if (!bAllesOk)
	printf("!!! Etwas ist schief gelaufen !!!");
					

Der erfahrene C Programmierer geht sogar noch einen Schritt weiter und kürzt selbst dies noch weiter, in dem er die Anweisungen gleich hinter das "if" bzw. "else" schreibt. Dies sieht dann folgendermaßen aus.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
					
int	iZahl1				= 50;
int	iZahl2				= 50;
bool	bAllesOk			= true;

// Wenn iZahl1 kleiner oder größer ist als iZahl2
if ((iZahl1 < iZahl2) || (iZahl1 > iZahl2))
	if (iZahl1 < iZahl2)		printf("%i < %i", iZahl1, iZahl2);
	else	if (iZahl1 == iZahl2)	bAllesOk	= false;
		else			printf("%i > %i", iZahl1, iZahl2);
else					printf("Beide Zahlen sind gleich");

// Wenn ein Fehler aufgetreten ist
if (!bAllesOk)				printf("!!! Etwas ist schief gelaufen !!!");
					

Sie sehen also, dass man in C viele Sachen geschickt kürzen kann. Statt 25 Zeilen, benötige ich im ersten Schritt nur noch 20 und im zweiten Schritt sogar nur noch 13 Zeilen. Allerdings erkaufe ich mir diese Platzersparnis durch die Tatsache, dass der Quelltext weit komplizierter zu verstehen ist, weshalb ich Ihnen dringend ans Herz lege, auf solche Kürzungen so weit wie möglich zu verzichten. Erst wenn Sie die Sprache C sicher beherrschen, können Sie anfangen, auf solche Tricks zurückzugreifen und dann ist es auch extrem wichtig, auf den Stil zu achten (gerade die Einrückungen sind extrem wichtig).

Zum Seitenanfang
Zum Inhaltsverzeichnis

3.4 Übungsaufgaben II

3.4 Übungsaufgaben II

  1. Lassen Sie vom Benutzer eine Zahl einlesen und geben Sie nur die Zahl aus, wenn sie kleiner als 10 ist.
  2. Lassen Sie vom Benutzer zwei Zahlen eingeben und prüfen Sie, ob die erste Zahl kleiner ist als die zweite. Ist dem so, Soll "Ja" ausgegeben werden und ansonsten soll der Benutzer darauf hingewiesen werden, dass die erste Zahl größer ist als die zweite.
  3. Erweitern Sie auf Aufgabe 2 so ab, dass noch eine dritte Zahl durch den Benutzer eingelesen wird. Falls die erste Zahl kleiner ist als die zweite, soll geprüft werden, ob die dritte Zahl zwischen der ersten und zweiten liegt. Ist dem so, geben Sie die dritte Zahl aus, ansonsten soll darauf hingewiesen werden, dass die Zahl nicht im Bereich liegt.
  4. Lassen Sie vom Benutzer zwei Zahlen eingeben und geben Sie die größere von beiden aus.
  5. Erweitern Sie Aufgabe 4 so, dass noch eine dritte eingelesen wird und geben Sie die größte von ihnen aus. Verschachteln Sie dafür die if Anweisungen.
  6. Lassen sie vom Benutzer eine Gleitkommazahl eingeben. Sorgen Sie dafür, dass die Zahl nachträglich positiv ist und geben sie den Wert aus. Benutzen Sie dafür den "?" Operator.
  7. Lassen Sie vom Benutzer eine vorzeichenlose Ganzzahl einlesen. Ist der Wert 0, soll "NULL" ausgegeben werden. Ist der Wert 1, soll "EINS" ausgegeben werden. Ist der Wert 2, soll "ZWEI" ausgegeben werden. Genau dieses Prinziep soll noch für die Zahlen 3, 4, 5, 6, 7, 8 und 9 geschehen. Wenn der Wert größer ist, geben Sie den Wert so aus, wie er ist. Verwenden Sie die switch Anweisung.
Zum Seitenanfang
Zum Inhaltsverzeichnis

3.2 Der ? Operator

3.2 Der ? Operator

Mit dem "?" Operator kann man eine komplette if Anweisung in eine Zeile schreiben, vorausgesetzt, man will einer Variablen nur den einen oder anderen Wert zuweisen. Dieses Konstrukt lässt sich auch ineinander verschachteln. Allerdings rate ich Ihnen, zunächst die Finger von solchen Geschichten zu lassen, da man so richtig fiese Ausdrücke bauen kann, die alles andere als trivial sind. Der Vollständigkeit halber möchte ich Ihnen dieses Werkzeug aber nicht vorenthalten, da es, gerade von Profis, sehr häufig eingesetzt wird.

Das Schema sieht so aus: <Bedingungen> ? <Ausdruck> [: <Ausdruck>]

Möchte man z.B. verhindern, dass eine Variable keinen negativen Wert hat. So könnte der Quelltext wie folgt aussehen.

 1
 2
 3
					
int	iWert		= 15;
// Folgende Zeile sorgt dafür, dass iPositiv mindestens 0 ist
int	iPositiv	= (iWert >= 0)? iWert : 0;
					

Wenn man jetzt verhindern möchte, dass der Wert negativ und nicht größer als z.B. 100 ist, so sähe der Quelltext, mit verschachteltem "?" Operator, wie folgt aus.

 1
 2
 3
					
int	iWert		= 15;
// Folgende Zeile sorgt dafür, dass iPositiv immer mindestens 0 und maximal 100 ist
int	iPositiv	= (iWert < 0)? 0 : (iWert > 100)? 100 : iWert;
					

Spätestens dieser Quelltext sollte Ihnen Respekt vor diesem Operator verschaffen.

Aber der eigentliche Zweck dieses Operators ist, dass man bedingte Berechnungen bauen kann, was mit einer if Anweisung so nicht möglich ist (in Excel oder Calc darf man das). Man benutzt den Operator also nicht um Platz zu sparen.

Zum Seitenanfang
Zum Inhaltsverzeichnis

© Copyright by Thomas Weiß, 2009 - 2012