Beruflich Dokumente
Kultur Dokumente
a) Welche der folgenden Aussagen über die C++-Programmiersprache sind wahr? (w=wahr,
f=falsch)? (2P., 2 zutreffende Antworten)
w f
C ist eine Erweiterung von C++.
Falsch. Anders herum.
C++ ist grösstenteils zu C kompatibel. Deshalb können in C geschriebene Programme
meist auch mit einem C++-Compiler übersetzt werden.
Richtig.
Im Gegensatz zu C müssen sich C++-Entwickler nie selbst um dynamische Speicherver-
waltung kümmern, denn C++ hat wie z.B. Java einen Garbage-Collector, der nicht mehr
benötigten Speicher automatisch frei gibt.
Falsch. C++ erlaubt ebenfalls dynamische Speicherverwaltung.
In C++ geschriebene Programme sind schneller als in C geschriebene Programme.
Falsch.
b) p1, p2 und p3 seien bereits initialisierte Zeiger auf Integer. Geben Sie für jede der fol-
genden Operationen an, ob sie erlaubt (=w) ist oder nicht (=f). (2P., 1 zutreffende Antwort)
w f
*p3 = p1;
Nicht erlaubt. Dies wäre nur mit einer expliziten Typenkonvertierung möglich. Voraus-
setzung ist, dass das Integer die Adresse überhaupt speichern kann. Zum Beispiel wäre
auf 64-bit Architekturen i.d.R. eine long int Variable nötig.
p3 = p2 + p1;
Nicht erlaubt. Die Zeigerarithmetik erlaubt nur die Addition von ganzen Zahlen.
p2 = p1 + 3.0;
Nicht erlaubt. Die Zeigerarithmetik erlaubt nur die Addition von ganzen Zahlen. 3.0 ist
eine Gleitkommazahl.
*p3 = *p2 * *p1;
Erlaubt. Hier wird mit den dereferenzierten Zeiger gerechnet. Daher handelt es sich um
eine normale Mulitplikation zweiter Integer.
c) Es gilt: double d; float f; short s; Tritt bei nachfolgenden Zuweisungen in der Regel
Informationsverlust auf (j=ja, n=nein)? (3P., 3 zutreffende Antworten)
j n j n j n
d = f; d = s; f = s;
Nein. Nein. Nein.
f = d; s = d; s = f;
Ja. Ja. Ja.
w f
Abstrakte Datentypen gibt es in C und C++.
Klassen in C++ vereinen Daten und Funktionen zum Zugriff und zur Bearbeitung dieser
Daten in einer Struktur.
Funktionen in C entsprechen Attributen in C++.
Klassen in C++ haben weniger Funktionalität wie strukturierte Datentypen in C.
Methoden in C++ erlauben es den Zugriff auf Daten ausschließlich über eine Funktion
zu realisieren.
Geben Sie für jede der nachfolgenden Operationen an, ob sie äquivalent zu x = TP->d; ist.
(2P., 2 wahre Antworten)
w f w f
x = *TP.d; x = (&TP)->d;
x = T.d; x = TP[0].d;
f) Wer sind die Erfinder der Programmiersprachen C und C++? (w=wahr, f=falsch)?
(1 Punkt, 1 wahre Antwort)
w f
Steve Jobs und Tim Cook
Walter Bright und Guido van Rossum
Kenneth Thompson, Dennis Ritchie und Bjarne Stroustrup
Brendan Eich, Rasmus Lerdorf und Linus Torvalds
Larry Wall, Perl Porter und Bill Gates
g) Geben Sie für die nachfolgenden Aussagen an, für welche Methode der Parameterübergabe
(v=„Call by Value“, r=„Call by Reference“) sie jeweils zutreffen (3P.).
v r
Eine Kopie der Variablen muss im Speicher angelegt werden.
v=Call-by-Value. Diese Tatsache macht diese Methode bei größeren Datenmengen sehr
ineffizient.
Die Menge der übergebenen Daten in Byte variiert mit dem Variablentyp.
v=Call-by-Value. Da beim Aufruf der Funktion mittels C-b-V eine Kopie im Speicher
angelegt wird, ist die Menge vom Variablentyp abhängig.
Es werden nicht die Variablen selbst, sondern deren Adresse im Speicher übergeben.
r=Call-by-Reference.
Die aufgerufene Funktion kann Variablen beim Aufrufer nicht direkt ändern.
v=Call-by-Value.
a) Präprozessor (2P.)
Geben Sie die Ausgabe des Programmes in Zeile 11 und Zeile 12 an.
Die Funktion printHello() ist dem Compiler bei Aufruf der main-Routine noch nicht
bekannt. Sie muss vorher folgendermaßen deklariert werden: void printHello();
Geben Sie die Ausgabe des Programmes mit kurzer Begründung für folgende Zeilen an:
Zeile 11: 2, da die Funktion func die globale Variable b=1 um eins er-
höht und zurückgibt.
Zeile 12: 3, da der Funktion func die Adresse der globalen Variable a=1
übergeben wird und der Wert von a mit dem Wert von b=2 erhöht wird.
Gegeben ist folgender Quelltext, wobei die Standardbibliothek <stdio.h> eingebunden ist:
1 int main() {
2 int i = 3;
3 float j = 2;
4 j=i/j;
5 i=j/i;
6 printf("j:%f\n",j); // 1 Punkt
7 printf("i:%i\n",i); // 1 Punkt
8 return 0;
9 }
Geben Sie die Ausgabe des Programmes für folgende Zeilen mit kurzer Begründung an:
Zeile 6:
Antwort: j:1.5, da auf der rechten Seite ein float von 1.5 steht und dann auf ein float zugewiesen
wird.
Zeile 7:
Antwort: i:0, da auf der rechten Seite ein float von 1.5/3=0.5 steht und dann auf ein int gecastet
wird.
Gegeben sei das Programm auf der linken Seite. Das Diagramm auf der rechten Seite stellt
den Stack (Kellerspeicher) dar. Der Anfang des Stacks sei die unterste Zelle. Das Programm
wird ausgeführt und es werden in main mehrere Variablen auf dem Stack angelegt. Das
Programm befinde sich nun innerhalb der while-Schleife in der 3. Iteration in Zeile 16 und
hat die Anweisungen in dieser Zeile bereits ausgeführt. Vervollständigen Sie das Diagramm,
indem Sie in die Kästchen die Werte der jeweiligen Variablen schreiben. Schreiben Sie
rechts neben die Kästchen die Variablen. Beispielhaft ist die Variable i mit Wert 2 bereits
eingetragen.
Hinweis: Die Adressierung des Stacks erfolgt über eine Blockgröße von 4 Bytes. Deshalb
belegt int i auch genau ein Kästchen.
1 struct Data {
2 int a, b, c; 0x049A6
3 };
4 0x049A2
5 int main(void) {
6 int r = 0; 0x0499E
7 int i = 0;
8 0x0499A
9 struct Data data = {0, 0, 0};
10 0x04996 6 inc
11 while (i < 10) {
12 int inc = 3 * i; 0x04992 9 c
13 data.a += inc;
14 data.b += inc; 0x0498E 9 b
15 data.c += inc;
16 i++; 0x0498A 9 a
17 }
18 0x04986 3 i
19 return r;
20 } 0x04982 0 r
a) Fibonacci (5P.)
Schreiben Sie eine Funktion int fibonacci_recursive(int n), welche für eine ganze Zahl
n die n-te Fibonacci-Zahl zurückgibt.
fn = fn−1 + fn−2 , f1 = 1, fn = 0 | n ≤ 0
definiert.
(i) Schreiben Sie die Funktion zunächst als Rekursion (ohne Schleifen). (2P. von 5P.)
int fibonacci_recursive(int n) {
if (n <= 0) {
return 0;
} else if (n ==1) {
return 1;
} else
return fibonacci(n - 2) + fibonacci(n - 1);
}
}
(ii) Schreiben Sie die Funktion nun als Iteration (int fibonacci_iterative(int n) ,verwen-
den Sie dazu eine while-Schleife). (3P. von
5P.)
int fibonacci_iterative(int n) {
if (n <= 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
int a = 0;
int b = 1;
int i = 2;
while (i <= n) {
int f_im1 = b;
int f_i = a + b;
a = f_im1;
b = f_i;
i++;
}
return b;
}
}
b) Vektor (7P.)
Gegeben ist folgender Code-Ausschnitt in C, der einen Vektor implementiert. Dieser ist im
Grunde ein dynamisches Array, welches seine Größe mitführt. Sollen Elemente hinzugefügt
oder entfernt werden, passt sich die Größe des Arrays entsprechend an. Das Array data
soll immer nur genau so viel Speicher belegen, wie für die Elemente des Vektors benötigt
wird.
Datei vector.h
#ifndef VECTOR_H
#define VECTOR_H
#include <stdlib.h>
#include <stdio.h>
int vec_get;
#endif // VECTOR_H
Datei vector.c
#include "vector.h"
return v->data[index];
}
if (v->data == NULL) {
printf("Error␣adding␣element␣to␣vector.");
return;
}
v->data[v->size++] = value;
}
(ii) void vec_remove(vector *v, unsigned int index) (4P. von 7P.)
Diese Funktion entfernt das index-te Element aus dem Vektor. Die restlichen Elemen-
te bleiben unverändert, wobei alle Elemente hinter index einen Eintrag nach vorne
rutschen. Dazu muss wieder die Größe des Arrays angepasst werden. Fangen Sie auch
hier mögliche Fehler ab. index = 0 bezeichne das erste Element des Vektors.
void vec_remove(vector *v, unsigned int index)
{
if (index >= v->size) {
printf("Vector␣remove␣out␣of␣bounds.");
}
int k = index;
v->size--;
if (v->data == NULL) {
printf("Error␣removing␣element␣from␣vector.");
return;
}
}
Allokieren Sie Speicher für einen Zeiger vom Typ int. Schreiben Sie den Wert “5” in den
allokierten Speicherbereich, und geben Sie den Speicher danach wieder frei.
// 1. Speicher allokieren
int * n = (int*) malloc(sizeof(int)); // Variante 1
int * n = (int*) malloc(4); // Variante 2
// Anmerkung: der Cast zu (int*) ist optional
// 3. Speicher freigeben
free(n); // ’delete’ ist hier nicht erlaubt
Gegeben ist folgender Quelltextausschnitt, der eine 2 × 3-Matrix vom Typ int darstellt:
int m[6];
(i) Initialisieren Sie alle Matrix-Elemente mit 1 in gültiger C-Syntax. (1P. von 3P.)
Lösung
for (int i = 0; i < 6; ++i) m[i] = 1; // Variante 1
m[0] = m[1] = m[2] = m[3] = m[4] = m[5] = 1; // Variante 2
(ii) Der Speicherbereich der Matrix m wird nun wie folgt dargestellt: (2P. von 3P.)
Nehmen Sie an, dass nun m[i] = 1 für alle i = 0, ..., 5 gilt. Nun wird folgender
Quelltext ausgeführt:
m[m[0]] = 2;
m[2 * m[1]] = 5;
m[2] = m[4] - 2;
m[3] = (m[2] + m[4]) / 2;
m[m[4]] = 6;
Welche Werte befinden sich nun in der Matrix?
Lösung:
1 2 3
m =
4 5 6
Punkteverteilung:
e) Strings kopieren (3P.) Schreiben Sie eine Funktion, welche den String src in den String
dest kopiert. Verwenden Sie dazu die folgende Funktionsdeklaration:
void copyString(char *src, char *dest);
Hinweis: Gehen Sie davon aus, dass dest groß genug für src ist.
Eine elegante Lösung ist
void copyString(char *src, char *dest)
{
while(*dest++ = *src++);
}
1. Objektorientierung / Klassen
2. (Mehrfach-)Vererbung
3. Polymorphie (überschreiben von Funktionen, spätes Binden)
4. Überladen von Funktionen und Operatoren
5. Templates / Generische Programmierung
6. Referenzen
7. Namensbereiche (namespace)
8. Standard Template Library (STL)
9. Ausnahmebehandlung (Exceptions)
10. Speicherverwaltung mit new/delete
b) Template-Programmierung (2P.)
Gegeben ist folgender Quelltext, der die Maximum-Funktion für die Datentypen int und
double implementiert:
int max(int v1, int v2) {
return v1 > v2 ? v1 : v2;
}
(ii) Wie wird Ihre Template-Funktion für den Typ float aufgerufen? Geben Sie ein Beispiel.
// Musterlösung (1P.)
float v = max<float>(10, 20);
// folgendes geht NICHT: hier ist 10.0 double, und 20.0f float. Hier
// schlägt Template-Deduction aufgrund inkompatibler Typen fehl.
float v = max(10.0, 20.0f);
c) Vererbung (4P.)
// weitere Klassenfunktionen...
protected:
double x;
double y;
};
// weitere Klassenfunktionen...
(i) Welche Ausgabe bewirkt die Ausführung von p->reset(); in Zeile 4? Begründen Sie
kurz. (1P. von 4P.)
Lösung: Die Funktion reset ist in der Basisklasse virtual, daher überschreibt
RgbPunkt diese Funktion, und es wird ausgegeben:
RgbPunkt wird auf (0, 0, 0) gesetzt
(ii) Welche Ausgabe bewirkt die Ausführung von delete p; in Zeile 5? Begründen Sie
ausführlich. (3P. von 4P.)
Lösung: Punkt wird freigegeben
p ist ein Zeiger vom Typ Punkt. Da der Destruktor von Punkt nicht virtual ist, wird
der Destruktor von Punkt aufgerufen. Wäre der Destruktor der Basisklasse Punkt vir-
tual, dann würden beide Destruktoren aufgerufen werden. Folglich ist das Fehlen des
Schlüsselwortes virtual in der Basisklasse Punkt (immer) ein Programmierfehler.
Punkteverteilung:
– 1P. für richtige Ausgabe.
– 2P. für richtige Erklärung.
Implementieren Sie eine Funktion void setPunkt(double x, double y);, die die beiden
Klassenvariablen x und y auf die übergebenen Werte setzt. Überladen Sie weiterhin die
Funktion setPunkt, sodass die Überladung nur einen Parameter vom Typ const Punkt & p
akzeptiert. Machen Sie deutlich, in welchen Zeilen Ihre Erweiterungen in der Header-Datei
bzw. in der .cpp-Datei hinzugefügt werden.
Lösung:
// .h-Datei in Zeile 6
void setPunkt(double x, double y);
void setPunkt(const Punkt & p);
// .cpp-Datei z.B. in Zeile 5 oder 9
void Punkt:: setPunkt(double x, double y)
{
this->x = x;
this->y = y;
}
Punkteverteilung: