Zur Geschichte von C++

1965 BCPL

1970 B


1972 C(einfach der nächste Buchstabe im Alfabet)

Entwicklung bei AT&T(Telefongesellschaft)

1978 Kernighan - Richie C

1980 C mit Klassen


1983 Dr Bjarne Strousdrup entwickelt C++ und benennt es nach dem Inkrementoperator

1988 ANSI C

1989ff ANSI C++

C# ist eine neue Programmiersprache von Microsoft, die ähnlich wie Java,
das von Sun entwickelt wurde an C++ angelehnt ist.

1) Basiskonzepte:
Aktionen, Variablen, Ein- / Ausgabe

2) Kontrollstrukturen:
Entscheidungen, Schleifen, Bedingungen

3) Datenstrukturen:
Zähler, Variablen, Ein- / Ausgabe

4) Objekte

5) Werkzeuge:
Übersetzung und Komplexität

Die Vorteile von C++ liegen besonders darin, dass es system- bzw. maschinennah ist
und trotzdem durch die Objektorientierung auch sehr große Projekte hantieren kann.

Datentypen

Datentypen können numerisch, alfabetisch oder logisch sein.

numerisch

Integer Zu int gehören char(1 Byte), short(2 Byte), long(4 Byte). Alle können
signed oder unsigned sein, wobei signed der default - Wert ist. Unsigned wird immer
dann genommen, wenn man nur positive Zahlen nehmen will und dafür einen doppelt so
großen Zahlenbereich braucht. int selbst entspricht auf 16 Bit Systemen short
und auf 32 Bit Systemen long.

Floating Point Zu float(4 Byte) gehören real(4 Byte), double(8 Byte)
und long double(10 Byte).

alfabetisch

Character(char) kann nicht nur die Zahlen von -127 bis 127(signed) oder von 0 bis 255(unsigned)
enthalten, sondern auch den alfabetischen 8 Bit ASCII Code(der eigentlich ISO 8859 heißt).
In vielen Programmiersprachen gibt es außerdem einen vorgefertigten Variablentyp "String", in C/C++ nicht!
Für uns heißt das zunächst, wenn wir ganze Zeichenketten verwenden wollen, also Strings, dann
gibt es für uns "was zu basteln".

logisch

bool ist im Idealfall nur ein Bit groß, das 0(falsch) oder 1(wahr) sein kann.
Da es aber von C und C++ verschiedene Standards gibt, kann hinter bool auch ein Integer
stehen. Generell gilt, dass C/C++ annimmt, dass 0 auch falsch bedeutet und !0(nicht 0) wahr.
Das Hexadezimalsystem ist besonders computerfreundlich.

Deklaration einer Variablen:
int alter;
mit Initialisierung:
int alter=0;
Deklaration einer Konstanten:
const int Umrechnungsfaktor;
mit Initialisierung:
const int Umrechnungsfaktor=1.95583;

Eine Konstante ist eine Variable, auf die nur der Programmierer Schreibrechte besitzt. Weder der Anwender,
noch das Programm selbst können in eine Konstante schreiben.
Bei großen Programmen sind Konstanten sehr praktisch. Hätten wir z.B. ein Modul "Umrechnung von Euro in DM"
und der Umrechnungsfaktor würde sich ändern, so müssten wir nicht mühsam nach allen Stellen suchen,
wo der alte Umrechnungsfaktor noch verwendet wird, sondern könnten als Programmierer einfach die
Konstante "Umrechnungsfaktor" ändern.

Der Name einer Variablen ist ein Bezeichner, d.h. er ist frei wählbar und muss mit
einem Buchstaben oder dem Unterstrich beginnen. Vorsicht mit dem Unterstrich, da dieser
auch in den Bibliotheken beliebt ist.
Das Gegenteil eines Bezeichners ist ein Schlüsselwort. Ein Schlüsselwort ist ein reserviertes Wort.
Variablentypen sind Schlüsselwörter, merkwürdigerweise sind aber Standardfunktionen keine!
Das bedeutet man könnte tatsächlich eine Variable printf nennen, sollte dann aber die stdio.h
nicht einbinden, da das Ergebnis dann unvorhersehbar ist.
Dies ist ein Beispiel für die Anarchie - artige Freiheit, die man im Umgang mit C und C++ hat.
Bezeichner, Schlüsselwörter und Kommentar summiert man unter dem Begriff "Token".
Kommentare kann man einzeilig oder mehrzeilig konzipieren:

