Startseite | Forum | Artikel/Tutorials | Downloads | Links
 
Navigation
Startseite
Forum
Artikel/Tutorials
Downloads
Bücher
Links
Kontakt
Galerie
Suche

Anzeige
FlashEcke.de

Shoutbox
Du musst Dich einloggen, um eine Nachricht zu schreiben.

philipp k
18.08.2010
Danke für die Info :-)

Marc
18.08.2010
Du darfst die Grafiken frei verwenden. Ein Hinweis, dass Sie von hier kommen wäre nett, ist aber nicht zwingend erforderlich

philipp k
18.08.2010
Unter welcher Lizenz stehen denn nun die Grafiken? "Isogames.de" ist keine mir bekannte Lizenz.

GSlang
03.01.2010
WoW

Himmelweiss
29.12.2009
Denk dir nix, bei mir antwort doch auch keiner smiley Naja k kurdt hat mal seinen Senf dazugegeben, aber sonst.. smiley

Shoutbox Archiv

Benutzer Online
Gäste Online: 4
Keine Mitglieder Online

Registrierte Mitglieder: 1,050
Neustes Mitglied: Hydralistika

C++ Basics



Einleitung

Hallo zusammen! Hier ist er also, ein erster Versuch von mir, ein Tutorial zu schreiben. Das Thema, C++, schien einige zu interessieren, und deshalb hab ich es mit einer kleinen Einführung in die Grundlagen der Sprache probiert.
Wenn ihr Einsteiger seid, und, so wie ich, am liebsten sofort mir eurem Spiel loslegen würdet, habt ihr bestimmt nicht viel Lust, vorher tausende Bücherseiten zu wälzen. Deshalb hab ich mir vorgenommen, das Tutorial so einzuteilen, dass hier, in Teil 1, die Grundlagen von C++ erklärt werden, mit ein paar Übungen am Ende.
Die Lösungen gibts dann in Teil 2, (sollte ich bis dahin durchhalten ;) wo es mit Funktionen, Objektorientierung und einer grafischen Oberfläche weitergeht.
Die Themen sind eigentlich nicht so kompliziert, und vielleicht habt ihr ja schonmal mit Pascal oder Delphi programmiert. Guckt euch in dem Fall einfach das Inhaltsverzeichnis an und klickt euch zu den Abschnitten, die euch interessieren. Ich hoffe, dass das Tutorial auch für Leute verständlich ist, die noch nie programmiert haben - für die ist es jedenfalls gedacht. Solltet ihr Fragen haben, könnt ihr mir auch schreiben. Wer auf Dauer ernsthaft was mit C++ machen will, sollte sich aber nicht nur auf Tutorials verlassen, es lohnt sich sicher auch ein Buch anzuschaffen, welches die Themen nochmal ausführlicher erklärt.
Ich habe unter anderem in dem hier gelesen:

Wolf, Jürgen: C++ von A - Z. Galileo Verlag, 2006X
Ein schönes, sehr ausführliches Buch. Auf CD ist unter anderem ein komplettes Buch über C mit enthalten. Das Thema ist C++ allgemein, und nicht speziell Spieleprogrammierung. Dafür ist es ein super Nachschlagwerk zu so gut wie allen relevanten Themen.

Das hier ist ein Klassiker:
Stroustrup, Bjarne: Die C++ Programmiersprache. Addison-Wesley, 2000
Ich hab selber nicht drin gelesen, aber es soll wohl recht formal und deswegen nicht so gut für Einsteiger sein - fachlich wird da allerdings kein Buch dran kommen, denn der Autor ist niemand anders als der Erfinder von C++.

Nicht empfehlen würde ich das folgende Buch:
Koening, Andrew und Moore, Barbara E.: Intensivkurs C++ - schneller Einstieg über die Standardbibliothek. Pearson Studium, 2003
Der Titel verspricht viel Erkenntnis auf wenigen Seiten - leider ist das Gegenteil der Fall, zumindest meiner Meinung nach. Die 35€ ist es auf jeden Fall nicht wert.

Buchempfehlungen gibts ja auch hier noch einige, vor allem im Bezug auf Spieleprogrammierung! Achtet aber, wenn ihr Anfänger seid, darauf, dass ihr euch kein Buch kauft, welches zu viele Vorkenntnisse voraussetzt, wie z.B. "Spieleprogrammierung mit DirectX und C++" aus dem Galileo Verlag.
Es gibt ja auch eine Menge C++ - Webseiten, eine Kurzreferenz wichtiger Befehle findet ihr z.B. unter
www.cppreference.com
So, jetzt aber Schluss mit dem Vorgeplänkel und viel Spaß beim Einstieg in C++!


1. Einstieg

1.1 Compiler und Entwicklungsumgebung

Um ein Programm zu schreiben und zu starten gibt es mehrere Möglichkeiten. Welche dabei in Frage kommt, hängt vor allem von der Sprache ab.
Es gibt so genannte Interpreter - Sprachen, bei denen ein Programm, der Interpreter eben, den Code, den ihr geschrieben habt, in Maschinenbefehle übersetzt, während das Programm läuft. Java benutzt ein ähnliches Verfahren, was letztendlich dem Zweck dient, die in Java geschriebenen Programme auf allen Plattformen lauffähig zu machen, also z.B. sowohl unter Linux als auch unter Windows. Aber das soll hier nicht Thema sein, denn C++ verwendet eine andere Möglichkeit um Programme zu starten und laufen zu lassen.
C++ - Programme benötigen kein spezielles Programm, um auf einem Computer ausgeführt zu werden. Sie werden als C++ - Code geschrieben und dann vor dem Start in Maschinenbefehle übersetzt. Da es keine Laufzeitumgebung gibt, die das Übersetzten übernehmen müsste, sind solche Programme in der Regel wesentlich schneller. Der Nachteil: Das Programm kann nur für eine spezielle Plattform übersetzt werden, nie für zwei gleichzeitig. Euer Programm kann also nachher entweder auf einem Windows- oder einem Linux - PC laufen, aber niemals auf beiden gleichzeitig - es sei denn, ihr benutzt zwei verschiedene Übersetzer für euer Programm.
Diese Übersetzerprogramme, welche aus dem C++ - Programmcode eine ausführbare Datei machen, heißen Compiler. Ihr braucht also einen C++ - Compiler, um ein Programm ausführen zu können. Die übersetzten Programme haben unter Windows immer die Endung ".exe" - ihr kennt solche Programme sicher von verschiedenen Spielen. Hier das ganze mal schematisch:



Jetzt braucht ihr also erstmal einen Compiler. Zusätzlich ist ein Programm sinnvoll, welches euch beim Programmieren unterstützt, z.B. durch bestimmte Farben für C++ - Schlüsselwörter (so genanntes "Syntax Highlighting"). Solche Programme werden Entwicklungsumgebung oder IDE (für "Integrated Development Enviroment") genannt. Microsoft bietet mit der Visual C++ Express Edition eine Entwicklungsumgebung mit Compiler an, welche recht viele Features bietet. Der Nachteil: Visual C++ und der "große Bruder" Visual Studio, welcher das Erstellen von Programmen in C+, C#, VisualBasic und anderen Sprachen ermöglicht, sind ziemlich komplex und für größerer Projekte gedacht. Ihr müsst z.B. für jedes Programm ein Projekt anlegen.
Für Einsteiger ist es also besser, eine übersichtliche Entwicklungsumgebung zu haben, die möglichst direkt auch einen Compiler mitliefert. Eine solche Entwicklungsumgebung ist das kostenlose Programm DevC++. Die Homepage ist http://www.bloodshed.net/dev. Ihr könnt auch einfach mal nach "DevC++ + download" googeln - auf der Downloadseite findet ihr eine Version, die den MinGW - Compiler enthält. Das ist die Version, die ihr downloaden solltet, sonst habt ihr keinen Compiler... .
Hinweis: Natürlich könnt ihr auch jede andere Entwicklungsumgebung bzw. jeden anderen Compiler benutzen! In Teil 2 werden wir Visual C++ verwenden. Wenn ihr eine andere Umgebung verwenden wollt, überspringt den nächsten Abschnitt zu DevC++.

Installiert jetzt DevC++ und startet das Programm. Bei der Frage nach dem "Code Completion Feature" beim Programmstart könnt ihr die Installation ruhig bestätigen, das Feature ist ganz nützlich. Ihr seht dann hoffentlich ein Programm wie das hier:


Mit einem Klick auf "Neu" und "Quelldatei" ist eine neue Datei angelegt.

1.2 Ein erstes Programm

Jetzt also endlich zum ersten Programm, so wie es meistens aussieht:

#include <iostream>

using namespace std;

int main(){
    cout << "Hello Nerds!" << endl;
    cin.get();
    return 0;
}

