Dies ist eine ältere Version dieses Textes.

Die neuste Version ist auf http://www.eggdrop.ch/texts/c/index.htm verfügbar!

 

Einführung in C

Dieser Text befindet sich in der neusten Version auf http://www.eggdrop.ch/texts/c/index.htm.

14.10.03: Version 0.4
20.09.03: Version 0.3
22.08.03: Version 0.2
14.08.03: Version 0.1

Inhalt

1 Einleitung
1.1 Was ist C?
1.2 Was kann man mit C alles schreiben?
1.3 Und was ist mit C++?
1.4 Was brauche ich zum Programmieren?
1.5 Anmerkungen
2 Hallo, Welt!
2.1 Code
2.2 Funktionen
2.3 Anweisungen
2.4 Struktur eines C-Programms
2.5 Steuerzeichen
2.6 Kommentare
3 Variablen
3.1 Was sind Variablen?
3.2 Ein Variablentyp: int
3.3 Formatierte Ausgabe mit printf
3.4 Rechnen mit Operatoren
3.5 Aufgabe: Variablen
4 Entscheidungen
4.1 Eingabe mit scanf
4.2 Entscheidungen mit if und else
4.3 Entscheidungen mit switch
4.4 Der Bedingungsoperator ? :
A Lösungen zu den Übungen
A.1 Variablen

 

1 Einleitung

1.1 Was ist C?
C ist eine Programmiersprache, die Anfang der 70er Jahre von Dennis Ritchie in den Bell Labs entwickelt wurde, um das Betriebssystem UNIX unabhänging von der Hardware zu schreiben. C ist sehr mächtig, flexibel und portabel, läuft also auf fast jeder Architektur. C ist heute eine der am meisten verbreiteten Programmiersprachen. Damit C-Programme überall ohne grosse Modifikationen laufen, wurde der sogenannte ANSI-C-Standard eingeführt. ANSI-C-Programme lassen sich auf jedem ANSI-C-Compiler unverändert kompilieren.

