Genereller Aufbau

  • Code
  • Erklärung
  • Ergebnis

#include <iostream>
using namespace std;

int main()
{
    cout << "Erste Ausgabe in der Console" << endl;
    return 0;
}

Erstelle in deiner IDE für C++ ein leeres Projekt.
Unsere ersten C++ Programme werden alle fast gleich beginnen. Zu Beginn benötigen wir sogenannte includes. Damit lassen sich zum Beispiel Bibliotheken aus der Standardbibliothek von C++ einbinden. Die iostream Bibliothek bietet Standardmethoden zur Ein- und Ausgabe die du nun in deinem Programm verwenden kannst. Danach kommt using namespace std; wodurch wir auf den namespace der Standardbibliothek zugreifen können. Zur kurzen Erklärung: namespaces ermöglichen die Verwendung gleicher Variablen- oder Methodennamen in unterschiedlichen Kontexten.
Nun folgt die main-Funktion. Diese ist der Einstiegspunkt jedes Programmes und muss in jedem Code ein mal (und nur ein mal) vorkommen. Das vorangestellte int definiert den Rückgabetyp dieser Funktion. Dieser ist bei main vom Typ integer doch dazu später mehr. Nach dem Funktionsnamen folgen zwei runde Klammern. Die geschweiften Klammern { } bilden einen sogenannten Anweisungsblock der unseren Code sozusagen gruppiert und anzeigt, dass der darin geschrieben Code zu unserer main-Methode gehört. cout leitet unsere Ausgabe (standard output stream) ein. Mit << (Kleiner Kleiner) lassen sich Bausteine die ausgegeben werden sollen verknüpfen. Abgeschlossen wird die Zeile mit endl; (end line) welches die Ausgabezeile beendet um einen Zeilenumbruch erweitert. Dieses endl; ist nicht verpflichtend, das abschließende Semikolon hingegen schon. Jede Anweisung (und cout ist so eine) muss mit einem Strichpunkt abgeschlossen werden.
Dieses cout wird und durchwegs begleiten und du wirst noch einige Besonderheiten dieses eigentlich einfachen Statements kennenlernen. Abschließend folgt das return Statement - die Rückgabe der aktuellen Methode. Näheres dazu im Artikel Funktionen.
Der geschrieben Code lässt sich nun in Dev C++ per F9 compilieren und ausführen. In Visual Studio F5 (bzw Strg-F5).

Einfache Datentypen und Variablen

  • Code
  • Erklärung
  • Ergebnis

#include <iostream>;
using namespace std;

int main()
{
	int a = 13;
	int b = 24, c = 26;
	float ergebnis = 5 * c + 5 - 3.0 / 7;

	bool x = true;

	float f;
	f = 13.7603;

	char p = 'p';

	cout << "a = " << a << endl;
	cout << "b = " << b << " c = " << c << endl;
	cout << "x = " << x << " f = " << f << endl;
	cout << p << endl;
	cout << "Ergebnis = " << ergebnis << endl;
	return 0;
}

Variablen dienen dazu um Informationen wie Zahlen oder Texte zu speichern. Es gibt unterschiedliche Datentypen die abhängig ihres Inhaltes zu verwenden sind.
Typische Datentypen sind int für ganze Zahlen, float oder double für Dezimalzahlen, char für Zeichen und bool für die Wahrheitswerte true/false sowie string für Zeichenketten.
Folgende Tabelle gilt für 32 bit Systeme:
Name Minimum Maximum Größe in Bit
bool false / true 8
char -128 127 8
int -2.147.483.648 2.147.483.647 32
unsigned int 0 4.294.967.295 32
short int -32.768 32.767 16
float 1,2E-38 3,4E+38 32
double 2,2E-308 1,8E+308 64
long double 3,4E-4932 1,2E+4932 80
Wie du siehst werden Variablen einfach per '=' initialisiert. Dabei ist immer der Datentyp an erster Stelle zu nennen. Es können auch mehrere Initialisierungen in einer Anweisung (also bis zum ; ) geschrieben werden. Ebenso ist es möglich - wie bei Variable f - diese zu deklarieren aber erst später zu initialisieren.
Zwei Besonderheiten sind hier zu nennen: Das Dezimaltrennzeichen ist ein Punkt und false wird als Ziffer 0 dargestellt während true als 1 dargestellt wird. Im Umkehrschluss gilt auch, dass jede Zahl außer 0 als true gewertet wird. Ebenfalls neu in diesem Code ist die Art der Ausgabe. Per << können so mehrere Texte und Variablen in einer Zeile ausgegeben werden.
Du wirst im Laufe der Zeit noch mehrere Datentypen kennenlernen, doch die hier genannten bilden sozusagen die Basis der Sprache.

