Sie sind auf Seite 1von 19

Musterlösung Seite 2

Aufgabe 1: Multiple Choice zu C und C++ (15 Punkte)


Hinweis: Pro Aufgabe ist angegeben, wieviele Antworten richtig (r) oder falsch (f ) sind.

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.

d) Welche der folgenden Aussagen sind wahr (w=wahr, f=falsch)?

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 3

(2 Punkte, 2 wahre Antworten)

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.

e) Gegeben sei folgender Code:


 
double x;
typedef struct {int i; double d;} test;
test T, *TP=&T;
 

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.

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 4

  In der Regel die effizientere Methode der Parameterübergabe


r=Call-by-Reference. Zeiger haben unabhängig von der Größe der Daten, auf den sie
zeigen immer die gleiche, systemabhängige Größe. Nur bei Variablen, die weniger Spei-
cher verbrauchen(z.B. Char, Short), ist Call-by-Value effizienter.
  Array-Variablentypen können so übergeben werden.
r=Call-by-Reference. Außer Arrays lassen sich alle anderen Datentypen auch per Call-
by-Value übergeben.

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 5

Aufgabe 2: Nachvollziehen von C-Programmen


(13 Punkte)
Hinweis: Alle Teilaufgaben sind unabhängig voneinander lösbar.

a) Präprozessor (2P.)

Gegeben ist folgender Quelltext:


 
1 #include <stdio.h>
2 #define DEFINED
3 #ifdef DEFINED
4 int VALUE = 2;
5 #endif
6 #define FUNCTION(x) x+x
7 #ifndef UNDEFINED
8 int function = FUNCTION(3);
9 #endif
10 int main()
11 {
12
13 printf("%i\n",function);
14 printf("%i\n",FUNCTION(VALUE));
15
16 return 0;
17 }
 

Geben Sie die Ausgabe des Programmes in Zeile 11 und Zeile 12 an.

Antwort: Es wird ausgegeben: 6, 4

b) Deklaration und Definition (1P.)

Gegeben ist folgendes Programm:


 
1 #include <stdio.h>
2
3 int main(int argc, char * argv[]) {
4 printHello();
5 return 0;
6 }
7
8 void printHello() {
9 printf("Hello␣World␣:-)\n");
10 }
 

Weshalb kompiliert das Programm nicht? Begründen Sie kurz.

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 6

Die Funktion printHello() ist dem Compiler bei Aufruf der main-Routine noch nicht
bekannt. Sie muss vorher folgendermaßen deklariert werden: void printHello();

c) Globale Variablen und Call-by-Pointer (3P.)

Gegeben ist folgender Quelltext:


 
1 #include <stdio.h>
2 static int a = 1;
3 int func (int* x) {
4 static int b = 1;
5 b=b+1;
6 *x=*x+b;
7 return b;
8 }
9 int main() {
10 printf("%i\n",a);
11 printf("%i\n",func(&a));
12 printf("%i\n",a);
13 return 0;
14 }
 

Geben Sie die Ausgabe des Programmes mit kurzer Begründung für folgende Zeilen an:

Zeile 10: 1, da die globale Variable a so initialisiert wurde.

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.

d) Implizite Typumwandlung (2P.)

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;

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 7

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.

e) Daten auf dem Stack (Stapelspeicher) (5P.)

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.

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 8

 
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
 

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 9

Aufgabe 3: Grundlagen und Programmieren in C


(20 Punkte)
Hinweise

• Alle Teilaufgaben sollen in der Programmiersprache C implementiert werden. Die Ver-


wendung von C++ ist nicht erlaubt.

• Alle Teilaufgaben können unabhängig voneinander gelöst werden.

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.

Hinweis: Die Fibonacci-Zahlen sind durch die Rekursionsgleichung

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);
}
}
 

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 10