Tippt das Programm in eure neue Datei in DevC++ ein.
Um das Programm zu übersetzen, drückt auf den Button oben links mit den 4 bunten Windows - Quadraten.



DevC++ fragt euch jetzt, unter welchem Namen das Programm und die dazugehörige ".exe" - Datei gespeichert werden sollen. Gebt einen Namen ein und bestätigt. Jetzt wurde das Programm hoffentlich fehlerfrei übersetzt. Wenn ihr eine Fehlermeldung bekommt, solltet ihr die Schreibweise überprüfen, denn C++ ist sehr pingelig bei kleinen Ungenauigkeiten, wie einem vergessenen ";". Wenn das ganze geklappt hat, könnt ihr das ganze mit dem 2. Button in der Reihe starten. Der dritte Button übersetzt ein Programm und startet es dann sofort.
Der Button mit dem Häkchen ist der Button zum Debuggen, das ist eine Ausführung des Programms in einer Art Fehlersuch - Modus, die helfen soll, Ursachen für Fehler zu finden. Leider sind die Meldungen des Debuggers meist nicht sehr aussagekräftig für Anfänger, zumindest bei diesem hier.
Wenn ihr das Programm gestartet habt, bezeichnet euch die Konsole als Nerds, und zwar so lange, bis ihr eine Taste drückt. Eigentlich ganz schön wenig für soviel Code, oder? Gucken wir uns die einzelnen Zeilen mal an...


2. Das erste Programm im Detail

#include <iostream>
Diese Anweisung sagt dem so genannten Präprozessor, einer Art Vorstufe des Compilers, dass er eine Datei namens "iostream" aus einem bestimmten Ordner (nämlich dem "include" - Ordner des Compilers, angedeutet durch die spitzen Klammern) vor euren Programmcode hängen soll. In dieser Datei sind bestimmte Definitionen enthalten, welche es ermöglichen, Ein- und Ausgaben, z.B. auf den Bildschirm in der Konsole, zu machen. Anweisungen an den Präprozessor beginnen immer mit "#" und enden als einzige Anweisungen ohne das Semikolon.

using namespace std;
Diese Anweisung legt fest, dass Befehle und Werte in einem bestimmten "Namensraum" (namespace) gesucht werden sollen. Der Namespace ist sowas wie ein Familienname. Nachher taucht die Bezeichnung "cout" auf, diese gehört zur "Familie" der Standardbibliothek, "std" genannt - sie heißt nämlich eigentlich "std::cout". Der "::" - Operator ist der so genannte Scope - Operator (Scope = Gültigkeitsbereich) und definiert, wo eine Anweisung o.ä. zu finden ist, also z.B. "cout" in "std". Er trennt also praktisch den Vor- und Nachnamen eines Bezeichners. Dank der "using namespace" - Anweisung kennt unser Programm nun alle Mitglieder der Familie "std", so dass wir nicht immer "std::cout" oder std::endl", sondern nur noch "cout" oder "endl" schreiben müssen. Probiert auch mal die Variante ohne "using namespace" aus!

int main(){
    ...
    return 0;
}

Dies ist, wie der Name schon andeutet, der Hauptteil des Programms. Wenn ein C++ - Programm gestartet wird, wird immer das gemacht, was in der so genannten "main - Funktion" steht. Diese main - Funktion besteht aus verschiedenen Teilen: Dem so genannten Kopf, das ist die Zeile "int main()", und dem so genannten Rumpf - das ist alles was zwischen den geschweiften Klammern steht.
Wo die Klammern dabei stehen, also z.B. in derselben Zeile wie der Kopf oder eine Zeile darunter, ist egal. Wichtig ist nur, dass nach den runden Klammern am Ende des Kopfes als nächstes erstmal eine geöffnete geschweifte Klammer kommt, dann die Anweisungen, die "main" abarbeiten soll (, also z.B. unsere Ausgabe,) und dann eine geschlossene geschweifte Klammer. Die Klammern sagen also dem Programm, wo die Fuktion anfängt und aufhört.
Aber was soll das "int", und warum steht da noch "return 0;", und wieso überhaupt die runden Klammern? Das alles hängt damit zusammen, das "main" eine Funktion ist. Eine Funktion kann man sich vorstellen wie ein kleines Programm: Man tut was rein, oder auch nicht, und es kommt was raus. Das was rauskommt ist der so genannte Rückgabewert, der einen bestimmten Rückgabetyp haben muss. Das heißt nichts anderes, als das man angeben muss, ob die Funktion eine Zahl, ein paar Buchstaben oder garnichts zurückliefert. Das, was zurückkommt, kann der Aufrufer dann entgegennehmen verwerten. Der Rückgabetyp muss immer am Anfang des Funktionskopfes stehen und ist hier int, was für "integer" steht. Ein integer ist immer eine ganze Zahl (, d.h. auch negative Zahlen sind möglich). Ein C++ - Programm, bzw. seine main - Funktion, wird z.B. von der "Eingabeaufforederung" aus aufgerufen, und somit liefert das Programm wenn es fertig ist auch einen Wert an die Eingabeaufforderung (bzw. eigentlich an das System) zurück. Welche Zahl das Programm zurückliefert, wird durch die "return" - Anweisung festgelegt, in unserem Fall "0". Alle Anweisungen müssen mit einem Semikolon enden, also auch "return".
*wtf*?!? Warum gibt das Programm dem System einen Zahlenwert zurück wenn es fertig ist? Die Antwort ist, dass das System manchmal wissen möchte, ob ein Programm erfolgreich zu Ende gelaufen ist oder nicht. "0" heißt dann, dass das Programm ordnungsgemäß zu Ende gelaufen ist. Das ganze ist sicher wissenswert, aber für uns nicht so wichtig, denn die return - Anweisung könnt ihr auch weglassen (aber bitte nur bei der "main" -Funktion).
So weit so gut, jetzt haben wir alles betrachet bis auf die beiden runden Klammern nach dem Namen der Funktion, also nach "main". Oben hatte ich ja gesagt, dass man in eine Funktion immer was reintut und nachher kommt was raus. Nun ja, das war nicht ganz richtig: Man kann auch nichts reintun, und es muss auch nicht unbedingt was rauskommen - aber genau das muss man dem Programm dann auch sagen. Das was man der Funktion mit auf den Weg gibt steht in den runden Klammern, in unserem Fall: nichts. Die runden Klammern kann man aber deswegen auf keinen Fall weglassen!! Sie zeigen dem Programm nämlich überhaupt erst an, dass es sich hier um eine Funktion handelt. Es gibt auch Bücher / Tutorials usw. welche eine andere main - Funktion benutzen, ungefähr so eine:

int main(int argc, char* argv[]){
    return 0;
}

Der Unterschied liegt, wie ihr sicher schon gesehen habt, nur im Inhalt der geschweiften Klammern, also in dem, was man der Funktion an Werten mitgibt, bevor das Programm startet. In diesem Fall bezeichnet das bunte Wirrwarr in den Klammern eine Reihe von Zeichen(ketten) und wieviele es insgesamt sind. Diese Variante gibt dem Benutzer die Möglichkeit, beim Programmstart noch bestimmte Optionen an das Programm mitzugeben, wie z.B. bei CS oder Half Life, oder bei vielen anderen Spielen / Programmen. Das sieht dann z.B. so aus:



Das Programm hat den Namen ("hans") beim Programmstart mitgegeben bekommen und ihn dann in die Ausgabe eingebaut. Es gibt allerdings wesentlich elegantere Methoden, Werte einzugeben, so dass ihr nicht wissen müsst wie das ganze jetzt genau funktioniert - der Vollständigkeit halber hab ich hier trotzdem mal diese Variante von "main" eingebaut, weil sie mindestens genau so oft verwendet wird wie die andere - auch wenn dann in 99% aller Fälle nichts mit den möglichen Eingaben gemacht wird, so dass man sich den Inhalt der runden Klammern auch sparen kann.

cin.get();
Eigentlich käme ja jetzt erstmal die "cout" - Zeile, aber weil wir gerade beim Thema Konsole waren bietet es sich an mal kurz zu erklären was diese Anweisung hier soll. Auf dem Bild oben seht ihr, dass ich das Programm "meinProgramm.exe" in der Konsole durch Eingeben des Programmnamens gestartet hab. Dann kam die Ausgabe, und dann konnte ich wieder etwas anderes in die Konsole eingeben. Wenn ihr DevC++ benutzt und auf "starten" klickt, übernimmt das DevC++ das Eintippen des Programmnamens für euch.
Es öffnet die Konsole und gibt den Text aus - dann schließt sie sich wieder, und zwar so schnell, dass es unmöglich ist, die Ausgabe vorher zu betrachten. Das ist der einzige Grund, warum hier cin.get(); steht, denn mit dieser Anweisung liest das Programm ein Zeichen von der Tastatur - sobald ihr also eine Taste drückt, hat das Programm ein Zeichen gelesen und ist fertig. Solange ihr keine Taste drückt, bleibt die Konsole aber geöffnet. Der einzige Grund für diese Zeile ist also, das DevC++ ohne sie beim Testen unsere Konsole direkt wieder schließt.