Dateneingabe

  • Code
  • Erklärung
  • Ergebnis

#include <iostream>;
#include <string>;
using namespace std;

int main()
{
	int a;
	string str;
	string str2;
	char c;

	cout << "Eingabe a: ";
	cin >> a;
	cout << "Eingabe c: ";
	cin >> c;

	cout << "Eingabe str: ";
	cin >> str;
	cin.ignore();

	cout << "Eingabe str2: ";
	getline(cin, str2);

	
	//Ausgabe der Werte
	cout << "\na =" << a << " str =" << str << " c =" << c << " st2 =" << str2 << endl;

	return 0;
}

Bei diesem Beispiel gibt es gleich mehrere Neuerungen. Die Dateneingabe ist in C++ sehr einfach. Per cin >> (größer größer) wird die Eingabe ermöglicht. Dabei ist darauf zu achten, dass die Variable vorher bereits deklariert wurde, und dass die Eingabe dem Datentyp der zu befüllenden Variable entsprechen muss. So kann die Eingabe 'Hallo' nicht in einem integer gespeichert werden. Wie Anfangs erwähnt, wird die Eingabe mit cin eingeleitet. Allerdings gilt ein Leerzeichen als Unterbrechung der Eingabe. Um auch Leerzeichen erfassen zu können um z.B. einen ganzen Satz einzugeben, benötigen wir den Befehl getline(). Werden mehrere Strings nach einander eingegeben, kann es vorkommen, dass eine Eingabe augenscheinlich ausgelassen wird. Das liegt daran, dass cin den input-Stream bei Strings anders abschließt. Um das zu beheben wird zwischen 2 Stringeingaben cin.ignore() eingefügt und ein im Stream verbliebenes „Enter“ wird nicht an das nächste cin weitergegeben.

Eine weitere kleine Neuerung ist das \n im letzten cout-Statement. Dieses \n stellt einen einfachen Zeilenumbruch in der Console dar, kann an jeder Stelle innerhalb von Anführungszeichen verwendet werden und ist eins von einer Reihe an sogenannten Escapesequenzen. Durch das vorangestellte Backslash ( \ ) lassen sich Zeichen darstellen die sonst im Programm zu Problemen führend würden. Die wichtigsten dieser Zeichen sind:
\n – Zeilenumbruch
\‘ – Einfaches Anführungszeichen
\“ – Doppeltes Anführungszeichen
\\ - Backslash
\a – akustisches Signal (klassisches „Beep“)
\t – Tabulator
\xnn – Zeichen als Hexadezimalziffer (zB \x40 für @)
\ooo – Zeichen als Octalziffer (zB \100 für @)

Bedingte Anweisungen

  • Code
  • Erklärung
  • Ergebnis

#include <iostream>;
using namespace std;

int main()
{
	int a = 13;
	int b = 20;
	bool x = false;

	if (a < 20)
		cout << "a ist kleiner als 20" << endl;
	else if (a > b)
		cout << "b ist groesser als b" << endl;

	if (x)
		cout << "True" << endl;
	else
	{
		cout << "Else wird ausgefuehrt" << endl;
		cout << "Falsch" << endl;
	}

	return 0;
}

Bedingte Anweisungen ermöglichen es Codestellen nur unter definierten Umständen ausführen zu lassen. Die klassische Bedingte Anweisung ist das If-Statement. In den runden Klammern erfolgt die Prüfung des Statements. Liefert diese true (ist die Aussage also wahr) wird die Nachfolgende Anweisung ausgeführt. Das kann eine einzelne Zeile sein oder ein ganzer { } Block. Per Else If lassen sich Bedingungen aneinander Reihen. Der Else Block wird dann ausgeführt wenn keine vorgestellter If-Block ausgeführt wird.
Vereinfacht lässt sich dies mit WENN (if Statement) – DANN (Anweisung wenn wahr) – SONST (else) übersetzten.
Typische Vergleichsparameter sind < (Kleiner als), > (Größer als), '==' (ist gleich) und != (ist ungleich). Die Erste Prüfung liefert true da a kleiner als 20 ist. Das Folgende Else If wird nicht ausgeführt. If (x) liefert false da x mit false initialisiert wurde. Somit wird der Else-Block ausgeführt.

If Bedingungen können auch verkürzt in der Form ( Statement ) ? DANN : SONST; geschrieben werden. Dies ist aber nur dann geeignet wenn keine Anweisungsblöcke sondern nur einzelne Werte das Ergebnis sind. zB ( x > 5) ? „Ja“ : „Nein“; bedeutet, dass ein „Ja“ geliefert wird wenn x > 5 ist. Ansonsten wird ein „Nein“ das Ergebnis sein.

Logische Ausdrücke

  • Code
  • Erklärung
  • Ergebnis

#include <iostream>;
using namespace std;

int main()
{
	int a = 13;
	int b = 24;
	bool x = true;

	if (a > 10 && a < 20)
		cout << "a liegt zwischen 10 und 20" << endl;

	if (a < 10  || x)
		cout << "a ist kleiner als 10  ODER x = true " << endl;

	return 0;
}

Logische Ausdrücke sind Aussagen oder Bedingungen die am Ende true oder false liefern, deren Aussage also wahr oder falsch ist.
Per || lassen sich Ausdrücke Oder-Verknüpfen und per && lassen sich Ausdrücke Und-Verknüpfen. Dabei wird jeder Teilausdruck für sich selber bewertet, so dass der Ausdruck 3 > 2 && 5 == 6 false liefert da der zweite Teilausdruck falsch ist.
Derart verknüpfte Bedingungen können natürlich auch an anderen Stellen, wie zB der If-Anweisung verwendet werden.
Eine weitere Eigenschaft lässt sich mit einem ! (Rufzeichen) erzielen. Dieses wird als „Umkehrsymbol“ interpretiert. Aus !true wird also false und umgekehrt. Eine einfache übersicht bietet nachfolgende Tabelle. Leicht zu merken sind die Umstände, dass && - Verknüpfungen nur dann true liefern wenn alle Teilausdrücke true sind während || - Verknüpfungen nur dann false liefern wenn alle Teilausdrücke false sind.
Wahrheitstabelle

Schleifen

  • Code
  • Erklärung
  • Ergebnis

#include <iostream>;
using namespace std;

int main()
{
	//FOR SCHLEIFE
	for (int i = 0; i < 10; i++)
	{
		cout << i << endl;
	}

	//WHILE SCHLEIFE
	int i = 0;
	while (i < 10)
	{
		cout << i << endl;
		i = i + 1;
	}

	//DO SCHLEIFE
	i = 0;
	do
	{
		cout << i << endl;
		i = i + 1;
	} while (i < 10);

	return 0;
}

Schleifen werden dazu verwendet um bestimmte Anweisungen wiederholt ausführen zu lassen. Typische Schleifen sind for, while und do. Jede der drei Schleifentypen sind untereinander austauschbar wobei die do-Schleife als einzige mindestens ein mal ausgeführt wird da die Prüfung erst am Ende der Schleife ausgeführt wird. Schleifen bestehen in der Regel aus dem Schleifenkopf in der geprüft wird ob der folgende Schleifeninhalt ausgeführt wird. So bedeutet for (int i=0; i<10; i++), dass die Variable i mit 0 beginnt und so lange i kleiner als 10 ist die Schleife ausgeführt wird. Danach wird i um 1 erhöht. Das passiert so lange bis i<10 false liefert. Wichtig ist hierbei, dass diese Bedingung auch tatsächlich irgendwann false liefert da man sonst in einer Endlosschleife landet.
Alle drei Schleifen liefern das selbe Ergebnis.
Diese Folgenden Grafiken verdeutlichen die Funktionsweise der Schleifen:
For-Schleife
For-Schleife
While-Schleife
While-Schleife
Do-Schleife
Do-Schleife

Arrays und Listen

  • Code
  • Erklärung
  • Ergebnis

#include <iostream>;
#include <vector>;
using namespace std;

int main()
{
	//array mit 20 Plätzen
	int arr1[20];

	//Vector
	vector vec;

	//array befüllen
	for (int i = 0; i < 20; i++)
		arr1[i] = i;
	
	//array ausgeben
	for (int i = 0; i < 20; i++)
		cout << arr1[i] << " ";

	//push_back() fügt bei einem Vector den Inhalt hinten an pop_back entfernt den letzten Eintrag
	vec.push_back(1);
	cout << vec[0] << endl;

	return 0;
} 