einzeilig:   //

mehrzeilig:   /*      */

Escape - Sequenzen

Beispiele:

\r      geht zurück an den Zeilenanfang ohne neue Zeile

\t      Tabulator

\0      Terminatorzeichen

\n      new line

\ooo      Zeichen oktal ausgeben

\xhh      Zeichen in hex ausgeben

\33[5m      blinkende Ausgabe

\33[0m      zurück zur normalen Ausgabe

Escape - Sequenzen heißen, wie sie heißen, weil man in der Batch - Programmierung unter DOS
den ASCII Code der Escape - Taste für die entsprechenden Zeichen verwendet.
Das oben genannte Terminatorzeichen beendet einen String mit einer 0. Die 0 wird am Ende der Zeichenkette eingefügt.
Man unterscheidet Compile - Time und Run - Time.

Operatoren

Zuweisung:    =

Vergleich:    = =, >, <, >=, <=, !=

Logische:    UND     &&,     ODER     | |,     NICHT     !     XOR, exklusives ODER     ^

Arithmetische:    +, -, *, /, %

Zuweisung+Arithmetik:    ++, --, *=, /=, %=, +=, -=

Operatoren verkleben Variable miteinander. Zum durch "^" repräsentierten XOR ist noch zu sagen, dass es nicht immer
ein fertiger Bestandteil von C++ war, also u.U. bei veralteten Compilern noch selbst gebastelt werden muss.
Da ist es dann hilfreich zu wissen, dass die Standardformel für XOR aus der Booleschen Algebra so aussieht:

(A&&!B)||(B&&!A).

Zur Rangfolge von Operatoren

Es gibt eine genau festgelegte Rangfolge von Operatoren, die bestimmt, in welcher Reihenfolge sie abgearbeitet werden.
Man kann diese Rangfolge jederzeit nachschlagen. Um für den Anfang unser Gedächtnis nicht zu sehr mit Details
zu befrachten,gehen wir einfach nach folgender Faustregel vor:

Alles, was sich nur auf eine Variable bezieht, wird zuerst erledigt, vor dem, was sich auf mehrere Variablen bezieht.
Außerdem gilt Punktrechnung vor Strichrechnung, wobei Modulo zu den Punktrechnungen gehört.
Wenn es keine Regel gibt, dann läuft alles in der reihenfolge einfach von links nach rechts ab.

Funktionen

Als Elemente von C++, die Aktionen auslösen, stehen den Operatoren die Funktionen gegenüber.
Man unterscheidet Standardfunktionen, das sind solche, die bereits implementiert in den C++ - Bibliotheken vorliegen
und selbstgemachte Funktionen.
Als kleines Beispiel für die Verwendung der Standardfunktionen cin und cout, für die man die Header - Datei iostream.h
einbinden muss, hier ein kleines Programm, das nichts weiter tut, als eine Zahl einlesen und wieder ausgeben:

#include <iostream.h >

int main(void)

{
        double zahl;
        cout <<"Zahl eingeben!:> ";
        cin >> zahl;
        cout <<"Die Zahl war" << zahl;
        return 0;
}

Wenn man die Header - Datei ohne abschließendes ".h" schreiben will, muss man unterhalb der
Makropräprozessor - Direktiven außerdem using namespace std; einfügen,

Selbstgemachte Funktionen lassen sich wie folgt deklarieren(Syntax beachten!):

Deklaration der Funktion, auch "Funktionskopf" genannt :

Typ-Rückgabewert Funktionsname(Argument1Typ Argument1Name[, Arg2Typ Arg2Name])

Die Hinzufügung in eckigen Klammern ist optional. Tatsächlich lassen sich hier beliebig
viele Argumente in der Funktionsklammer durch Kommata getrennt als Argument-Typ und Argumentname
deklarieren, die man dann später der Funktion auch als Parameter übergeben muss.
Eine solche Deklaration einer Variablen als Argument in der Funktionsklammer ersetzt die
Deklaration derselben Variablen irgendwo anders(sonst Compiler - Fehler: doppelte Deklaration).
Wenn die Implementierung der Funktion der Deklaration nicht unmittelbar folgt, muss hinter der
Deklaration ein Semikolon stehen.

Implementierung der Funktion, auch "Definition" oder "Funktionskörper" genannt :

{
        Neue Variablen zur Entgegennahme der Parameter(Argumente) deklarieren
        Anweisungen;
        Returnwert(e);
}

Aufruf

[Rückgabedatentyp]Funktionsname(ParameterName);

Die Angabe des Rückgabedatentyps ist optional. Wenn man ihn nicht angibt, nimmt C++ intern an,
es sei eine Integer - Zahl.

Die Vorbelegung von Argumenten mit default - Werten gestattet, Argumente beim Funktionsaufruf wegzulassen.

Eine besondere Funktion ist die Funktion main. Sie kommt in jedem C - Programm genau einmal vor.
Wenn man modular programmiert, d.h. dass man seinen Quellcode in verschiedene Dateien speichert,
besteht die Tätigkeit der main - Funktion oft nur noch darin, Funktionen an den richtigen Stellen
im Programmablauf aufzurufen, ihnen Parameter zu übergeben und ihre Rückgabewerte entgegen zu
nehmen.

Beispiel für eine selbstgemachte Funktion

Deklaration:   void Gruss(void)

Implementierung:
{
    printf("Sehr geehrte Damen und Herren, ich begruesse Sie herzlich im Koelner Zoo");
}

Aufruf: Gruss;

Wie man hier sieht, ist es am einfachsten, nur einen Text auszugeben, den printf direkt als String entgegennimmt.

Beispiel für eine Kreisberechnung mit globalen Funktionen

rekursive Funktion


Folgende Aufrufe der main - Funktion sind zulässig:

main( )                 Implizit wird angenommen, dass main einen int zurückliefert, sie erhält keine Parameter.

int main( )                 Hier wird explizit festgelegt, dass main als return einen int zurückgibt.

void main( )                 kein Return-Wert, keine Parameter

void main(void)                 kein Return-Wert, keine Parameter

double main( )                 main gibt einen double Wert zurück und nimmt keine Parameter entgegen.

float main( )                 entsprechend.

char main( )                 usw.

Interessant wäre es nun, den Aufruf einer main - Funktion zu sehen, die Parameter entgegennimmt.
Aufrufparameter heißen auch Argumente. So könnte man z.B.
char main(double giraffe, int hallo, char test) schreiben.

Ein solches Programm müsste jedoch beim Aufruf am DOS-Prompt etwa so gestartet werden:

c:\>Programmname -2.5 7 A --- sonst würde es eine Fehlermeldung ausgeben, dass es nicht genügend Parameter erhalten hat!
Die Unterlassung, die Argumente zu benennen, die main haben will(giraffe, hallo, test--siehe unten!) würde einen Compilerfehler bewirken,
jedenfalls in VC++6!

Korrekt implementiert sähe eine solche main - Funktion, die allerdings noch fast gar nichts macht,
so aus:

#include < stdio.h >

char main(double giraffe, int hallo, char test)
{
printf("google");
return 'A';
}

Standardfunktionen aus C :

Funktionsname Was tut die Funktion eigentlich? Header - Datei
printf Daten aller Formate ausgeben #include <stdio.h >
scanf Daten einlesen und als Zahl speichern #include <stdio.h >
atoi "ascii to integer" Buchstaben in Zahlen umwandeln #include <stlib.h >
toupper "to upper case" Buchstaben in Großbuchstaben umwandeln #include <ctype.h >
tolower "to lower case" Buchstaben in Kleinbuchstaben umwandeln #include <ctype.h >
getchar Lese einen Buchstaben ein #include <stdio.h >
fprintf Gib einen Stream aus #include <stdio.h >
sprintf Gib einen String aus #include <stdio.h >
gets Get String #include <stdio.h >
fflush Arbeitsspeicher leer machen #include <stdio.h >
strlen "string length" Ermittle die Länge eines Strings #include <string.h >
sizeof Sag mir, wie groß eine Variable oder ein Typ ist #include <limits.h >


Hier ein Schmankerl für alle:

#include<stdio.h>
#include<math.h>
#define OBERGRENZE 100

void main( ) //Programm Primzahlen von 1 bis OBERGRENZE
{
        bool ist_noch_ungeteilt; //Statusvariable: Ist aktuelle Zahl eine Primzahl?
        int zu_testende_zahl, teiler; //wenn zu_testende_zahl durch teiler mögl. -> keine Primzahl!
                             /*Idee: Alle Zahlen von 2 bis OBERGRENZE testen, indem pro
                             Zahl die Wurzel aus allen darunter liegenden
                             Zahlen als mögliche Teiler ausprobiert werden!*/

        for(zu_testende_zahl = 2; zu_testende_zahl <= OBERGRENZE; zu_testende_zahl=zu_testende_zahl+1)
        {
               ist_noch_ungeteilt = true; /*solange sie nicht geteilt worden ist, ist zu testende Zahl
                                                  für uns Primzahl! */
               for (teiler = 2; teiler < = sqrt(zu_testende_zahl); ++teiler)
               {                       if((zu_testende_zahl % teiler) == 0)
                      {
                             ist_noch_ungeteilt = false; // Ganzzahldivision möglich?
                      }
                      if (ist_noch_ungeteilt) /*wenn Bool - Variable nach allen Teilversuchen
                                                         unverändert -> Primzahl!! */

                                    printf("%10i", zu_testende_zahl);

                     }
               }
               printf("\n\n\n");
}

Das Programm hat noch einige Probleme! Probiert's aus und lasst den Debugger heißlaufen!
In der Ausgabe gibt es noch furchtbar viele Zahlen, die durch 5 gehen!!
Vielleicht kriegt man es heraus, wenn man als OBERGRENZE mal die 10 nimmt.....

But now for something completely different :

Präinkrement       ++i

Postinkrement       i++

Entsprechend gibt es auch Prädekrement und Postdekrement
Diese kurzen Darstellungen von i += 1 bzw. i = i + 1 haben den besonderen Vorteil, besser optimierten
Quellcode zu erzeugen, als ihre eben genannten Entsprechungen. Der Hund ist jedoch an einer anderen Stelle begraben:
Das Präinkrement erhöht die Zahl unmittelbar, sobald der sequenzielle Programmablauf dort ankommt,
nicht so das Postinkrement, welches nämlich erst nach Abarbeitung des gesamten Ausdrucks die Zahl erhöht(!).

Eingedenk dieser Tatsache muss man wahrscheinlich auch das oben aufgeführte Programm nocheinmal sehr sorgfältig
überdenken.

Exkurs: Boolesche Algebra und Wahrheitstafeln

Wir haben die weiter oben genannten logischen Operatoren UND     &&,     ODER     | |,     NICHT     !     XOR, exklusives ODER     ^

George Boole dachte vor allem an den mathematischen Beweis, als er seine Algebra so formulierte, dass wenn ein Ausdruck stimmt,
sein Gegenteil mit Sicherheit nicht stimmt, anders ausgedrückt:

A = = TRUE ----> !A = = FALSE

Für den, der was damit anfangen kann : Auf diese Weise hat Sokrates die Athener aufs Glatteis geführt.
Jeder boolesche Operator hat seine eigene Wahrheitstafel :
2 Elemente haben immer 4 mögliche Verknüpfungen.

&& :

        A     B

        w     w    ----> w
        w     f    ----> f
        f     w    ----> f
        f     f     ----> f

| | :(einschließliches ODER)

        A     B

        w     w    ----> w
        w     f    ----> w
        f     w    ----> w
        f     f     ----> f

^ : XOR

        A     B

        w     w    ----> f
        w     f    ----> w
        f     w    ----> w
        f     f     ----> f

Manche Leute sagen: "Das ist so und wird auch immer so sein."
Hat man diese "ewige" Wahrheit einmal akzeptiert, so werden dann auch Kombinationen möglich,
wie z.B. (A) && (!B) :

        w     w    ----> f
        w     f    ----> w
        f     w    ----> f
        f     f     ----> f

Mit etwas Nachdenken kommt man nun darauf, dass XOR (^) nichts anderes besagt, als

(A && !B) | | (B && !A)

Wahrheitstafel siehe oben: XOR

Der logische Datentyp bool wird oben beschrieben.

Die Sache mit dem Modulo

Die Modulo - Division wird durch das Zeichen % dargestellt.
Es ist eine Rest Division, also ganz so wie
10 / 3 = 3 R 1,
nur mit dem Unterschied, dass ich nun das Ergebnis wegwerfe und
nur den Rest behalte, also
10 % 3 = 1.

Datenbanken, neue vollständige Fassung

C-Kurs

Weiter mit C++