cout << "Hello Nerds!" << endl;
Diese Zeile ist die Anweisung, welche für die Ausgabe sorgt. Schauen wir uns die einzelnen Teile mal genauer an. "cout" ist die Bezeichnung für einen so genannten Ausgabestrom("cout" = "command out", Konsolenausgabe). Alles, was wir auf diesen Ausgabestrom legen, wird in derselben Reihenfolge auf der Konsole ausgegeben. Die spitzen Klammern (<<) machen das deutlich, alles wird nach links auf den Strom "cout" gelegt.



Unmöglich, was die Leute alles in den Fluss werfen: Über den Ausgabestrom cout direkt in die Konsolenausgabe.


Um die Zeichenfolge "Hello Nerds" sind Anführungszeichen gesetzt worden. Das ist nötig, damit das Programm weiß, dass es sich um eine Zeichenkette handelt. Wenn ihr die Anführungszeichen weglasst, erwartet dass Programm eine Zahl oder eine Variable, und da es keine Variable mit dem Namen Hello gibt, führt das zu einem Fehler.
Hinweis:
Sollte es doch eine solche Variable geben, tritt trotzdem ein Fehler auf, denn dann müsste es noch eine weitere Variable mit dem Namen Nerds! geben. Sollte die auch existieren, würde die gewünschte Ausgabe immer noch nicht erzeugt. Warum? Das steht im nächsten Abschnitt...

Nach dem cout << "Hello Nerds!" folgt nun wieder das Fischgrätenzeichen "<<". Das ist nötig, weil jedes neue Element auf diese Weise einzeln auf den Ausgabestrom gelegt werden muss. Das nächste Element ist endl. Diese Abkürzung steht für nichts anderes als "end line" und sagt dam Programm, dass es an dieser Stelle einen Zeilenumbruch in der Ausgabe machen soll. Alternativ könnt ihr auch ein"\n" in eine Zeichenfolge einbauen, um einen Zeilenumbruch zu bewirken:

cout << "Erste\nZweite und\nDritte Zeile";

Probiert es ruhig mal aus, indem ihr diese Zeile an die Stelle der "Hello Nerds" - Zeile schreibt! (Vergesst dabei nicht das Semikolon am Ende der Zeile, denn es handelt sich ja um eine Anweisung!)
Das wars dann auch mit dem ersten Programm. Ganz schön viel für so wenig Code, oder? Keine Angst - jetzt gehts erstmal mit mehr Beispielen hoffentlich auch schneller weiter!


3. Einfache und fortgeschrittene Datentypen


3.1 Einfache Datentypen und Zuweisungen

Wir haben gesehen, dass "int" für einen Zahlenwert steht. Damit ist "int" ein so genannter Datentyp. Es gibt ein paar wichtige grundsätzliche Datentypen:

int
"Integers" sind ganze Zahlen. Eine Variable vom typ "int" speichert immer eine ganze Zahl. Dabei gibt es Grenzen für die Zahl, welche gespeichert werden soll. In einer bestimmten Variablen namens INT_MAX ist der größtmögliche Wert für ein "int" gespeichert, in einer Variable namens INT_MIN der kleinstmögliche. Dieses Programm gibt euch die Werte für euer System aus:

#include <iostream>

using namespace std;

int main(){
    cout << "Die groesste Integer - Zahl: " << INT_MAX << endl;
    cout << "Die kleinste Integer - Zahl: " << INT_MIN << endl;
    cin.get();
    return 0;
}

Für größere Zahlen benutzt man den Datenyp long, falls der auf dem gegebenen System größere Zahlen als "int" halten kann - bei mir ist INT_MAX allerdings genauso groß wie LONG_MAX. Für kleinere Zahlen gibt es den Datenyp short, dessen maximaler Wert in der Konstante SHRT_MAX gespeichert ist. (8 Buchstaben nicht zu überschreiten war vielleicht auch mal sinnvoll... auf jeden Fall heißt das Ding SHRT_MAX und nicht SHORT_MAX.) "Short" wird allerdings kaum noch verwendet, da der Unterschied im Speicherplatzbedarf bei den meisten Anwendungen kein Problem mehr darstellt.
Wenn ihr wisst, das ihr große Zahlen verwenden möchtet, aber nur positive, könnt ihr den Bereich der möglichen Zahlen mit dem Schlüsselwort unsigned in den Bereich der positiven Zahlen verschieben und so doppelt so viele, aber eben nur positive Zahlen speichern. (Beispiel: unsigned int meineZahl;)

float
Um auch Kommazahlen speichern zu können, benutzt man "float". Für genauere Kommazahlen gibt's außerdem den Typ double.

char
"char" steht für "character" (= "Buchstabe"). Eine variable vom Typ char speichert somit einen Buchstaben. Dieser muss bei der Zuweisung in einfachen Anführungszeichen angegeben werden, aber das seht ihr gleich noch.

string
Strings sind Aneinanderreihungen von chars, Zeichenketten eben. Strings werden immer in Gänsefüßchen angegeben, auch wenn sie nur ein Zeichen enthalten. "Hello Nerds!" ist ein Beispiel für einen String.

bool
"Bool" ist der Name eines Mathematikers, nach dem die so genannte "boolesche Algebra" benannt ist. Dabei geht es um das Rechnen mit Wahrheitswerten - eine Variable kann somit nur den Wert "wahr" oder den Wert "falsch" haben. Genau so eine Art von Variable könnt ihr mit dem Typ "bool" anlegen. "Wahr" wird dann als "1" oder "true" angegeben, "falsch" als "0" oder "false". (Ihr seht das noch im Beispiel!)

Zuweisungen
Wenn Ihr eine Variable anlegen wollt, braucht ihr nur den Datentyp anzugeben und anschließend einen Namen. Etwa so:

int meineZahl;

Es handelt sich um eine Anweisung, denn ihr habt dem Programm gesagt einen gewissen Bereich im Speicher zu reservieren, um dort die integer - Zahl "meine Zahl" zu speichern. Stellt euch das Ganze vor wie ein Fach, auf das das Programm "meineZahl" schreibt, und in das ihr eine Zahl ablegen und jederzeit wieder rausholen könnt. Um der Zahl einen Wert zuzuweisen, benutzt man ein einfaches Gleichheitszeichen:

int meineZahl;
meineZahl = 12;

Da es sich um eine Anweisung (genauer: eine Zuweisung) handelt, muss die Zeile wieder mit einem Semikolon enden. Das Ganze kann man auch in einem Schritt machen:

int meineZahl = 12;

Dabei müsst ihr beachten, dass die Variable auf der linken Seite des Gleichheitszeichens immer den Wert auf der rechten Seite des Gleichheitszeichens zugewiesen bekommt. ("12 = meineZahl" ginge also nicht!) Das ganze geht auch mit Variablen:

int meineZahl = 12;
int meineAndereZahl = 7;
meineZahl = meineAndereZahl;

Durch die Zuweisung haben jetzt beide Zahlen den Wert 7!


Zuweisungen finden immer von Rechts nach Links statt.


Das Anlegen einer Variablen (oder Funktion) nennt man Deklaration. Das erste Mal, wenn eine Variable mit einem Wert belegt wird, ist die so genannte Initialisierung. Beides kann man auch gleichzeitig für mehrere Variablen vom gleichen Typ machen, nämlich indem man die Variablen durch Kommas (für Germanisten: Kommata) trennt und das ganze wie immer mit einem Semikolon abschließt:

int a = 12, b = 235, c = 5237, d, e = 23;

Hinweis:
In diesem Beispiel hat "d" noch keinen Wert bekommen. Das heißt aber nicht, dass es einen Fehler gibt, wenn ihr jetzt auf d zugreift, sondern bloß, dass d immernoch den Wert hat, der vorher an der Stelle im Speicher lag, wo d sich jetzt eingenistet hat. Das kann 0 sein, muss es aber nicht.

Hier ein kleines Beispielprogramm zu dem, was wir bisher hatten:

#include <iostream>

using namespace std;

int main(){
    int attacke = 12, parade = 8;
    float goldvorrat = 23.65;
    char charakterklasse = 'k';
    bool istMagiebegabt = true;
    string name = "Irenicus";

    cout << "Attackewert: " << attacke << endl;
    cout << "Paradewert: " << parade << endl;
    cout << "Charakterklasse: " << charakterklasse << endl;
    cout << "Magiebegabt? " << istMagiebegabt << endl;
    cout << "Name: " << name << endl;

    cin.get();
    return 0;
}