(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>

typedef struct Vector {


int size;
int *data;
} vector;

void vec_init(vector *v);

int vec_get;

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 11

void vec_add(vector *v, int value);

void vec_remove(vector *v, unsigned int index);

#endif // VECTOR_H
 

Datei vector.c
 
#include "vector.h"

void vec_init(vector *v) {


free(v->data);
v->data = NULL;
v->size = 0;
}

int vec_get(vector *v, unsigned int index) {


if (index >= v->size) {
printf("Vector␣access␣out␣of␣bounds.");
}

return v->data[index];
}
 

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 12

Ihre Aufgabe ist es nun, folgende Funktionen zu implementieren:

(i) void vec_add(vector *v, int value) (3P. von 7P.)


Diese Funktion soll das Element value an das Ende des Vektors anhängen. Dabei muss
entsprechend Speicher allokiert werden. Fangen Sie mögliche Fehler ab.
 
void vec_add(vector *v, int value)
{
v->data = (int*) realloc(v->data, sizeof(int) * (v->size + 1));

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;

while (index < v->size - 1) {


v->data[index] = v->data[index + 1];
index++;
}

v->size--;

v->data = (int*) realloc(v->data, sizeof(int) * (v->size));

if (v->data == NULL) {
printf("Error␣removing␣element␣from␣vector.");
return;
}
}
 

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 13

c) Dynamische Speicherverwaltung in C (3P.)

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

// 2. Wert 5 in den allokierten Speicher schreiben


*n = 5;

// 3. Speicher freigeben
free(n); // ’delete’ ist hier nicht erlaubt
 

d) Arrays & Speicherbedarf (3P.)

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.)

m[0] m[1] m[2]


m =
m[3] m[4] m[5]

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:

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 14

1 2 3
m =
4 5 6

Punkteverteilung:

• 2P. alles richtig.


• 1.5P. 5 richtig.
• 1P. 3 oder 4 richtig.
• 0.5P. 2 richtig.
• 0P. 1 richtig oder alles falsch.

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++);
}
 

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 15

Aufgabe 4: Programmieren in C/C++ (12 Punkte)


a) Von C zu C++ (2P.)
Nennen Sie stichpunktartig 4 Konzepte in C++, die es in C nicht gibt.

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

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 16

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;
}

double max(double v1, double v2) {


return v1 > v2 ? v1 : v2;
}
 

(i) Schreiben Sie eine Template-Funktion max.


 
// Musterlösung (1P.)
template<class T>
T max(T v1, T 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 auch, da der Compiler von den beiden float-Argumenten


// auf den Typ float schließt (Template-Deduction)
float v = max(10.0f, 20.0f);

// 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);
 

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 17

c) Vererbung (4P.)

Gegeben ist folgende Klassenhierarchie:


 
class Punkt {
public:
Punkt() : x(0.0), y(0.0) {
}
~Punkt() {
printf("Punkt␣wird␣freigegeben\n");
}

// weitere Klassenfunktionen...

virtual void reset() {


printf("Punkt␣wird␣auf␣(0,␣0)␣gesetzt\n");
x = 0;
y = 0;
}

protected:
double x;
double y;
};

class RgbPunkt : public Punkt {


public:
RgbPunkt() : Punkt(), r(0.0), g(0.0), b(0.0) {
}
~RgbPunkt() {
printf("RgbPunkt␣wird␣freigegeben\n");
}

// weitere Klassenfunktionen...

virtual void reset() {


printf("RgbPunkt␣wird␣auf␣(0,␣0,␣0)␣gesetzt\n");
r = 0;
g = 0;
b = 0;
}
private:
float r;
float g;
float b;
};
 

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 18

Nun wird folgender Quelltext ausgeführt:


 
1 int main(int argc, char * argv[])
2 {
3 Punkt * p = new RgbPunkt();
4 p->reset();
5 delete p;
6
7 return 0;
8 }
9
 

(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.

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 19

d) Überladen einer Funktion (4P.)

Gegeben ist folgende Klasse:


 
1 // Ausschnitt aus der Header-Datei
2 class Punkt {
3 public:
4 Punkt();
5 ~Punkt();
6
7 protected:
8 double x;
9 double y;
10 };
11
 
 
1 // Ausschnitt aus der .cpp-Datei
2 Punkt::Punkt() : x(0.0), y(0.0)
3 {
4 }
5
6 ~Punkt()
7 {
8 }
9
 

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.

Programmierung in der Automatisierungstechnik (C/C++)


Musterlösung Seite 20

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;
}

void Punkt::setPunkt(const Punkt & p)


{
x = p.x;
y = p.y;
}
 

Punkteverteilung:

• 2P. void setPunkt(double x, double y); richtig implementiert.


• 2P. void setPunkt(const Punkt & p); richtig implementiert.
• -0.5P. Abzug für jeden Syntaxfehler.

Programmierung in der Automatisierungstechnik (C/C++)

Das könnte Ihnen auch gefallen