1.2 Was kann man mit C alles schreiben?
In C ist alles möglich: Grafische Oberflächen (GUI's), Berechnungsprogramme, Datenbanken, 2D und 3D Spiele, Betriebsysteme, Simulationen, Internetanwendungen und viel mehr! Dem Programmierer sind in C keine Grenzen gesetzt.

1.3 Und was ist mit C++?
C++ ist nichts anderes als ein erweitertes C. Alles was in C erlaubt ist geht auch mit C++. C++ enthält Zusätzliches für die objektorientierte Programmierung und ist somit etwas komplizierter als C. Wer C kann, kann ohne weiteres C++ lernen.

1.4 Was brauche ich zum Programmieren?
Zuerst braucht man einen Editor, wo man den C-Code eingeben kann. Theoretisch ist jeder Editor möglich, empfehlenswert ist aber einer, der den C-Code farbig hervorhebt. Ich persönlich benutze den Unix-Editor vim, der mit dem Befehl :syntax on den C-Code hervorhebt und auch automatisch einrückt. Wenn man einen Editor hat, benötigt man einen C-Compiler, um aus dem C-Code eine ausführbare Datei zu erstellen. C-Compiler gibt es auch genug. Ich verwende unter Linux den Compiler gcc, der meistens schon standardmässig dabei ist. Für Windows gibt es z.B. den freien Compiler lcc und mehr (in einer Suchmaschine z.B. windows c compiler eingeben). Alternativ zu einem Editor und einem Compiler kann man auch eine komplette Entwicklungsumgebung verwenden. Die bekanntesten für Windows sind Visual C++ und Borland C++ Builder. Diese unterstützen sowohl C, als auch C++. Wie man den Editor bedient und die Dateien kompiliert, erfährst du in den dazugehörigen Handbüchern usw. Für gcc-Fans sag ich doch noch schnell den Aufruf, um eine Datei zu kompilieren: gcc -o datei datei.c und Ausführen mit ./datei.

1.5 Anmerkungen
Begriffe, die du dir merken solltest, werden Kursiv gekennzeichnet.

 

2 Hallo, Welt!

2.1 Code
Wir fangen gleich mit einem einfachen Programm an. Das Programm soll uns die Zeichenfolge "Hallo Welt" auf den Bildschirm ausgeben. Hier schon mal der Quellcode:

#include <stdio.h>

int main(int argc, char *argv[])
{
        printf("Hallo, Welt!\n");
        return 0;
}

Tippe den Quellcode in deinen Editor bzw. deine Entwicklungsumgebung ein und speichere ihn z.b. unter hello.c. C-Dateien haben grundsätzlich die Dateiendung .c. Kompilier das Programm und führe es aus (unter Windows in einer DOS-Box). Wenn sich das Programm nicht kompilieren lässt, dann überprüf noch einmal den Quellcode auf Schreibfehler: z.B. vergessene Abstände oder Semikola (;) usw. Beachte auch, dass C Gross- und Kleinschreibung unterscheidet. Ich werde das Programm nun in den nächsten Abschnitten beschreiben. Die nächsten zwei Abschnitte sind wahrscheinlich die schwierigsten und die wichtigsten in diesem Kapitel. Also nicht sofort aufgeben, lieber mehrere Male lesen!

2.2 Funktionen
Wir fangen mit der Zeile int main(int argc, char *argv[]) an. Diese Zeile definiert eine Funktion. Die Befehle der Funktion werden in den geschweiften Klammern { und } - man nennt das Block oder Anweisungsblock - geschrieben. Jede Funktion hat einen Rückgabewert, der mit return zurückgegeben wird. Der Rückgabewert ist jedoch im Moment nicht sehr wichtig. Nimm einfach mal an, dass der Rückgabewert die Funktion verlässt und hier also das Programm beendet (weil das hier ja die einzige Funktion ist). Eine Funktion sieht so aus:

Typ Name(Argumente)
{
        Befehle;
        return Wert;
}

Typ: Das ist der Typ des Rückgabewerts. main gibt immer den Typ int zurück. int-Werte sind ganze Zahlen. Auf diese Datentypen werde ich später noch zurückkommen.

Name: Wir sehen hier, dass der Name unserer Funktion main ist. Diese Funktion wird beim Aufrufen des Programms immer zuerst aufgerufen. Man kann beliebig viele andere Funktionen mit (fast) beliebigen Namen machen. Diese Funktionen kann man dann aus der Funktion main oder aus anderen Funktionen aufrufen.

Argumente: Jede Funktion kann Argumente haben. Die Argumente werden durch Kommas voneinander getrennt. Die Funktion main hat die Argumente int argc und char *argv[]. Eigene Funktionen können eigene Argumente haben. Auf die Argumente von Funktionen wird aber erst später eingegangen.

Befehle: Hier kommt der eigentliche Code der Funktion hin.

Wert: Das ist jetzt eben Rückgabewert. In der Funktion main verwendet man immer den Rückgabewert 0 (Null), wenn das Programm korrekt beendet wurde. Bei einem Fehler verwendet man meistens 1. Normalerweise wird dieser Rückgabewert nicht weiter vom Betriebssystem beachtet. Er kann aber nützlich sein, wenn man das Programm von anderen Programmen aus startet und dann wissen muss, ob das Programm einen Fehler verursacht hat oder nicht. Momentan werden wir uns aber nicht weiter mit diesem Rückgabewert den Kopf zerbrechen.

2.3 Anweisungen
Im Anweisungsblock der Funktion main befinden sich folgende Anweisungen:

printf("Hallo, Welt!\n");
return 0;

Hier möchte ich festhalten, dass jede Anweisung mit einem Semikolon (;) endet. Ausnahme bilden die Anweisungen, denen ein Adressblock folgt. Doch zu denen später mehr. Das vergessene Semikolon ist einer der häufigsten Fehler von C-Programmierern. Die Anweisung return kennen wir ja bereits schon. Sie gibt den Rückgabewert der Funktion zurück. Ausserdem sollte man wissen, dass sie eventuelle Anweisungen danach nicht mehr ausführen wird. Im folgenden Beispiel würde der Text "Hallo Welt" nicht ausgegeben werden:

#include <stdio.h>

int main(int argc, char *argv[])
{
        return 0;
        printf("Hallo, Welt!\n");
}

Nun zur Anweisung printf. Sie ähnelt ein bisschem einem Funktionskopf, da hinter dem Namen runde Klammern sind - genau wie bei einer Funktion auch. Sie hat aber ein Semikolon am Schluss und befindet sich innerhalb einer Funktion (es gibt keine verschachtelten Funktionen innerhalb von Funktionen). Es ist ein Funktionsaufruf. Diese Anweisung ruft die Funktion printf auf mit dem Argument "Hallo, Welt!\n" auf. Nun, wo befindet sich diese Funktion? Wir haben im Code keine Funktion mit dem Namen printf. Lösung: Sie befindet sich in der Datei stdio.h (genauer gesagt, sie befindet sich in der C-Library, die während dem Kompilieren automatisch mitgelinkt wird; in stdio.h befindet sich nur der sogenannte Prototyp der Funktion; ich möchte dich nicht damit verwirren, denn das war nur vollständigkeitshalber zu erwähnen) . Diese Datei wird mit dem Compiler mitgeliefert. Und die erste Zeile (#include <stdio.h>) bewirkt, dass diese Datei mit eingebunden wird. Diese Zeile nennt man Präprozessordirektive. Man erkennt eine Präprozessordirektive daran, dass sie mit einem # beginnt. Vor dem Kompilieren werden diese Befehle durch den Präprozessor abgearbeitet und dann zum eigentlichen C-Compiler geschickt. Die Anweisung #include wird durch den Inhalt der angegebenen Datei ersetzt. Wird der Dateiname bei #include in spitzen Klammern (< und >) angegeben, dann wird im sogenannten Include-Verzeichnis vom Compiler diese Datei gesucht (das ist bei stdio.h der Fall). Wird der Name aber in Anführungszeichen angegeben (z.B. #include "test.h"), dann wird zuerst im Verzeichnis, wo sich das Programm befindet, gesucht und erst dann, wenn nichts gefunden wurde, im Include-Verzeichnis. So kann man eigene Dateien (sogenannte Header-Dateien) einbinden. Zu beachten ist, dass Header-Dateien gewöhnlich die Endung .h haben.

Der letzte Abschnitt zusammengefasst: Die Funktion printf wird mit dem Argument "Hallo Welt\n" aufgerufen. Ich denke ich muss gar nicht erklären, dass diese Funktion Text auf den Bildschirm schreibt. Der Text (eine Zeichenfolge oder String) wird in C immer in Anführungszeichen angegeben. Was ich vielleicht noch erklären muss, ist das \n am Schluss der Zeichenfolge. Das ist ein sogenanntes Steuerzeichen. Steuerzeichen beginnen immer mit einem Backslash (\). Das Steuerzeichen \n macht eine neue Zeile. Beispielsweise erzeugt printf("Dieser Text\nerstreckt\nsich\n\n über mehrere Zeilen\n"); folgende Ausgabe:

Dieser Text
erstreckt
sich

 über mehrere Zeilen

Man könnte das obere Programm auch auf mehrere printf-Anweisungen verteilen:

printf("Dieser Text\n");
printf("erstreckt\n");
printf("sich\n\n");
printf(" über mehrere Zeilen\n");

2.4 Struktur eines C-Programms
In der Programmiersprache C hat man eine grosse Freiheit in der Struktur des Programms. Das heisst, man könnte das obige Programm auch so schreiben:

#include <stdio.h>
int main(int argc,char *argv[]){printf("Hallo, Welt!\n");return 0;}

oder auch mit Leerzeichen und Tabulatoren so "aufpeppen":

                        #include         <stdio.h>
        int
main(


int argc
,
char *argv[   ]
) { printf  ("Hallo, Welt!\n"
)
;                return 0;}

Bei diesen zwei Beispielen leidet jedoch stark die Übersichtlichkeit. Also schreibe den Code am besten immer so, wie er hier geschrieben wird. Folgende Regeln muss man noch beachten:

2.5 Steuerzeichen
Hier werde ich auf die Steuerzeichen noch genauer eingehen. Wir kennen ja schon das Steuerzeichen \n, welches eine neue Zeile erzeugt.
 
Zuerst eine Tabelle der wichtigsten Steuerzeichen:

Steuerzeichen Beschreibung
\a Gibt ein akustisches Signal aus
\b Setzt den Cursor um eine Position nach links
\f Erzeugt einen Seitenvorschub beim Drucken
\n Setzt den Cursor an den Anfang der nächsten Zeile
\r Setzt den Cursor an den Anfang der aktuellen Zeile
\t Setzt den Cursor zur nächsten horizontalen Tabulatorposition. Meistens wird alle 8 Zeichen ein Tabulator gesetzt.
\v Setzt den Cursor zur nächsten vertikalen Tabulatorposition.
\" Gibt das Anführungszeichen (") aus.
\nnn Gibt ein Zeichen mit dem Oktalwert (Basis 8) nnn aus.
\xnn Gibt ein Zeichen mit dem Hexadezimalwert (Basis 16) nn aus. Folgende Ziffern werden dazu verwendet:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A (10), B (11), C (12), D (13), E (14), F (15)

Hier einige Beispiele zu den Steuerzeichen:

Gibt den Text "Ungültige Eingabe" aus und piepst:

printf("Ungültige Eingabe!\n\a");

Gibt eine Tabelle aus (am besten selber mal kompilieren):

printf("\tA\tB\tC\tD\tE\n");
printf("1\tA1\tB1\tC1\tD1\tE1\n");
printf("2\tA2\tB2\tC2\tD2\tE2\n");
printf("3\tA3\tB3\tC3\tD3\tE3\n");

Hier die Tabelle, die ausgegeben wird:

        A       B       C       D       E
1       A1      B1      C1      D1      E1
2       A2      B2      C2      D2      E2
3       A3      B3      C3      D3      E3

2.6 Kommentare
Kommentare werden vom Compiler ignoriert und dienen also nur den Programmierern, um den Code einfacher zu lesen und verstehen. Kommentare sind immer sinnvoll, vor allem bei grösseren Projekten, wenn mehrere Leute zusammenarbeiten. Durch Kommentare können auch Anfänger komplexe Programme besser verstehen. In C gibt es zwei Typen von Kommentaren:

Der C-Style Kommentar beginnt mit einem /* und endet mit einem */. Er kann sich über mehrere Zeilen erstrecken. Wenn man einmal mehrere Zeilen schnell rausnehmen will, eignet sich dieser Kommentar am besten, weil man am Anfang der ersten Zeile ein /* setzen kann und am Ende der letzten Zeile ein */. Ich bevorzuge diesen Kommentar. Achtung: Dieser Kommentartyp darf nicht verschachtelt werden. Die Zeile /* Kommentar /* FALSCH! */ */ gäbe einen Fehler

Der C++-Style Kommentar heisst C++, weil er ursprünglich nur in C++ erlaubt war. Er ist aber seit dem ANSI C99-Standard (seit 1999) auch in C erlaubt. Ältere Compiler können unter Umständen Fehlermeldungen ausgeben. Der Kommentar beginnt mit // und endet am Ende der Zeile.

Ein Kommentar ist nicht in einem String gültig.

Hier ein Beispiel mit beiden Kommentar-Typen:

/* bindet die Header-Datei stdio.h für printf ein */
#include <stdio.h>

int main(int argc, char *argv[]) // Hauptfunktion
{
        // gibt eine Zeile aus
        printf("Das ist ein Text. /* Das ist auch ein Text. */ // Das auch\n");
        // Kommentar
        // über
        // mehrere
        // Zeilen
        /* Kommentar
           über
           mehrere
           Zeilen */
} /* ende des Programms */

 

3 Variablen

3.1 Was sind Variablen?
Variablen sind in C veränderbare Speicherstellen. Man kann also den Wert einer Variable verändern (man nennt das Zuweisung) und den dann später verarbeiten und/oder wieder verändern. Eine Variable besteht aus dem Namen und dem Inhalt. In C gibt es verschiedene Typen von Variablen (sogenannte Datentypen): z.B. für Ganzzahlen, Zeichen usw. Das erstellen einer Variable nennen wir Deklaration. Wir deklarieren eine Variable, indem wir den Datentyp der Variable und den Namen der Variable mit einem Abstand getrennt angeben und die Anweisung mit einem Semikolon abschliessen:

typ name;

Der Name muss mit einem Gross- oder Kleinbuchstaben oder mit einem Unterstrich (_) beginnen und kann danach auch Zahlen beinhalten. Ich erwähne hier nochmal, dass C zwischen Gross- und Kleinschreibung unterscheidet. Also sind die Variablen name, Name und NAME alles unterschiedliche Variablen. Bei Variablen werden nur die ersten 32 Zeichen zur Unterscheidung benötigt. Das heisst, dass man Variablennamen, die länger als 32 Zeichen sind, vermeiden sollte, da sie zu Verwechslungen führen können. Ausserdem gibt es in C eine Liste sogenannter Schlüsselwörter. Diese Wörter dürfen nicht von Variablen benutzt werden.

Hier die Liste der 32 C-Schlüsselwörter:

auto      break     case      char      const     continue  default   do
double    else      enum      extern    float     for       goto      if
int       long      register  return    short     signed    sizeof    static
struct    switch    typedef   union     unsigned  void      volatile  while

Im ANSI C99-Standard wurden noch folgende zusätzliche Schlüsselwörter definiert:

inline    restrict  _Bool     _Complex  _Imaginary

Dazu gibt es noch C++ Schlüsselwörter, die den Compiler auch stören können, da die meisten Compiler sowohl C, als auch C++ beherrschen. Wenn also ein unerklärlicher Fehler bei einer Deklaration auftretet, könnte es sich um ein Schlüsselwort handeln. Ausserdem stellen einige Editoren die Schlüsselwörter mit einer anderen Farbe dar, so dass man diese schnell erkennen kann.

Gültige Variablennamen wären z.B.:

das_ist_EinTest
ABC123
_for_

Ungültige Variablennamen wären z.B.:

while (Schlüsselwort)
123zahl (Variable darf nicht mit einer Zahl anfangen)
sonder-zeichen (Bindestrich ist nicht erlaubt)

Genug der Theorie: Im nächsten Abschintt lernen wir den ersten Variablentyp kennen.

3.2 Ein Variablentyp: int
Der Datentyp int kann ganze Zahlen (also ohne Nachkommastellen) speichern. Sein Bereich geht auf 16Bit-Maschinen von -32768 bis +32767 und auf 32Bit-Maschinen von -2147483648 bis +2147483647. Wir verwenden höchstwahrscheinlich eine 32Bit-Maschine (Windows 95 bis XP sind 32Bit-Betriebssysteme). Wenn wir den Bereich überschreiten, zählt C wieder von vorne. Also +2147483648 wäre in C -2147483648. Um eine int-Variable zu deklarieren, geben wir folgendes ein:

int name;

Wenn wir diese Variable in unserem Beispielprogramm nach der printf-Anweisung versuchen zu deklarieren, bekommen wir eine Fehlermeldung (ausser es handelt sich um einen C++-Compiler).

Hier wäre das fehlerhafte Programm:

#include <stdio.h>

int main(int argc, char *argv[])
{
        printf("Hallo, Welt!\n");
        int name;
        return 0;
}

Das liegt daran, dass in C eine Variable nur am Anfang eines Anweisungsblockes deklariert werden darf. Das heisst, dass am Anfang des Blockes die Deklarationen kommen und erst dann die Anweisungen. Hier ein Beispiel-Block zur Veranschaulichung:

{
        Deklarationen
        Befehle
}

Korrekt müsste unser Programm also folgendermassen sein:

#include <stdio.h>

int main(int argc, char *argv[])
{
        /* Deklarationen */
        int name;

        /* Befehle */
        printf("Hallo, Welt!\n");
        return 0;
}

Wir können auch mehrere Variablen deklarieren:

        /* Deklarationen */
        int eins;
        int zwei;
        int drei;

Oder durch Kommas (,) getrennt in einer Anweisung:

        /* Deklarationen */
        int eins, zwei, drei;

Jetzt wollen wir den Variablen einen Wert zuweisen. Das geschieht mit dem Zuweisungsoperator "=". Die Zuweisungen gehören nicht mehr in den Abschnitt Deklarationen. Hier ein Beisipel, wie man den Variablen einen Wert zuweisen könnte:

#include <stdio.h>

int main(int argc, char *argv[])
{
        /* Deklarationen */
        int eins, zwei, drei;

        /* Befehle */
        eins = 1;
        zwei = 2;
        drei = 3;

        printf("Hallo, Welt!\n");
        return 0;
}

Übrigens nennt man das erste Zuweisen eines Werts einer Variable Initialisierung. Denn eine Variable hat nach der Deklarataion einen zufälligen, unvorhersehbaren Wert (nämlich den, der vorher an dieser Speicherstelle war). Nachdem wir die Variable initialisiert haben, hat die Variable einen vorhersehbaren Wert. Meistens initialisiert man Variablen mit 0 (Null).

Wir können Variablen auch während der Deklaration sofort initialisieren:

#include <stdio.h>

int main(int argc, char *argv[])
{
        /* Deklarationen */
        int eins = 1, zwei = 2, drei = 3;

        /* Befehle */
        printf("Hallo, Welt!\n");
        return 0;
}

Da C viel Freiheit bietet, wäre auch das möglich:

#include <stdio.h>

int main(int argc, char *argv[])
{
        /* Deklarationen */
        int eins = 1, zwei;
        int drei = 3;

        /* Befehle */
        zwei = 2;
        printf("Hallo, Welt!\n");
        return 0;
}

Den Abstand zwischen dem Gleichheitszeichen und dem Wert kann man weglassen. Genauso ist es mit dem Abstand nach dem Komma.

3.3 Formatierte Ausgabe mit printf
Nun beschäftigen wir uns genauer mit der Ausgabeanweisung printf. Bis jetzt haben wir nur einen gegebenen Text (String) ausgegeben. Nun wollen wir aber auch Variablen ausgeben können. Dazu verwenden wir auch die Anweisung printf. printf hat eine veränderbare Anzahl Argumente (siehe Kapitel 2.2). Das erste Argument bestimmt den Formatstring. Der Formatstring unterscheidet sich dadurch von einem normalen String, dass er Formatelemente enthalten kann. Formatelemente erkennt man am Prozentzeichen (%). Der Datentyp int hat das Formatelement %d. Wollen wir uns nun die drei Zahlen ausgeben lassen, müssten wir also folgendes in der printf-Anweisung angeben:

printf("eins: %d zwei: %d drei: %d\n");

Ersetzen wir also die "Hallo Welt"-Anweisung durch unsere "neue" Anweisung. Kompilieren wir jetzt das Programm und führen es aus. Eventuell gibt es Compilerwarnungen oder gar einen Fehler. Bei mir kam die folgende Ausgabe:

eins: -1073743176 zwei: 1074056984 drei: 1075023432

Das ist nicht so ganz das, was wir wollten, oder? Wir haben ja gar nicht angegeben, welche Variable er ausgeben soll. Wir haben nur das Formatelement %d als "Platzhalter" genommen. Die Lösung: Wir müssen die Variablen, die ausgegeben werden sollen als zusätzliche Argumente angeben. Und zwar in der Reihenfolge, in der die Formatelemente sind. Wir wir vielleicht noch wissen, werden die Argumente durch Kommas getrennt. Daraus ergibt sich die folgende Anweisung:

printf("eins: %d zwei: %d drei: %d\n", eins, zwei, drei);

Und siehe da, die Ausgabe stimmt:

eins: 1 zwei: 2 drei: 3

Hier zur Veranschaulichung folgende Abbildung. Die Formatelemente (%d) werden durch den Inhalt der Variablen ersetzt:

                                  ,-----------------.
                                 |                  |
                         ,-------+------------.     |
                        |        |            |     |
                ,-------+--------+------.     |     |
               |        |        |      |     |     |
              \|/      \|/      \|/     |     |     | 
printf("eins: %d zwei: %d drei: %d\n", eins, zwei, drei);

                          |
                          |
                          |
                         \|/

               eins: 1 zwei: 2 drei: 3                         

3.4 Rechnen mit Operatoren
Jetzt werden wir ein bisschen mit den Zahlen rechnen. Wir beschäftigen uns jetzt mit einigen C-Operatoren. Hier die Tabelle dieser Operatoren:

Operator Beschreibung
+ Addition
- Subtraktion
* Multiplikation
/ Division
% Modulo (Rest einer Division)

Die Anwendung dieser Operatoren ist sehr einfach in C. Man kann einer Variable einfach so einen Ausdruck (z.B. 1+1) zuweisen:

#include <stdio.h>

int main(int argc, char *argv[])
{
        int a;
        a = 1+1;
        printf("a ist %d\n", a);
        /* Ausgabe: a ist 2 */
        return 0;
}

Hier noch einige weitere Beispiele für die oben genannten Operatoren:

a = 5-3; /* a ist 2 */
a = 8*8; /* a ist 64 */
a = 6/2; /* a ist 3 */
a = 7/2; /* a ist 3 */
a = 7%2; /* a ist 1 */

Bei der zweitletzten Anweisung, werden die Nachkommastellen einfach abgeschnitten (nicht gerundet). Das liegt daran, dass der Datentyp int nur Ganzzahlen beherrscht und Nachkommastellen gar nicht beachtet. Die letzte Anweisung gibt den Rest der Division 7/2 aus, also 1.

Anstelle von Zahlen können wir aber auch Variablen verwenden:

int a,b,c;
a = 5;
b = 3
c = a + b - 2;
/* c ist 6 */

Es gibt noch Operatoren, die einen Ausdruck verkürzen. Wir können also anstelle den folgenden Anweisungen...

a = a - 2;
b = b * 5;
c = c % 6

... auch das schreiben:

a -= 2;
b *= 5;
c %= 6;

Wenn wir nun Operatoren vermischen, müssen wir auf die Priorität der Operatoren achten. Dazu folgende Vorrang-Tabelle von den Operatoren:

Priorität Operatoren
1. ()
2. * / %
3. + -
4. = += -= *= /= %=

Wie wir sehen, hat die Klammer () die erste Priorität. Wollen wir also den Vorrang von bestimmten Operatoren umgehen, setzen wir Klammern. Hier ein Beispiel mit und ohne Klammern:

a = 4 + 6 * 2   /* der Computer rechnet wie folgt: 4 + (6 * 2) = 4 + 12 = 16 */
a = (4 + 6) * 2 /* der Computer rechnet wie folgt: (4 + 6) * 2 = 10 * 2 = 20 */

3.5 Aufgabe: Variablen
Schreibe ein Programm, welches drei int-Variablen a, b und c deklariert. Weise den ersten zwei Variablen den Wert 13 und -300 zu. Die Variable c soll den Inhalt von a mit dem Inhalt von b addieren und dann mit a multiplizieren. Erhöhe anschliessend den Wert von c um 2 und gib folgenden Text mit den Anführungszeichen aus, wobei a, b und c durch den jeweiligen Inhalt ersetzt werden sollen: "a addiert mit b und multipliziert mit a gibt c". Die Lösung gibts hier.

 

4 Entscheidungen und Schleifen

4.1 Eingabe mit scanf
Bevor wir Entscheidungen treffen werden, beschäftigen wir uns kurz mit der Eingabe von Zahlen. Bis jetzt kannten wir nur den Funktionsaufuf printf, der zur Ausgabe von Text diente. Die Funktion zur Eingabe heisst scanf. Sie funktioniert ähnlich wie die Funktion printf, dient aber nur zur Eingabe.

Wollen wir zum Beispiel eine Zahl auslesen und in die Variable abc schreiben, dann benötigen wir folgenden Aufruf:

scanf("%d", &abc);

Das Formatzeichen %d sagt der Anweisung, das sie eine Zahl einlesen soll. Das komische & ist der sogenannte Adressoperator. Dieser Operator liefert die Adresse der Variablen, damit scanf auch etwas reinschreiben kann. Ich werde jedoch diesen Operator erst später ausführlich beschreiben.

Wir programmieren nun ein Programm, welches zwei Zahlen einliest, sie addiert und dann das Ergebnis ausgibt. Der Quellcode sollte verständlich und nachvollziehbar sein:

#include <stdio.h>

int main(int argc, char *argv[])
{
        /* Variablen deklarieren */
        int a=0, b=0;
        int ergebnis=0;

        /* Zahlen einlesen */
        printf("Erste Zahl eingeben:\n");
        scanf("%d", &a);
        printf("Zweite Zahl eingeben:\n");
        scanf("%d", &b);

        /* Zahlen addieren */
        ergebnis = a+b;

        /* Ergebnis ausgeben */
        printf("%d + %d = %d\n", a, b, ergebnis);

        /* Programm sauber verlassen */
        return 0;
}

4.2 Entscheidungen mit if und else
In diesem Abschnitt lassen wir das erste mal unseren Computer Entscheidungen treffen! Dies geschieht mit einer der wichtigsten C-Anweisungen, nämlich if, was soviel wie "wenn" bedeutet.So sieht ein if-Konstrukt aus:

if (Bedingung)
{
        Anweisungen
}

Die Bedingung ist ein Ausdruck, der wahr sein muss, damit die Anweisungen ausgeführt werden. Ein Ausdruck ist wahr, wenn er ungleich 0 (Null) ist und in den anderen Fällen falsch. Das heisst, dass Ausdrücke, die einen Wert unter Null haben, auch wahr sind. Bis jetzt kannten wir Ausdrücke wie 2+3 oder 15/3. Diese Ausdrücke können wir auch in if-Anweisungen verwenden, jedoch werden fast immer Vergleichsoperatoren verwendet. Diese Operatoren geben entweder den Wert 1 für wahr oder 0 für falsch zurück. Dazu die Tabelle der Vergleichsoperatoren:

Operator Bedeutung
a < b kleiner: wahr, wenn a kleiner als b
a <= b kleiner gleich: wahr, wenn a kleiner oder gleich b
a > b grösser: wahr, wenn a grösser als b
a >= b grösser gleich: wahr, wenn a grösser oder gleich b
a == b gleich: wahr, wenn a gleich b
a != b ungleich: wahr, wenn a nicht b

Wenn wir jetzt also den Benutzer einen Wert eingeben lassen wollen, welcher höchstens 100 sein soll, könnten wir folgende Anweisungen verwenden:

/* ... */
scanf("%d", &a);
if (a > 100)
{
        a=100;
}
/* ... */

Wenn nun ein Wert eingegeben wird, welcher grösser als 100 ist, wird a zurück auf 100 gesetzt. Besteht der Anweisungsblock aus einer Anweisung (also wie im oberen Beispiel), dürfen wir die geschweiften Klammern weglassen:

/* ... */
scanf("%d", &a);
if (a > 100)
        a=100;
/* ... */

Gefährlich ist dabei, dass man sich vergessen kann und versehentlich mehrere Anweisungen in den Anweisungsblock stopft und sich dann wundert, warum das Programm nicht richtig funktioniert. Beispielsweise würde sich das folgende Programm immer beenden, auch wenn a kleiner als 100 ist:

/* ... */
scanf("%d", &a);
if (a > 100)
        printf("a darf nicht grösser als 100 sein!\n"); return 1;

printf("a ist kleiner als 100!\n");
/* ... */

Das Gegenstück zu if ist else, welches so viel wie "sonst" bedeutet. else muss immer einem if folgen. Dazu gleich ein Beispiel:

/* ... */
scanf("%d", &a);
if (a > 100)
{
        printf("a grösser als 100\n");
}
else
{
        printf("a kleiner oder gleich 100\n");
}
/* ... */

Die geschweiften Klammern könnten wir hier auch weglassen. Folgendes Beispiel zeigt aber ein Problem, welches sich bei verschachtelten if-Konstrukten ergeben kann:

/* ... */
scanf("%d", &a);
scanf("%d", &b);
if (a > 100)
        if (b > 100)
                printf("a und b grösser als 100\n");
        else
                printf("a grösser als 100, b kleiner oder gleich 100\n");
/* ... */

Das Problem stellt sich hier ja, zu welchem if die else-Anweisung gehört. Dank meiner Einrückung des zweiten else wird deutlich, dass ein else immer zum letzten if gehört, dem noch kein else zugeordnet ist.

Wenn man in einem else-Block nur eine if-Abfrage hat, lässt man meistens die geschweiften Klammern von else weg und schreibt else und if auf eine Zeile. Dazu ein Beispiel:

/* ... */
scanf("%d", &a);
if (a > 100)
{
        printf("a grösser als 100\n");
}
else if (a == 100)
{
        printf("a ist 100\n");
}
else
{
        printf("a kleiner als 100\n");
}
/* ... */

Im oberen Beispiel könnten wir natürlich auch die geschweiften Klammern weglassen.

4.3 Entscheidungen mit switch
Wenn man beispielsweise ein Auswahlmenü ausgibt (bei jedem Eintrag steht eine Nummer, die man eingeben muss) und dann überprüfen will, welche Zahl ein Benutzer eingegeben hat, könnte man mehrere else if-Anweisungen verwenden. Weil das aber nicht nur mühsam ist, sondern auch unübersichtlich aussieht, verwendet man die sogenannte switch-Anweisung. Ein switch-Konstrukt sieht folgendermassen aus:

switch(Variable)
{
        case Wert1:
                Anweisungen
                break;
        case Wert2:
                Anweisungen
                break;
        ...
        default:
                Anweisungen
}

Ich vermute die Funktionsweise von switch ist grösstenteils schon klar. Der Wert, welcher in der Variablen gespeichert ist, wird von switch ausgewertet und wenn er mit dem bei case angegebenen Wert übereinstimmt, werden die entsprechenden Anweisungen ausgeführt. Nach der letzten Anweisung folgt die Anweisung break, welche switch verlässt. Wenn man break weglässt, dann werden auch die Anweisungen bei den nachfolgenden case's ausgeführt. Der Doppelpunkt nach dem Wert darf auch nicht vergessen werden. Was noch zu erklären ist, ist das default. default wird ausgeführt, wenn keines der oberen case's gültig ist. Nach default braucht es kein break, weil der Computer ja sowieso switch verlässt.

Nun denke ich, dass dringend ein Beispiel nötig ist. Hier ein Beispielprogramm:

#include <stdio.h>

int main(int argc, char *argv[])
{
        int x;
        printf("Gib eine 1, 2 oder 3 ein!\n");
        scanf("%d", &x);
        switch(x)
        {
                case 1:
                        printf("Du hast eins eingegeben!\n");
                        break;
                case 2:
                        printf("Du hast zwei eingegeben!\n");
                        break;
                case 3:
                        printf("Du hast drei eingegeben!\n");
                        break;
                default:
                        printf("Du hast nicht 1, 2 oder 3 eingegeben!\n");
        }
        return 0;
}

Kompiliere das Programm und probiere es aus. Nun wollen wir ein kleines Experiment machen. Wir lassen die break-Anweisungen weg und kompilieren das Programm noch einmal. Was würde jetzt kommen?

Wer richtig aufgepasst hat ahnt es schon. Weil das break ausgelassen wurde, verlässt das Programm nicht die switch-Anweisung sondern führt alle folgenden Anweisungen auch aus. Hier die Ausgabe des Programms auf meinem Computer mit den Werten 1 und 3:

tom@workstation:~/testing$ ./switch 
Gib eine 1, 2 oder 3 ein!
1
Du hast eins eingegeben!
Du hast zwei eingegeben!
Du hast drei eingegeben!
Du hast nicht 1, 2 oder 3 eingegeben!
tom@workstation:~/testing$ ./switch 
Gib eine 1, 2 oder 3 ein!
3
Du hast drei eingegeben!
Du hast nicht 1, 2 oder 3 eingegeben!
tom@workstation:~/testing$ 

4.4 Der Bedingungsoperator ? :
Der Bedingungsoperator ? : ist ein Operator, der ähnlich wie if und else aufgebaut ist. So funktioniert er:

Bedingung ? Erfüllt : Nicht erfüllt

Dazu möchte ich ein Beispiel zu der Verwendung dieses Operators geben.

#include <stdio.h>

int main(int argc, char *argv[])
{
        int x, ergebnis;
        printf("Zahl eingeben: ");
        scanf("%d", &x);
        ergebnis = x>100 ? 100 : x;
        printf("ergebnis = %d\n", ergebnis);
}

In der printf-Anweisung wird keine Zahl über 100 ausgegeben. Die Zeile ergebnis = x>100 ? 100 : x; entspricht hier also dem folgenden if-Konstrukt:

if (x>100)
        ergebnis=100;
else
        ergebnis=x;

 

A Lösungen zu den Übungen

A.1 Variablen
Hier ist der Quellcode des Programms:

#include <stdio.h>

int main(int argc, char *argv[])
{
        int a,b,c;

        a=13;
        b=-300;

        c=(a+b)*a;
        
        c+=2;

        printf("\"%d addiert mit %d und multipliziert mit %d gibt %d\"\n", a, b, a, c);
        
        return 0;
}

Das Programm sollte folgende Zeile ausgeben:

"13 addiert mit -300 und multipliziert mit 13 gibt -3729"

Zurück zur Hauptseite
 
Letzte Änderung: 14.10.03
Copyright (C) 2003 by Thomas "tom" S. <tom at eggdrop.ch>
Valid HTML 4.0!

Dieser Text gehört zu www.eggdrop.ch und ist urheberrechtlich geschützt. Das Weitergeben und Kopieren dieses Textes ist erwünscht unter folgenden Bedingungen: 1. Der Text muss so sein wie er ist und darf in keiner Weise verändert oder in die eigene Homepage integriert werden. 2. Es muss ein deutlicher Hinweis auf die Herkunft (www.eggdrop.ch) vorhanden sein. 3. Der Text sollte wenigstens alle 3 Monate auf Updates überprüft werden (siehe die Versionsnummer ganz am Anfang des Textes!)