Das Programm initialisiert ein paar Variablen und gibt sie dann aus, jeweils mit einer kleinen Anmerkung um was es sich handelt. Natürlich könnten wir das auch ohne Variablen machen, indem wir direkt in die Gänsefüßchen in der "cout" - Zeile schreiben, was ausgegeben werden soll - aber wenn man sich vorstellt, dass das Programm größer ist und vielleicht noch viele andere Ausgaben mit diesen Werten erzeugt, wird klar, warum diese variante besser ist: wenn wir unseren Charakter z.B. anders benennen wollen, brauchen wir nur an einer Stelle, nämlich bei "name = ..." was zu ändern, und schon sind werden Ausgaben dementsprechend angepasst.

Wenn wir einen Zahlenwert mit einer anderen Zahl addieren wollen, geht das über das Pluszeichen:

int attacke = 12 + 3;

Kein Problem, attacke ist jetzt 15. Wenn wir auf einen Wert etwas draufaddieren wollen, können wir das aber auch so machen:

int attacke = 12;
attacke = attacke + 3;

Dabei wird "attacke" der vorherige Wert zugewiesen, plus 3. Dafür gibt es eine eigene, kürzere Schreibweise:
int attacke = 12;
attacke += 3;

Wenn man den Wert nur um 1 erhöhen will, geht das noch kürzer:

int attacke = 12;
attacke++;

"attacke" hat jetzt den Wert 13. Probiert die Varianten mal aus! Genauso geht das Ganze auch mit "-", "*" ("mal", Multiplikation) und "/" ("geteilt", Division):

int attacke = 12;
attacke /= 2;
attacke *= 3;
attacke--;
attacke -= 2;

Probiert mal, bevor ihr den nächsten Abschnitt lest, zu raten (besser: herauszufinden ;) welchen wert "attacke" nach diesen ganzen Anweisungen hat. Ihr könnt euren Tipp mit der Konsolenausgabe kontrollieren:

#include <iostream>

using namespace std;

int main(){
    int attacke = 12;
    attacke /= 2;
    attacke *= 3;
    attacke--;
    attacke -= 2;
    int parade = 8;
    float goldvorrat = 23.65;
    char charakterklasse = 'k';
    string name = "Irenicus";

    cout << "Attackewert: " << attacke << endl;
    cout << "Paradewert: " << parade << endl;
    cout << "Charakterklasse: " << charakterklasse << endl;
    cout << "Name: " << name << endl;

    cin.get();
    return 0;
}

Hier die Auflösung: Die erste Zeile weist "attacke" den Wert 12 zu - soweit klar. Die zweite Zeile bedeutet ausgeschrieben "attacke = attacke / 2", der Wert wird also durch 2 geteilt.
Wichtig: Bei int - Divisionen wird immer abgerundet, also ist 5 / 2 = 2 und 1 / 2 = 0!

Das Ergebnis ist 6 - nun wird das ganze mit 3 multipliziert (=18), dann wird eins abgezogen, durch die Anweisung "attacke--" (- analog zum Beispiel oben mit "attacke++;"). Nun kommt die letzte Zeile "attacke -= 2", hier wird attacke = attacke - 2, d.h. aus 17 wird... 15!

Wichig ist noch, dass es für den "++" - und den "--" - Operator zwei je Schreibweisen gibt:

int attacke = 12;
attacke--;
attacke++;
--attacke;
++attacke;

Der Unterschied ist erst dann zu sehen, wenn um den Ausdruck "attacke++" oder "++attacke" noch eine Anweisung drum herum steht. Im Fall von "attacke++" wird dann erst die Anweisung drum herum ausgeführt, im Fall von "++attacke" wir der Wert erst um eins erhöht und dann erst die Anweisung ausgeführt. Für "--" funktioniert das Ganze genauso. Beispiel gefällig?

int attacke = 12;
int parade = 8;
parade = attacke++;

"parade" erhält jetzt den Wert von "attacke", und erst dann wird "attacke" um eins erhöht. "parade" ist dann also 12, "attacke" ist 13. Anders siehts aus, wenn ihr "++attacke" verwendet:

int attacke = 12;
int parade = 8;
parade = ++attacke;

In dem Fall wird "attacke" zuerst erhöht und dann auch auf die Variable "parade" übertragen - dann sind beide Werte 13.
[top]

 

3.2 Zeiger und Adressen

Jetzt kommt ein kurzer Abschnitt über das Gemeinste was C++ zu bieten hat, nämlich Zeiger. Zeiger sind, wie der Name schon sagt, Verweise auf eine Speicheradresse, wo dann wiederum in der Regel ein Wert liegt. Die Vorteile von Zeigern werden erst deutlich, wenn man Werte an Funktionen übergibt, deshalb werde ich im Abschnitt über Funktionen nochmal drauf zu sprechen kommen. Einen Zeiger legt man an wie eine Variable, nur mit einem Sternchen als Zeichen dafür, dass er keine Variable vom angegebenen Typ ist, sondern nur auf eine vom angegebenen Typ zeigen kann. Bei der Deklaration zeigt der Zeiger erstmal nirgendwo hin.

int* zeiger;

Soweit ist hoffentlich alles klar. Es ist auch möglich, das Sternchen auf die Seite des Variablennamens zu schreiben:

int *zeiger, attacke = 12;

Jetzt gilt das Sternchen nur für den Zeiger und nicht für "attacke". wenn wir den Zeiger jetzt auf etwas zeigen lassen wollen, brauchen wir eine (virtuelle) Speicheradresse, auf die gezeigt werden soll. Die Adresse einer Variablen kann man sich mit einem bestimmten Zeichen, nämlich dem "&", holen. Das geht zum Beispiel so:

int *zeiger, attacke = 12;
int parade = 8;
zeiger = ¶de;

Merkt euch also: Mit "&" holt man sich die Speicheradresse einer Variablen. Da der zeiger diese Adresse enthält, führt eine Ausgabe des zeigers auch zur Ausgabe der Adressse:

int *zeiger, attacke = 12;
int parade = 8;
zeiger = ¶de;
cout << zeiger << endl;

Probierts mal aus! (Die Speicheradresse wird mit "0x" beginnend ausgegeben, das heißt das die folgende Nummer im Hexadezimalsystem steht.) Wir haben also irgendeine kryptische Nummer ausgegeben bekommen, die uns überhaupt nichts bringt. Wie kommen wir denn jetzt an den Wert der Variablen, auf die der Zeiger verweist? Auch dafür gibt es einen Operator, der leider wiedermal das Sternchen ist. Das steht also, je nach Zusammenhang, für die Deklaration eines Zeiger, die Multiplikation, oder eben, wie in der letzten Zeile des folgenden Beispiels, für das Holen der Variablen, auf die der Zeiger verweist:
int *zeiger, attacke = 12;
int parade = 8;
zeiger = ¶de;
cout << *zeiger << endl;

Nur ein Sternchen mehr als oben, und schon bekommen wir statt der Adresse des Zeigers den wert, auf den er zeigt, ausgegeben, in diesem Fall den wert von "parade". Merkt euch also hier: Mit * holt man sich den Wert, auf den ein Zeiger zeigt.
Also... &holt Adresse zur Variablen... * holt Wert zum Zeiger... . Interessant wird das ganze nachher bei den Funktionen und Objekten. Nach dem Abschnitt über Referenzen wirds wieder etwas praktischer, versprochen... ;)
[top]

 

3.3 Referenzen

Referenzen sind so etwas ähnliches wie Zeiger, werden aber im Programmcode anders behandelt, nämlich einfacher. Die C++ - Leute haben gesehen, dass dieses ganze Adressen - holen und Variablen - zum - Zeiger - holen leicht verwirrend sein kann und daher die Referenzen eingeführt. Dabei ist ein Zeiger ja eigentlich auch eine "Referenz" (also ein "Verweis") auf ein Objekt, aber man musste ja irgeneine treffenden Bezeichnung für das neue Konstrukt finden. Referenzen haben die Besonderheit, dass sie direkt initialisiert werden müssen. Das Zeichen für eine Referenz ist... das hier: & ... Verwirrung... . Wenn ihr eine Adresse holen wollt verwendet ihr das Zeichen ebenfalls, wie wir oben gesehen haben, aber wenn man es hinter den Namen des Datentyps bei der Deklaration und Initialisierung einer Referenzvariablen setzt, heißt es eben, dass es sich bei der angelegten Variable um eine Referenz handelt. Beispiel:

int parade = 8;
int& referenz = parade;
cout << referenz << endl;