Als Array oder Liste bezeichnen wir einen Datentyp der sozusagen als Container für eine andere Variablen dient. So kann man zum Beispiel einem Array mit dem Namen ziffern 20 Zahlen speichern ohne dafür 20 integer-Variablen anlegen zu müssen.
Jeder dieser Container legt seine beinhaltenden Informationen unter einem fortlaufenden Index ab. So liegt der erste Wert auf Patz 0 (wir beginnen immer bei 0 an zu zählen) und z.B. der dritte Wert auf Platz 2. Referenziert wird dieser Platz - zum befüllen oder abrufen - per [INDEX]. Im nachfolgenden Beispiel sind zwei der häufigsten Listentypen vorgestellt. Das Array, das eine fixe Größe hat und der Vector mit dynamischer Größe. Der Beinhaltende Datentyp wird gleich bei der Deklarierung angegeben und kann nicht geändert werden. So kann ein integer-Array nur Variablen vom Typ integer enthalten.
Wichtig hierbei ist zu beachten, dass man in seinem Code keine Zugriffsverletzungen ausführt. So kann ein Array arr1 mit 10 Werten keinen Wert bei arr1[12] enthalten oder entgegennehmen.
Ebenfalls möglich ist es ein solches Array mehrdimensional darzustellen. Möchte man etwa ein Schachbrett in einem Array abbilden, könnte man ein zweidimensionales Array erstellen. Die Verwendung ist dabei gleich der eines eindimensionalen, allerdings mit einer weiteren Indexangabe.
Ein char-Array für unser Schachbrett könnte also z.B. als char schachbrett[8][8]; abgebildet werden.
Leicht lässt sich dies als ARRAYNAME[ZEILEN][SPALTEN] veranschaulichen. Arrays können aber durchaus mehrere Dimensionen besitzen, allerdings muss man bedenken, dass der benötigte Speicher exponentiell wächst. So benötigt z.B. ein char arr [100][365][24][60][60]; bereits über 3 Gigabyte Arbeitsspeicher.

Gerne wird ein solches Array per for-Schleife bearbeitet oder ausgegeben. Hierfür wird die Zählervariable der for-Schleife direkt für den Index des Arrays verwendet.

Referenzen

  • Code
  • Erklärung
  • Ergebnis

#include <iostream>
using namespace std;

int main()
{
    int  a = 5;
    int  b = 10; 
    int &r = a;  
 
    cout << "a= " << a << " b= " << b << " r= " << r << endl;
    a++;    //Erhöhung um 1 (Post Inkrement)
    cout << "a= " << a << " b= " << b << " r= " << r << endl;
    r = b;  // r zeigt weiterhin auf a, r (und somit a) wird 10 zugewiesen 
    cout << "a= " << a << " b= " << b << " r= " << r << endl;
    
    return 0;
}

Eine Referenz ist einfach ausgedrückt ein anderer Name für eine bereits bestehende Variable. Die Referenz zeigt direkt auf die Speicheradresse der Variable.
Definiert wird das durch die Verwendung eines '&'-Zeichens. Wird die Referenz geändert, ändert sich auch die referenzierte Variable und umgekehrt. Worin liegt nun der Vorteil? Der wesentlichste Vorteil liegt darin die Performance zu verbessern. Wird eine Referenz an eine andere Funktion übergeben so wird keine lokale Kopie für diese Funktion erstellt. Es wird die Speicheradresse der eigentlichen Variable direkt angesprochen und verwendet.

Zeiger (Pointer)

  • Code
  • Erklärung
  • Ergebnis

#include <iostream>
using namespace std;

int main()
{
    int  a = 20;
    int  *ip;        // ein Zeiger des Typs Integer
    ip = &a;       // Wir befüllen den Zeiger mit der Adresse von a

    cout << "a= " << a << endl;

    // Ausgabe der Adresse auf die ip verweist
    cout << "Gespeicherte Adresse in *ip " << ip << endl;

    // Ausgabe des Wertes der unter der Adresse gespeichert ist
    cout << "Wert von *ip: " << *ip << endl;
    
    return 0;
}

