1. Was ist ein Zeiger und welche Vorteile und Gefahren bringt die Anwendung mit sich?
Ein Zeiger ist ein Variablentyp, der die Adresse einer anderen Variable enthält. Der Vorteil besteht in der Flexibilität der Variable. Ihr kann jeder Zeit ein anderer Speicherblock zugewiesen werden. Die ist auch eines der Probleme die Zeiger mit sich bringen können. Beispielsweise vergessen einen zur Laufzeit zugewiesenen Speicherblock wieder freizugegeben. Dies nennt man dann Memory Leak. Auch ist die Benutzung von Pointern oft für Anfänger etwas verwirrend und kann so zu ungewollten Programmabstürzen bzw. Sicherheitslücken führen. Für fortgeschrittene Anwender ist die Benutzung von Zeigern zu empfehlen, da dies auch einer der Vorteile der Programmiersprache C/C++ ist. Anfänger sollten jedoch nur dann Zeiger verwenden, wenn sie müssen oder sich bei dem was sie tun sicher sind.
2. Wie werden Zeiger definiert und wie dereferenziert?
Ein Zeiger hat immer einen Datentyp. Die Definition unterscheidet sich von der normaler Variablen dadurch, das vor den Variablennamen ein * gestellt wird. Will man einen Zeiger dereferenzieren (auf den Wert zugreifen) muss dem Zeiger wieder ein * vorangestellt werden.
Beispiel:
#include <iostream> using namespace std; int main() { int i = 5; int *prt_i = NULL; prt_i = &i; // prt_i zeigt jetzt auf die Speicheradresse von i cout << *prt_i << endl; // Ausgabe 5 // Klammern sind notwenig, sonst wird nur der // Zeiger eine Speicheradresse weitergeschoben (*prt_i)++; cout << *prt_i << endl; // Ausgabe 6 }
3. Erklären sie den Unterschied zwischen „const char* ptr“ und „char* const ptr“ .
Der Ausdruck
const char* prtist ein Pointer auf einen unveränderlichen Charakter. Der Pointer kann auf einen neuen Speicheradresse verschoben werden. Jedoch kann man über eine dereferenzierung den Wert nicht verändern.
Beispiel:
#include <iostream> using namespace std; int main() { const char *ptr = NULL; // Zuweisung einer Adresse char a = 'a'; ptr = &a; // Erneute Zuweisung einer Adresse cout << *ptr << endl; *ptr = 'c'; // Dies funktioniert nicht !!! }
Analog dazu verbietet die Definition
char * const ptrdas ändern des Pointers. Man kann jedoch über eine dereferenzierung den Wert der Variable ändern.
Beispiel:
#include <iostream> using namespace std; int main() { char a = 'a'; char * const ptr = &a; cout << *ptr << endl; *ptr = 'b'; // Erneute Wertzuweisung cout << *ptr << endl; ptr = NULL; // Dies funktioniert nicht !!! }
4. Gegeben ist die Funktion
float mittelwert (float x, float y) {return (x+y)/2;}.
Definieren sie einen Zeiger pf auf diese Funktion.
Rufen sie diese Funktion mit den Parameterwerten x=4, y=2 auf.
#include <iostream> using namespace std; float mittelwert (float x, float y) { return (x+y)/2; } int main() { float (*pf)(float, float) = mittelwert; float ret = (*pf)(4,2); cout << ret << endl; }
5. Gegeben ist die Klasse Ort mit der Methode float Ort::XWert(). Auf ein Objekt von Ort verweist der Zeiger pOrt. Rufen sie die Methode XWert dieses Objektes mit Hilfe von pOrt auf.
Auf eine Methode wird mittels des Strukturoperator
->zugegriffen.
#include <iostream> using namespace std; class Ort { public: // ... float XWert() { return 1.2; } }; int main() { Ort *pOrt = new Ort(); float ret; ret = pOrt->XWert(); cout << ret << endl; }
6. Welche Bedeutung haben Basisklassenzeiger?
Basisklassenzeiger werden für die Polymorphie benötigt. Also das dynamische Binden von Funktionen. Dies ist ein wichtiger Bestandteil von Objektorientierter Programmierung.
7. Worin besteht der Unterschied zwischen Referenzen und Zeiger?
Referenzen sind Aliase für Variablennamen. Sie müssen gleich bei der Definition initialisiert werden. Man erstellt diese indem man den Typ angibt und vor dem Variablennamen ein kaufmännisches Und voranstellt
&. Dabei muss man beachten, dass dies nicht der Adressoperator ist, mit dem man an die Adresse einer Variable kommt!
Ein Zeiger wiederum ist ein Verweis auf den Speicherplatz einer anderen Variable.
#include <iostream> using namespace std; int main() { int i = 0; // Variable int &ref = i; // Referenz auf Variable i int *ptr = NULL; // Zeiger ptr = &ref; // Benutzung Adressoperators ref++; // gleichwertig zu i++ oder (*ptr)++ cout << ref << endl; // Ausgabe über Referenz (*ptr)++; cout << i << endl; // Ausgabe über normale Variable cout << *ptr << endl; // Ausgabe über Pointer }