Wie gesagt, ihr müsst die Referenz sofort initialisieren, in diesem Fall wurde die Referenz mit "parade" initialisiert. Die Ausgabe gibt euch somit auch direkt "parade" aus. Wie man sieht, verhält sich die Referenz wie eine Kopie der Variablen - sie ist jedoch ein Zeiger. Der Unterschied wird im folgenden Beispiel deutlich:

int parade = 8;
int& referenz = parade;
parade = 17;
cout << referenz << endl;

Wir haben die Referenz als Verweis auf "parade" angelegt und danach nur "parade" (nicht "referenz"...) verändert - trotzdem hat sich der Wert für "referenz" mitverändert, wie die Ausgabe beweist. Referenzen können also wie einfache Variablen behandelt werden, sind aber keine Kopien sondern Verweise. Auch auf Referenzen und ihren eigentlichen Nutzen werde ich im Abschnitt über Funktionen nochmal eingehen.
[top]

 

3.4 Arrays

Bisher haben wir Werte immer einzeln verwaltet, d.h. für eine Reihe von Werten haben wir immer auch eine Reihe von Variablen benutzt. Das wir allerdings auf die Dauer ziemlich umständlich.
Nehmen wir an, der Charakter in unserem fiktiven RPG hat einen Rucksack, ein Inventar. Das Inventar besteht aus 16 * 8 Feldern, auf denen Gegenstände abgelegt werden sollen. Die Gegenstände haben Nummern, anhand derer wir sie zuordnen können, z.B.:
0 = kein Gegenstand
1 = kleiner Heiltrank
2 = großer Heiltrank
3 = kleiner Manatrank
4 = großer Manatrank
5 = kleiner Dolch
... und so weiter. Wenn wir bei dem bleiben, was wir bisher wissen, sähe das Inventar z.B. so aus:

int platz1 = 1; //auf Platz 1 liegt ein kleiner Heiltrank
int platz2 = 5; //auf Platz 2 liegt ein kleiner Dolch
int platz3 = 0; //auf Platz 3 liegt nix

... und so weiter. Was sind eigentlich diese Schrägstriche ("//")? Ganz einfach: Wenn ihr zwei Schrägstriche hintereinander schreibt, wird alles was in derselben Zeile dahinter kommt vom Compiler ignoriert. Das heißt, ihr könnt euch auf diese Weise Notizen in euren Code schreiben. Macht davon ordentlich Gebrauch, um euch zu behalten was ihr noch nicht so gut kennt. (Sonst kann es sein, dass ihr die Datei zwei Wochen später öffnet und überhaupt nicht mehr wisst, was ihr da eigentlich geschrieben habt ;)
Kommentare könnt ihr auch über mehrere Zeilen schreiben. Dazu müsst ihr den Kommentar mit "/*" beginnen und mit "*/" abschließen. Aber zurück zum Thema: wenn wir für jeden Platz eine einzelne Variable anlegen, dauert das ganz schön lange für 16 * 8, also immerhin 128 Felder. Stellt euch vor ihr wollt das ganze ausgeben - dann müsst ihr alle 128 Variablen einzeln durchgehen. Das ist praktisch nicht machbar. Zum Glück gibt es eine Möglichkeit, das ganze Inventar in einer einzigen Variable abzulegen. Dies ist der (das?) so genannte Array. Ein Array ist eigentlich nichts anderes als eine Liste. Wenn ihr ein Array anlegt, müsst ihr angeben, wie viele Elemente in die Liste passen. Das Anlegen unserer Variable für das ganze Inventar klappt dann problemlos in einer Zeile, und zwar so:

int inventar[128];

Erst kommt der Datentyp der Listenelemente, in diesem Fall "int", dann die Kapazität des Arrays. Die Zahl in Klammern gibt also an, wieviele "int" - Variablen im Array gespeichert werden. Dabei hat sich das Array jetzt einfach eine bestimmte Menge Speicher gekrallt. Der speicher ist praktisch noch nicht verändert, also wissen wir nicht welche Werte jetzt gerade im Array liegen. Wenn wir alle Werte gleich zu Anfang auf 0 setzen wollen, gibt es eine spezielle Anweisung dafür - das ganze klappt aber nur bei der Deklaration, also nur wenn ihr das Array anlegt:


int inventar[128] = {};

Jetzt sind alle Elemente auf 0 gesetzt. Die geschweiften Klammern geben an, was das Array enthält. Wenn ihr bei der Deklaration Werte für einzelne Elemente angeben wollt, müsst ihr die Werte durch Kommas (Kommata) trennen. Es geht also alternativ auch so:

int inventar[128] = {1,2,3};

Jetzt haben wir das erste Element auf 3, das zweite auf 2 und das dritte auf 3 gesetzt. Alle anderen Elemente werden automatisch auf 0 gesetzt. Wir können jetzt auf die Elemente zugreifen, indem wir wieder die eckigen Klammern verwenden, um anzugeben welchen Platz im Array wir haben wollen.
Wir bekommen dann den Gegenstand (bzw. die Nummer des Gegenstandes) zu einem bestimmten Inventarplatz ausgegeben. Probierts mal aus, und guckt euch an welche Nummer ausgegeben wird wenn ihr das folgende Programm verwendet:

#include <iostream>

using namespace std;

int main(){
    int inventar[128] = {1, 2, 3};
    cout << inventar[2] << endl;

    cin.get();
    return 0;
}

Ganz klar... Nummer 3. Aber wieso 3? Wir haben doch die Nummer 2 an Platz 2 abgelegt! Das stimmt zwar, aber die Besonderheit liegt darin, dass wir gar nicht Platz 2 ausgegeben haben. Das Array beginnt nämlich bei der Nummerierung der Elemente mit 0 und nicht mit 1. Das heißt, inventar[0] wäre das 1. Element. Das 128. Element ist dann logischerweise inventar[127].
Vorsicht: Wenn ihr trotzdem auf das Element inventar[128] oder z.B. Inventar[129] zugreift, wird keine Fehlermeldung ausgegeben! Das Programm kontrolliert also nicht, ob ihr bei eurem Zugriff die Grenzen des Arrays einhaltet. Das kann zu ziemlich gemeinen Fehlern führen, denn ihr bekommt dann irgendeinen Wert von einer bestimmten Stelle im Speicher. Das ganze kann man sich in etwa so vorstellen wie unten auf dem Schaubild.



Das Array und verschiedene Zugriffe. Zugriffe über die Arraygrenzen sind möglich und deshalb tückisch.

Zugriffe können dabei sowohl lesend, wie im Beispiel oben, als auch schreibend stattfinden. Das ganze funktioniert über ganz normale Zuweisungen. Hier ein Beispiel, bei dem unser Held erst nichts trägt und dann einen Heiltrank aufnimmt:

#include <iostream>

using namespace std;

int main(){
    int inventar[128] = {};
    cout << "Inventarplatz 0: Gegenstand Nr." << inventar[0] << endl;
    //kleinen Heiltrank aufnehmen in Platz 0 des Inventars:
    inventar[0] = 1;
    cout << "Inventarplatz 0: Gegenstand Nr." << inventar[0] << endl;

    cin.get();
    return 0;
}

Wenn wir allerdings das ganze Inventar durchgehen möchten, z.B. um einen Gegenstand zu suchen oder alle Gegenstände nacheinander auszugeben, brauchen wir trotzdem noch eine Menge Zugriffe, die wir alle einzeln angeben müssen.
wir bräuchten also eine Methode, mit der wir das Inventar automatisch Schritt für Schritt durchlaufen könnten. Eine Möglichkeit ist die so genannte for - Schleife, die wir gleich noch kennen lernen werden.

 

3.5 Strukturen

Bevor wir auf die Schleifen zu sprechen kommen, hier noch zwei Konstrukte die man kennen sollte: Die so genannten Strukturen und das typedef - Schlüsselwort.
Strukturen sind eine Art eigener Datentyp, welcher mehrere Variablen speichert. So könnten wir z.B. aus unserem Held eine Struktur machen. Seine Daten wären dann z.B:
- Der Name (eine Zeichenkette)
- Die Charakterklasse (ein Buchstabe)
- Der Attacke - Wert (eine Zahl)
- Der Parade - Wert (eine Zahl)
- Das Inventar (ein Array von Zahlen)
- Der Goldvorrat (eine Kommazahl)
Wenn wir eine Struktur anlegen, die diese Elemente enthält, geht das ganz einfach. Wir schreiben das Schlüsselwort struct, dann den Namen der struktur und dann die Elemente in geschweiften Klammern. Das ganze beenden wir dann noch mit einem Semikolon. Beispiel:

#include <iostream>

using namespace std;

int main(){
    struct held {
      string name;
      char charakterklasse;
      int attacke;
      int parade;
      int inventar[128];
      float goldvorrat;
    };

    struct held held1;

    held1.name = "Hans";
    held1.attacke = 12;

    cout << held1.name << " hat den Attacke - Wert " << held1.attacke << endl;

    cin.get();
    return 0;
}