Zeiger verwenden, wie Referenzen, die Speicheradresse einer bereits bestehenden Variable. Dargestellt wird ein Zeiger durch die Verwendung eines *-Zeichens. Der nähere Sinn von Zeigern ergibt sich Anfängern zu Beginn nicht und auch Fortgeschrittene können Probleme mit dieser Thematik haben - weshalb C# und Java auf diese verzichtet haben. Allerdings bieten Zeiger (oder auch Pointer genannt) spätestens bei dynamischen Speicher erhebliche Vorteile. An dieser Stelle folgt nur ein einfaches Beispiel zur Deklaration und Verwendung.

Funktionen

  • Code
  • Erklärung
  • Ergebnis

#include <iostream>
using namespace std;

void hallo()
{
    cout << "Funktion 'hallo' aufgerufen" << endl;
}

int add()
{
    int a;
    int b;
    
    cout << "Eingabe a:";
    cin >> a;
    
    cout << "Eingabe b:";
    cin >> b;
    
    return a+b;
}

int main()
{
    int ergebnis;
    
    cout << "Erster Funktionsaufruf:" << endl;
    hallo();
    
    ergebnis = add();
    cout << "Ergebnis = " << ergebnis << endl;
    
    return 0;
}

Funktionen eignen sich hervorragend um häufig verwendete Codeabschnitte in einer eigenen Funktion (oder Methode) zu implementieren anstatt die gleichen Zeilen immer wieder zu schreiben. Somit sinkt der Schreib- und Wartungsaufwand.
Die erste Funktion kennen wir bereits. Nämlich die main-Funktion. Funktionen werden nach folgendem Schema deklariert: [Rückgabetyp] [Funktionsname] () {Anweisungen}. Optional kann auch ein [Zugriffsmodifier] wie z.B. public oder const vorangestellt werden. Der Rückgabetyp definiert den Typ der durch das return-Statement an die aufrufende Funktion zurückgegeben wird. Sobald das return Statement erreicht wird endet die Funktion, egal was danach noch kommen mag.
Die Rückgabetypen von Funktionen sind die gleichen wie sie für Variablen verwendet werden.
Einzig der Typ void hat keinen Rückgabetyp und auch kein return-Statement. So muss ein eine Funktion int getNumber() einen integer als return-Wert haben.

Parameterübergabe

  • Code
  • Erklärung
  • Ergebnis

#include <iostream>
using namespace std;

int add(int a, int b)
{
	int result = a + b;

	return result;
}

void div(float &var)
{
	var = var / 60;
}

int main()
{
	int v1;
	int v2;
	float c = 50;

	cout << "Eingabe a:";
	cin >> v1;

	cout << "Eingabe b:";
	cin >> v2;

	cout << "Ergebnis = " << add(v1, v2) << endl;
	div(c);
	
	cout << "Variable C nach der Division = " << c << endl;

	return 0;
}

Damit Funktionen mit Variablen aus anderen Funktionen (z.B. aus main() ) arbeiten können, müssen diese übergeben werden. Die Anzahl, der Typ der Parameter und die Reihenfolge muss bei der Funktion definiert werden. Diese Reihenfolge muss bei dem Aufruf strikt eingehalten werden.
Wahlweise können die Werte als Wert (Call By Value) oder als Referenz (Call By Reference) übergeben werden.
Wird der Parameter als Wert übergeben, arbeitet die Funktion mit einer Kopie dieser Variable, bei einer Referenz (symbolisiert mit dem &-Zeichen) wird der Wert der ursprünglichen Variable verwendet und ggf. verändert. Es wird keine Kopie erstellt.
Obwohl der Funktionsname nur einmal im aktuellen Namespace verwendet werden darf, kann er mehrfach genutzt werden, wenn er sich zumindest in der Parameterliste unterscheidet.
Dieser Vorgang wird überladung genannt.

Somit können die Funktionen int calculate(int a, int b) und int calculate(int a, int b, int c) im gleichen Namespace trotz gleichen Namens existieren. Bei dem Aufruf dieser Funktion erkennt der Compiler automatisch welche der beiden Funktionen gemeint ist, je nach dem ob 2 oder 3 Parameter übergibst.

Wichtig zu wissen ist, dass Variablen die keine Referenzen sind nur innerhalb dieser Funktion gültig sind. Außerhalb der Funktion sind Variablen anderen Funktionen unbekannt. Jetzt erschließt sich wahrscheinlich auch der Nutzen von Referenzen. Wie du in unserem Beispiel sehen kannst, können wir entweder 2 Parameter übergeben ohne, dass die Funktion diese ändert, oder aber wir lassen die Funktion unsere Variable bewusst ändern in dem wir sie als Referenz übergeben.