Im einfachsten Fall
beschafft
man sich eine IDE (integrated development environment) wie z.B.
Code::Blocks oder eine
kostenlose Version von MS Visual Studio (Express oder Community).
Diese IDE
enthalten
die notwendigen Werkzeuge Editor,
Compiler und Linker.
Wichtig: Auf optionale Zuschaltung der Neuerungen des C++-ISO-Standards
von 2011 bei den Compilereinstellungen achten.
Dieses Tutorial soll Ihnen einen
Einstieg in die Erstellung von Konsolen-Programmen mit der
objektorientierten Sprache C++ ermöglichen. Konsolen-Programme sind das
Gegenstück zu "Windows"-Programmen und entstammen den
Anfängen der Programmierung.
Ein- und Ausgaben erfolgen
hier primär textorientiert.
Obwohl diese Programme aus der "EDV-Steinzeit" stammen, sind sie zum Einstieg in C++ gut geeignet. Man konzentriert sich hier auf die eigentliche Problemlösung und die wesentlichen Programmiergrundlagen und nicht von Anfang an auf die grafische Gestaltung.
Beginnen wir mit einem
rudimentären
Beispiel:
int main()
{ return 0; // ist laut C++-ISO-Standard von 1998 nicht mehr notwendig, wird daher in Folge weggelassen. } |
Der C++-Compiler - das ist das
Programm,
das
Ihren Sourcecode in ausführbaren Code übersetzt - sucht in C
und
C++ die Funktion main() als Einstiegspunkt. Vor dem main() steht ein int,
das
für den Variablentyp Integer (Ganzzahl) steht. Ein
aktueller
Compiler gibt automatisch die Null als Wert zurück, wenn das
Programm
normal beendet wird.
Das Ergebnis bei Ausführung der resultierenden exe-Datei sieht dann z.B. in der Konsole ("DOS-Box") von MS Windows wie folgt aus:
Was können wir auch mehr erwarten?
Wenn Sie diese Ausgabe sehen, ist es Ihnen aber immerhin gelungen, mit
dem Programmierwerkzeug, das Ihnen zur Verfügung steht, eine
ausführbare exe-Datei zu erzeugen.
Übrigens sehen viele Einsteiger
zunächst
nur ein kurzes Aufblitzen
dieser Box. Daher muss man das
Schließen
am Programmende verhindern. Der einfachste Weg, dies zu erreichen, ist
der
Einbau der ursprünglich von Borland stammenden Funktion getch()
bzw. _getch() aus conio.h. Dies entspricht leider nicht dem
C++-Standard,
ist aber unter MS Windows ziemlich praktisch.
Um portables C++ zu schreiben,
verwendet man eine eigene Funktion wait() wie folgt:
#include
<iostream> #include <limits> void wait() { std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::cin.get(); } int main() { wait(); } |
Nun wollen wir sofort etwas mehr
erreichen. Im
nachfolgenden Programm deklarieren wir eine Integer-Variable namens zahl.
Wir lesen einen Wert über die
Tastatur ein, den wir in dieser Variable speichern. Anschließend geben wir das Quadrat
dieses Wertes auf dem Bildschirm aus:
#include <iostream> #include <limits> using namespace std; void wait() { std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::cin.get(); } int main() wait(); /*---------------------------------------------------------*/ #include <iostream> int main() wait(); |
Anstelle endl kann man auch '\n'
schreiben. Es gibt aber einen Unterschied: endl entspricht '\n'
(neue Zeile) plus flush (Ausgabepuffer leeren).
Mehrere Anweisungen werden hier zu
einer
Anweisungsfolge verknüpft, in dem sie nacheinander geschrieben
werden.
Dies ist eine einfache Form von
Kontrollstruktur, nämlich die sequenzielle Ausführung.
Zunächst wollen wir verstehen, wie
eine exe-Datei aus unserem Sourcecode entsteht.
Hierzu verwenden wir (wahrscheinlich
unbewusst) drei Werkzeuge:
Precompiler / Präprozessor
Compiler
Linker
Der Precompiler / Präprozessor
durchforstet den Sourcecode, um spezielle Anweisungen
auszuführen. Diese Anweisungen beginnen mit #.
In unserem Beispiel erkennt der
Precompiler #include
<iostream> und setzt an dieser
Stelle den
entsprechenden Sourcecode ein. Auf diese Weise wird der gesamte
Sourcecode
bearbeitet. Der resultierende Sourcecode (cpp) wird dem Compiler
übergeben.
Dieser erzeugt eine Objektdatei (o). Diese wird vom Linker
in
eine lauffähige Programmdatei (z.B. exe)
überführt.
In C++ verfügt man über
sogenannte "namespaces". Namensräume
sollen dem Programmierer helfen, bei gleichen Namen für Variablen,
Klassen
etc. Konflikte zu vermeiden. Der
Standard-Namespace
wird mit std
bezeichnet.
Gibt
man den Namensraum nicht frei, so muss man den
Namensraum zusätzlich angeben, also std::cout
oder std::cin
schreiben.
Betrachten wir zur Veranschaulichung folgendes C++-Programm:
#include
<iostream> #include <limits> void wait() { std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::cin.get(); } namespace MyCpp { double var; } float var; int main() { int var; std::cout << "globale Variable : " << ::var << std::endl; // 0 std::cout << "lokale Variable : " << var << std::endl; std::cout << "Variable im Namespace: " << MyCpp::var << std::endl; // 0 wait(); } |
Hier wird drei Mal eine
Variable
namens var
ausgegeben. Die Variable innerhalb main() hat
dort ihren
begrenzten
Scope (Sichtbarkeitsbereich). Um die globale Variable var
aufzurufen,
setzt
man :: davor.
Wir können
nun ebenfalls in einem eigenen Namensbereich (hier: MyCpp) eine
Variable
var
erzeugen. Hierbei muss man diese Variable durch Voranstellen der
Bezeichnung
des Namensbereiches und den Operator ::
ansprechen.
cout, cin, endl
gehören zum Namensbereich std. Daher
wird dieser
Namen
vorangestellt. Wollen Sie das vermeiden, gibt es zwei
Möglichkeiten:
a) Man gibt den gesamten Namensbereich std
durch using
namespace std;
frei.
b) Man macht die verwendeten Elemente des Namensbereiches std gezielt
bekannt:
using std::cout;
usw.
Mit int zahl deklarieren
wir
eine
Integer-Variable. Wir reservieren bei einem
32-Bit-Rechner
4 Byte Speicherplatz für eine vorzeichenbehaftete Ganzzahl. 4 Byte
entsprechen
4 * 8 = 32 Bit.
Damit können wir binär einen
Ganzzahlenbereich von 2 hoch 32 = 4 294 967 296 abdecken.
Dieser Bereich ist für int (32 Bit) heutzutage - 2 147 483 648 ... 0 ... 2 147 483 647.
Es gibt auch die Möglichkeit nur
positive Ganzzahlen und die Null zuzulassen. Hierfür stellt man
ein unsigned
vor das int:
unsigned int
umfaßt
0 ... 4 294 967 295 (32-Bit-Maschinen).
Sie sehen, dass int
automatisch
signed
int bedeutet. Solche Details findet man üblicherweise in der
Datei limits.h.
Dort findet man die Grenzen für die
einzelnen Variablentypen: char, short, int, long, ...
... #define
SHRT_MIN
(-32768) /* minimum (signed)
short value */ #if
_INTEGRAL_MAX_BITS >= 8 #if
_INTEGRAL_MAX_BITS >= 16 #if
_INTEGRAL_MAX_BITS >= 32 #if
_INTEGRAL_MAX_BITS >= 64 #if
_INTEGRAL_MAX_BITS >= 128 ... |
cin ist das Standardeingabe-Objekt (Tastatur) und cout das Standardausgabe-Objekt (Bildschirm). Man bezeichnet diese Objekte auch als Streams. Der Doppelpfeil zeigt jeweils die Richtung des Datenflusses an.
Damit nach Ausgabe des Ausdruckes zahl*zahl
ein Zeilenvorschub erfolgt wird entweder endl oder das
Sonderzeichen '\n'
gesendet.
endl leert den
Ausgabepuffer
(entspricht flush
und setzt ein "newline"). Hier finden Sie einige Möglichkeiten
für solche
Sonderzeichen, die noch aus der Zeit der Programmiersprache C stammen:
\n | Zeilenvorschub | RETURN bei der Tastatureingabe |
\r | Carriage Return | Zeilenende besteht aus \n\r |
\b | Backspace | letztes Zeichen wird gelöscht |
\t | Tabulator | Tabulator-Sprung |
\f | formfeed | Druckerausgabe: Seitenvorschub |
\0 | NULL | String-Endmarkierung |
\\ | Backslash | erzeugt ein \ auf dem Bildschirm |
\' | Hochkomma | erzeugt ein ' auf dem Bildschirm |
\" | Anführungszeichen | erzeugt ein " auf dem Bildschirm |
Wenn Sie nun die Zahl 12 eingeben, erhalten Sie die entsprechende Quadratzahl 144:
An unserem einfachen Quadratzahl-Programm können Sie bereits eine Menge testen.
Zunächst geben wir 10 000 oder -10
000 ein und erhalten mathematisch korrekt die Quadratzahl 100 000 000.
Anders sieht es bei 100 000 aus. Hier
erhalten wir nicht 10 000 000 000, sondern völlig falsch 1 410 065
408.
Das liegt daran, daß bei 2 147
483 647 plus 1 die Zählweise wieder von vorne beginnt, also
bei - 2 147 483 648.
Man spricht hier von einem
"Überlauf". Genau genommen liegt es daran, dass das höchste
Bit das Vorzeichen signalisiert. Ist es gesetzt, ist die Zahl negativ,
wenn nein, dann ist sie
positiv. Solche Integer-Typen nennt man signed. Bei unsigned
Typen gibt es kein Vorzeichenbit, damit kann man Ganzzahlen von 0
bis 2
^ 32 - 1 darstellen.
Testen Sie es selbst aus, indem Sie die Programmzeile:
cout << zahl * zahl << endl;
durch folgende Zeile ersetzen:
cout << zahl+1 << endl;
Für den Variablentyp Integer (int) spendiert ein PC typischerweise 4 Byte ( = 32 bit ). Der Datentyp int entspricht der "Maschinenbreite", die ist noch weitgehend 32 bit mit der Tendenz nach 64 bit.
Wenn man keine Zahl, sondern z.B. den String (Zeichenfolge) "Hallo" eintippt, dann erhält man 0 (Null) als Ergebnis. Das ist genau genommen auch nicht korrekt, aber immerhin noch erträglich.
Es liegt also an Ihnen als Programmierer, diesen "Blödsinn" zu beherrschen und entsprechende Begrenzungen bei der Entgegennahme und Auswertung von Eingaben durchzuführen.
Nehmen wir den konkreten Fall. Die
größte Ganzzahl, die wir mit int (4 Byte) darstellen
können, ist
2 147 483 647.
Die Quadratwurzel hieraus ist abgerundet 46340.
Also dürfen wir keine Eingabe größer als 46340 oder
kleiner
als -46340 akzeptieren.
Hierzu verwendet man z.B. eine if / else
- Kontrollstruktur,
einen Größenvergleich und eine logische "ODER"-Verknüpfung:
#include <iostream> #include <limits> using namespace std;
void
wait()
wait(); |
Die if / else - Kontrollstruktur
funktioniert nach folgendem Prinzip:
if( Bedingung ) { Block 1 } else { Block 2 } |
Da Grössenvergleiche und logische Verknüpfungen häufig vorkommen, hier eine Übersicht:
== | gleich |
!= | ungleich |
> | größer |
>= | größer oder gleich |
< | kleiner |
=< | kleiner oder gleich |
&& | logisches UND |
|| | logisches ODER |
! | Negation |
Nun fehlt noch die Anzeige für den
Benutzer, was eigentlich passieren soll bzw. passiert ist.
Das erledigt
man bei Konsolenanwendungen in C++ durch cout-Anweisungen (Ausgabe auf
das Standardausgabe-Objekt):
#include <iostream> #include <limits> using namespace std;
void
wait()
wait();
|
Experimentieren Sie an dieser Stelle
bitte eifrig mit eigenen Ideen, z.B. verschiedene Umrechnungen (kW/PS,
kcal/kJ, °C/°F/K, Währungen, ...).
Nur durch eigene Versuche erhalten Sie
Routine beim Erstellen des Sourcecodes.