Dabei haben wir zuerst eine Struktur namens "held" definiert. Dann haben wir ein Exemplar dieser Struktur angelegt, mit der Zeile struct held held1. Das Exemplar hat den Titel "held1". Das "struct" in dieser Zeile kann man auch weglassen, aber es ist ganz nützlich, weil es einen daran erinnert, dass es sich um eine struktur handelt.
Wenn wir jetzt auf die Elemente der Struktur, auch "Members" genannt, zugreifen wollen, schreiben wir einen Punkt hinter den Namen der Struktur und dann die Bezeichnung der Member - variablen, z.B. "held1.name". So kann man auf die Membervariable "name" zugreifen und den Namen des Helden auslesen oder ändern. Genauso wurde das Ganze mit "attacke" gemacht. Die Ausgabeanweisung gibt uns die Werte einmal aus.
Der Vorteil dieser Strukturen? Ganz einfach: wenn wir mehr als einen Helden anlegen wollen, entfällt für jeden Helden das anlegen der nötigen Variablen für Attacke, Parade usw., statt dessen legen wir einfach eine neue Struktur an, die dann direkt die passenden Variablen enthält. Auch dazu ein Beispiel - so sähen die Deklarationen für zwei Helden ohne die held - Strukur aus:

string nameHeld1, nameHeld2;
char charakterklasseHeld1, charakterklasseHeld2;
int attackeHeld1, attackeHeld2;
int paradeHeld1, paradeHeld2;
int inventarHeld1[128], inventarHeld2[128];
float goldvorratHeld1, goldvorratHeld2;

...und so mit der "held" - Struktur:

struct held held1;
struct held held2;

 

3.6 Das typedef - Schlüsselwort

Das typedef - Schlüsselwort ist schnell erklärt. Es ermöglicht euch eigene Namen für bestimmte Datentypen. Wenn ihr z.B. die Deklaration

const unsigned int MAXIMALE_ERFAHRUNGSPUNKTE = 20000;

betrachtet, fällt auf, dass sie ganz schön lang ist. "const" steht dabei für "Konstante", also eine Variable die man im Programmverlauf nicht mehr ändern möchte (und dann auch nicht mehr ändern kann) - const - Variablen müssen ihren Wert direkt bei der Deklaration mitgegeben bekommen und werden typischerweise in Großbuchstaben geschrieben - so erkennt man, dass es sich um Konstanten handelt.
Um die lange Deklaration und andere dieser Art abzukürzen kann man das typedef - Schlüsselwort benutzen. Man schreibt "typedef", dann die Deklaration wie sie ist und dann wie man sie nennen möchte, z.B.:

typedef const unsigned int CUINT;

Jetzt können wir schreiben:

CUINT MAXIMALE_ERFAHRUNGSPUNKTE = 20000;
CUINT MAXIMALE_LEBENSPUNKTE = 360;

... und so weiter. Wenn ihr also irgendwo auf komische Datenypen stosst, die nicht zu C++ gehören, können sich dahinter umbenannte Standarddatentypen verbergen.

 

4. Kontrollstrukturen: Schleifen und Abfragen

 

4.1 Die for - Schleife

Nun also zu der oben schon erwähnten for - Schleife. Eine for - Schleife sieht etwa folgendermaßen aus:

for (int i = 0; i < 10; i++){
  //etwas tun...
}

Die Variable "i" wird beim Eintritt in die for - Schleife angelegt und gilt nur für die Dauer der Schleife, also innerhalb der geschweiften Klammern. "i" bekommt einen Startwert, dass geschieht bei der ersten Anweisung innerhalb der Schleife: "int i = 0;". (Dabei kann man für "i" jeden beliebigen Bezeichner wählen, aber üblicherweise heißt das Ding "i".) "i" ist die so genannte Laufvariable. Diese wird jetzt so lange verändert, wie die Bedingung der Schleife gilt. Die Bedingung steht an zweiter Stelle nach der Initialisierung der Laufvariablen, hier ist die Bedingung "i < 10" - das heißt, die Schleife wird so lange ausgeführt, wie "i" kleiner als 10 ist. Der dritte Teil in der Klammer, hier "i++", bestimmt wie die Laufvariable bei jedem Schritt verändert wird. In unserem Fall wird "i" bei jedem Schritt um 1 erhöht.
Dabei geht die Schleife so for: (sorry, das konnte ich mir nicht verkneifen;)

1. Initialisiere die Laufvariable!
2. Kontrolliere ob die Bedingung erfüllt ist!
    2.1 Wenn nein: verlasse die Schleife!
    2.2 Wenn ja:
        - führe die Anweisung(en) in den geschweiften Klammern aus!
        - verändere die Laufvariable!
        - kehre zu 2. zurück!

Schauen wir uns das ganze mal an einem Beispiel an. Diese Schleife gibt die Zahlen von 1 bis 10 in die Konsole aus:

for (int i = 1; i < 11; i++){
  cout << i << endl;
}

Probiert das ganze mal aus, und versucht vielleicht auch mal ein paar Varianten. (Mittlerweile dürfte hoffentlich klar sein, wie das Programm drumrum auszusehen hat: ihr schreibt die Schleife einfach in die "main" - Funktion - natürlich vor das "return 0", denn da ist die Funktion ja fertig!)
Oben hab ich immer geschrieben, dass die Laufvariable "verändert" wird, nicht "erhöht" - das hat den Grund, dass ihr frei entscheiden könnt, was mit der Variable bei jedem schritt gemacht werden soll. Guckt euch diese Beispiele an:

cout << "Schleife 1:" << endl;
for (int i = 10; i > 0; i--){
  cout << i << endl;
}

cout << "Schleife 2:" << endl;
for (int i = 0; i < 17; i += 2){
  cout << i << endl;
}

cout << "Schleife 3:" << endl;
for (int i = 32; i > 0; i /= 2){
  cout << i << endl;
}


Die for - Schleife ist sehr praktisch um Arrays auszugeben oder zu füllen. Beispiel:

int inventar[128];
for (int i = 0; i < 128; i++){
  inventar[i] = 1;
}

Jetzt haben wir das Array mit Einsen, also das ganze Inventar mit Heiltränken gefüllt. (Wieviel Sinn das macht ist eine andere Frage ;)
Um ein Array auszugeben kann die for - Schleife natürlich auch benutzt werden:

int inventar[128];
for (int i = 0; i < 128; i++){
  cout << inventar[i] << endl;
}

Jetzt bekommen wir mithilfe dieser wenigen Zeilen den Inhalt des kompletten Inventars ausgegeben.

 

4.2 Die while - Schleife

Außer der for - Schleife gibt es noch einen weiteren wichtigen Schleifentyp: die while - Schleife.
Dabei werden die Anweisungen in den geschweiften Klammern so lange wiederholt, wie die Bedingung in den Klammern hinter dem Schlüsselwort while gilt. Gilt diese nicht, wird die Schleife gar nicht erst ausgeführt. Beispiel:
int zahl = 0;
while (zahl < 11){
  zahl++;
  cout << zahl << endl;
}

Jetzt bekommen wir eine ähnliche Ausgabe wie schon bei den for - Beispielen: Die Zahlen von 1 bis 10.
Der Ablauf im Detail sieht so aus: zuerst wird "zahl" mit 0 initialisiert. Dann kommt die while - Schleife und prüft, ob die Bedingung ("zahl < 10") gilt. Weil das der Fall ist, werden nun die Anweisungen in der Schleife ausgeführt: "zahl" wird erhöht und danach ausgegeben. Jetzt springt das Programm wieder zur Bedingung und überprüft, ob noch ein weiterer Durchlauf stattfinden kann.
Stellt euch jetzt vor, die Variable würde statt 0 mit 11 initialisiert. Dann würde die Schleife nicht vom Programm betreten. Manchmal möchte mann aber, dass die Anweisungen in Klammern (auch "Schleifenrumpf" genannt) wenigstens ein Mal ausgeführt werden. Dafür gibts eine Variante der while - Schleife, die "do - while - Schleife". Beispiel:

int zahl = 11;
do {
  zahl++;
  cout << zahl << endl;
} while(zahl < 11);

Jetzt bekommen wir die 12 ausgegeben. Dann wird die Bedingung überprüft und festgestellt dass sie nicht gilt - daher werden die Anweisungen nicht noch einmal ausgeführt und es geht weiter im Programm.

 

4.3 Die if - Abfrage

Jetzt kommen wir zu einem wichtigen und sehr einfachen Element: der Abfrage. Die if - Abfrage prüft einfach nur eine Bedingung und führt, sollte die Bedingung erfüllt sein, die Anweisungen in den folgenden Klammern aus. Das ganze funktioniert also wie die while - Schleife, nur ohne Wiederholung.
Ein kurzes Beispiel:

if (attacke < 0){
  cout << "Attacke hat einen negativen Wert!" << endl;
}

Hier wird geprüft ob "attacke" kleiner als Null ist und gegebenenfalls eine Meldung ausgegeben. Bisher hatten wir nur die "<" (= "kleiner als") und die ">" (= "größer als") - Bedingung.
Hier andere mögliche Bedingungen: (mit a und b als "int" - variablen)

a &tl;= b Hier wird geprüft ob a kleiner oder gleich b ist.
a >= b Hier wird geprüft ob a größer oder gleich b ist.
a != b Hier wird geprüft ob a ungleich b ist.
a == b Hier wird geprüft ob a gleich b ist.

Das doppelte Gleichheitszeichen ist wichtig: wenn ihr hier ein einfaches Gleichheitszeichen setzt, findet eine Zuweisung statt.
Dabei müsste der Compiler dann doch eigentlich einen Fehler melden, oder? Schließlich ist eine Zuweisung keine Bedingung, und in den Klammern sollte doch ein Bedingung stehen! Wenn wir allerdings sowas hier schreiben...

if (attacke = 5){
  cout << "Blablabla" << endl;
}

..., bekommen wir keinen Compilerfehler, denn das Programm prüft hier wirklich eine Bedingung, nämlich die Variable "attacke". Dabei wird geprüft, ob "attacke" einen Wert ungleich Null hat. Das hängt mit den booleschen Variablen zusammen, die ja immer "true", also 1, oder "false", also 0 sein müssen - wenn man prüfen will, ob eine boolesche Variable gleich "true" ist, existiert für diesen Code

if (bedingung == true){

die Kurzschreibweise

if (bedingung){

, welche einfach prüft ob die boolesche Variable "bedingung" ungleich "false" und damit ungleich 0 ist. Genau das wird im Beispiel oben auch mit unserem "attacke" gemacht. Verwirrt? Dann probierts einfach mal aus! Merkt euch: bei Bedingungen prüft ein doppeltes Gleichheitszeichen, ob zwei Variablen den gleichen Wert haben.
Wichtig ist außerdem das Schlüsselwort "else" - hier wird an die if - Abfrage einfach ein zweiter Block angehängt, der nur dann ausgeführt wird, wenn die Bedingung hinter dem "if" nicht wahr ist. Ein Beispiel dazu:

if (attacke < 0){
  cout << "Attacke hat einen negativen Wert." << endl;
} else {
  cout << "Attacke hat einen positiven Wert oder ist Null." << endl;
}

Hinweis: Ihr könnt übrigens auch die geschweiften Klammern beim "if", "else", "for" oder "while" weglassen - unter einer Bedingung: es darf nur eine einzige Anweisung für das jeweilige Konstrukt folgen.
Das ist aber nicht ratsam wenn ihr Anfänger seid und noch das Gefühl habt, schnell den Überblick zu verlieren - insbesondere bei mehreren kombinierten "if ...else" - Anweisungen kann schnell unklar werden, zu welchem "if" das "else" dann gehört - der gefürchtete "dangling else" - Fehler.
Wichtig ist außerdem, dass ihr Bedingungen verknüpfen könnt. Dabei steht "&&" für ein "und" und "||" für ein "oder". Beispiel:

if (attacke > 0 || attacke == 0){
  cout << "Attacke hat einen positiven Wert oder ist Null." << endl;
}

(Natürlich kann man in diesem Fall auch direkt ">= 0" schreiben, aber es ist ja nur zur Demonstration ;)
[top]

 

4.4 Die if - Abfrage (für Freaks)

Der Vollständigkeit halber hier noch eine freakige, extrem kompakte Form der if -Abfrage:

attacke = (attacke < 0) ? 0 : attacke;

Hier wird attacke ein Wert zugewiesen. Wenn die Bedingung in Klammern erfüllt ist, wird der Wert nach dem Fragezeichen zugewiesen, sonst der nach dem Doppelpunkt. Das heißt, in diesem Fall wir attacke auf 0 gesetzt, wenn die Variable einen negativen Wert enthält ( - ansonsten wird attacke = attacke gesetzt, es passiert also nichts). Das muss man nicht unbedingt auswendig können, aber man sieht es eben ab und zu.

 

5. Ein Übungsspiel

Hier also ein kleines Spiel, um das was wir bisher hatten auszuprobieren und zu üben. Damit das Spiel auch Eingaben entgegen nehmen kann, benötigt ihr die cin - Anweisung, die genau wie "cout" funktioniert - nur eben umgekehrt. Statt Daten auf den Ausgabestrom zu legen, werden sie vom Eingabestrom in Variablen gespeichert. Beispiel:

#include <iostream>

using namespace std;

int main(){
    string name;
    int alter;

    cout << "Wie heisst du?" << endl;
    cin >> name;
    cout << "Wie alt bist du?" << endl;
    cin >> alter;
    cout << "Du heisst " << name << " und bist " << alter << " Jahre alt." << endl;

    cin.ignore();
    cin.get();
    return 0;
}

Ich glaub ich brauche nicht mehr zu erklären was das Programm macht ;) Die Besonderheiten: Die ">" - Zeichen stehen bei "cin" genau andersrum als bei "cout". Ausserdem hab ich noch ein "cin.ignore" vor unserer "cin.get()" - Zeile zum Anhalten der Konsole eingebaut. Das hat den Grund, dass "cin" sich das letzte Enter - Zeichnen, welches eine Eingabe abschließt, merkt, es aber nicht ausgibt bzw. in unsere Variable schreibt. Dadurch liegt es noch im Puffer von "cin" und wird mit "cin.get()" gelesen - das Programm schließt sich dann sofort. Mit "cin.ignore" wird cin angewiesen, das nächste Zeichen im Puffer zu ignorieren und wartet dann bei "cin.get()" auf eine weitere Eingabe.

Hinweis: Es ist nicht so wichtig, sich zu merken warum dass jetzt so ist. Es können noch mehr Probleme auftreten, z.B. wenn ihr ein Leerzeichen in eurem Namen habt und diesen eingebt. Auch dazu gibts natürlich Lösungen, wie z.B. die "getline" - Anweisung, aber es lohnt sich nicht, sich unnötig lange mit Konsoleneingabe herumzuschlagen - wir wollen ja eigentlich Spiele mit grafischen Oberflächen programmieren, und die Konsoleneingabe braucht man da so gut wie nie.

Jetzt also zur Aufgabenstellung:
Es soll ein kleines Spiel programmiert werden, bei dem der Benutzer zuerst seinen Namen eingeben muss. Dann wird er begrüsst, und kann ein Ratespiel spielen. Dabei hat er 10 Versuche, eine Zahl zwischen 0 und 20 zu erraten, welche im Programmtext festgelegt ist.
Wenn er keine Lust mehr hat, gibt er einfach eine negative Zahl oder eine Zahl über 20 ein, und das Programm wird beendet. Wenn er eine gültige Zahl im Bereich zwischen 0 und 20 eingegeben hat, wird geschaut ob diese größer oder kleiner als die geheime Zahl ist, oder vielleicht sogar richtig geraten wurde. Wenn richtig geraten wurde, ist das Programm fertig und es erscheint eine Meldung, die den Spieler beglückwünscht. Ansonsten erscheint eine Meldung, welche angibt ob die eingegebene Zahl zu groß oder zu klein war, und es geht beim nächsten Versuch weiter. Wenn ihr möchtet, könnt ihr bei jedem Schritt die Anzahl der verbleibenden Versuche mit angeben.
Ihr braucht dabei z.B.:
- eine string - Variable für den Namen des Spielers
- drei int - Variablen: die geheime Zahl, die eingegebene Zahl und die Anzahl der (verbleibenden) Versuche
- eine boolesche Variable: wurde richtig geraten? (Eventuell: wurde abgebrochen?) - eine while - Schleife

Ich habe "z.B." geschrieben, weil es für den ein oder anderen Punkt auch andere Möglichkeiten gibt. Wenn ihr möchtet, schickt mir eure Lösung, dann baue ich sie eventuell in den nächsten Teil ein, wo wir uns ein paar Lösungsmöglichkeiten angucken werden.
So könnte das Programm in Aktion aussehen:




Ihr müsst dabei wissen, dass ihr die bisher erlernten Elemente auch ineinander verschachteln und so z.B. eine "if" - Abfrage innerhalb einer "while" - Schleife verwenden könnt.
Wenn euch das zu langweilig ist, hilft vielleicht noch eine Zusatzaufgabe, wenn das Spiel bis hier fertig ist: Wenn eine Zahl nicht erraten wurde, soll die richtige Zahl in einer Liste, die ausgegeben wird, markiert werden, etwa so:



So, ich wünsch euch viel Spaß, Erfolg und Geduld damit - bis zum nächsten Mal!

Dieses Tutorial wurde vom Isogames.de Mitglied Max_A_L geschrieben!

Kommentare
kurdt am 25. März 2008 23:44
Nur kurz:
Sollte man bei 5. Ein Übungsspiel nicht noch:

#include <string>





machen, da es ansonsten Problem bei string name; geben könnte.

Aber so, was ich jetzt kurz überflogen habe sieht sehr gut aus.
Pascal am 26. März 2008 01:37
Schön und gut das Tutorial aber als blutiger anfänger kann ich das wohl am besten bewerten, was zu bemängeln ist:

-Ein mustervorschlag wäre in diesen teil schon ganz gut gewesen oder zumindest ein paar mehr anhaltspunkte, bedenke dieses tutorial lesen sich leute durch (wie ich) die c++ nicht ansatzweise kennen (oder es für katoffelschälen halten ^^) klar man hat vorher alles was man braucht durchgearbitet aber auch nur mit direkten beispiel, da fällt die anwendung in komplexeren Dinge etwas schwer weil der übergang irgentwie nicht da ist.

Ich weiss ich habe irgentwann das Talent mich kurz zu fassen versoffen oder verspielt ^^

mfg Pascalsmiley
kurdt am 26. März 2008 08:22
Hi Pascal,

du kannst es ja erstmal selbst versuchen dieses Übungsprogramm zu schreiben.
Und wenn du dann absolut nicht mehr weiterkommst kannste ja mal im Forum schreiben smiley
Max_A_L am 27. März 2008 12:54
Ja, das mit dem #include <string> ist richtig, aber da es bei mir und allen die ich kenne wohl standardmäßig eingebunden wird, hab ichs weggelassen smiley
Sorry Pascal, wenn das ein bisschen zu wenig Anhaltspunkte waren, ich hatte schon probiert es ausführlich zu machen und befürchtet Leute zu langweilen, aber du hast sicher auch Recht.
Als Programmgerüst war eigentlich das Beispiel mit "gib deinen Namen und dein Alter ein" gedacht, das musst du nur so umändern dass da anstatt <code> int alter </code> jetzt <code> int ratezahl </code> oder sowas steht, da hast du schon die ersten Zeilen smiley
Dann machst du eine Schleife, z.B. mit "while", die solange läuft wie entweder weniger als 10 Versuche verbraten wurden oder die "ratezahl" richtig geraten wurde (also gleich der "geheimen Zahl" ist). Das ist dann der schwierigere Teil, aber wie kurdt schon gesagtm hat, wenns einen Fehler gibt den du nicht findest (was durchaus am Anfang mal vorkommen kann smiley ) schreibs einfach ins Forum oder so!

@ marc: kannst du wenn du mal Zeit hast vielleicht
- die [top] - Links am Ende von Abschnitt 3.1, 3.2, 3.3 und 4.3
- den Verweis auf das Inhaltsverzeichnis in der Einleitung ("Guckt
euch..."smiley
-die kursive Formatierung ab Abschnitt 3.5 (ist wohl irgendwo ein
<i> nicht geschlossen) wegmachen?
Ich lass beim nächsten Teil die Navigation direkt weg, dann musst du dir die ganze Arbeit nicht machen smiley
Danke schonmal!!
Max_A_L am 27. März 2008 12:56
oder die "ratezahl" richtig geraten wurde

muss natürlich heissen "nicht richtig geraten", um die Verwirrung komplett zu machen...smiley sorry!
Naga am 11. April 2008 13:43
ich find das toutoriel is gut für blutige anfänger wie mich gebaut
Altair am 04. Mai 2008 16:41
Richtig gut und leicht eingängig geschrieben. Dieser "kurze" Einstieg hat mir die nötigen Grundkenntnisse viel besser und kompetenter übermittelt, als die paar Bücher über C++, die ich hier rumstehen habe. Auch die häufig aufgeführten Beispiele machen das ganze leicht verständlich. Hab selten so nen guten Artikel gelesen: smiley

Schade aber, dass du nach diesen Grundkenntnissen nicht auf die Spieleentwicklung übergehst, fänd ich echt total super, wenn du das vortführst.

Der Artikel mit dem Weltraumshooter, der wohl für den Übergang geplant war, hat mich leider nicht so sehr angesprochen. smiley
Raptor Reptiel am 06. Mai 2008 09:30
Sehr gursmiley
Felix94 am 16. September 2008 14:03
Ich fand das Tutorial richtig hilfreich und ich binn total happy das ich das Übungsspiel hinbekommen hab!smiley
nemesis am 21. November 2008 18:15
also ich fand das tutorial super(ich bin ja auch so ein blutiger anfänger),aber ich würde gerne etwas wiessen.In dem hier:
#include <iostream>

using namespace std;

int main(){
string richtig = "richtig!!!";
string fehler = "falsch!";
string frageeins = "Wie heist der Schreiber von One Piece (Nachname)?";
string fragezwei = "Wann fand die letzte Fussball-WM in Dt statt?";
string antworteins = "Oda";
int antwortzwei = 2006;
string anteins;
string abschiedvier = "Sie haben die zweite Frage falsch beantwortet!!!";
string abschieddrei = "Sie haben die erste Frage falsch beantwortet!!!";
string abschiedeins = "Sie haben die erste Frage richtig beantwortet!!!";
string abschiedzwei = "Sie haben die zweite Frage rchtig beantwortet!!!";
int antzwei;


cout << frageeins << endl;
cin >> anteins;
if (anteins == antworteins){
cout << richtig << endl;
} else {
cout << fehler << endl;
}
cout << fragezwei << endl;
cin >> antzwei;
if (antzwei == antwortzwei){
cout << richtig << endl;
} else {
cout << fehler << endl;
}
if (anteins == antworteins){
cout << abschiedeins << endl;
} else {
cout << abschieddrei << endl;
}
if (antzwei == antwortzwei){
cout << abschiedzwei << endl;
} else {
cout << abschiedvier << endl;
}
cin.ignore();
cin.get();
return 0;
}
Dafür brauch ich etwas was nicht drinnen war:mit welchem code macht man das z.b. wenn die frage,die antwort und der kommentar geschrieben sind sie verschwinden bevor die nächste frage erscheint?ßß
kurdt am 23. November 2008 11:23
Hi nemesis,

mit folgendem Befehl kannst du die Eingabeaufforderung leeren:

system ("cls"smiley;


kurdt am 23. November 2008 11:24
... dumme Smilies ....

hier noch einmal ohne Smilies:

system ("cls");


Freak am 23. November 2008 19:40
aber da verschwindet der satz davor auch. wie macht man ea so, dass man erst enter drucken muss, damit die zeilen verschwinden?:
kurdt am 28. November 2008 14:25
einfach einen cin.get() einbauen, dann wartet er auf einen Tastendruck.
Downloader44 am 21. Juni 2010 19:43
Hallo , ich weiß das ich etwas späht komme ^^ , aber machst du noch ein zweites Tutorial?

Ich find nämlich das hier echt gut^^

Hoffe du ließt den Kommentar .
mfg Downloader smiley
Kommentar schreiben
Bitte einloggen, um einen Kommentar zu schreiben.
Bewertung
Die Bewertung ist nur für Mitglieder verfügbar.

Bitte loggen Sie sich ein oder registrieren Sie sich, um abzustimmen.

Fantastisch! Fantastisch! 67% [6 Abstimmungen]
Sehr Gut Sehr Gut 33% [3 Abstimmungen]
Gut Gut 0% [Keine Abstimmungen]
Durchschnittlich Durchschnittlich 0% [Keine Abstimmungen]
Schlecht Schlecht 0% [Keine Abstimmungen]
Login
Username

Passwort



Noch kein Mitglied?
Klicke hier um dich zu registrieren.

Passwort vergessen?
Fordere Hier ein neues an

Letzer Artikel
01 - Creating a 2D G...
Quellcode-Dokumentat...
IsoGuide Teil 2
C++ Basics
Teil 3: Serie zur En...

Letzten Kommentare
Artikel Kommentar Aber da ich mich die l...
Artikel Kommentar Hallo , ich weiß das i...
Artikel Kommentar Ich habe für einige In...
Artikel Kommentar Sehr schöner Beitrag! ...
Artikel Kommentar Wann kommt denn nun da...

Mitgliederstimme
Welche Programmier-/Scriptsprache benutzt du für dein derzeitiges Projekt?

C/C++

C#

Basic

Actionscript

PHP

Pascal/Delphi

Java

Andere

Du musst dich einloggen, um zu voten.

Partner
GameDev.de
GFX-Sector - Your GFX-Source No. 1
Partner werden!

 
Copyright © 2008 Isogames.de

733945 Eindeutige Besuche