Skip to content
Snippets Groups Projects
Commit cf7e8374 authored by Peter Gerwinski's avatar Peter Gerwinski
Browse files

Musterlösung 14.1.2019

parent bc2d65bb
Branches
No related tags found
No related merge requests found
File added
% hp-musterloesung-20190114.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019 Peter Gerwinski
%
% This document is free software: you can redistribute it and/or
% modify it either under the terms of the Creative Commons
% Attribution-ShareAlike 3.0 License, or under the terms of the
% GNU General Public License as published by the Free Software
% Foundation, either version 3 of the License, or (at your option)
% any later version.
%
% This document is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this document. If not, see <http://www.gnu.org/licenses/>.
%
% You should have received a copy of the Creative Commons
% Attribution-ShareAlike 3.0 Unported License along with this
% document. If not, see <http://creativecommons.org/licenses/>.
% README: Iteratorfunktionen, Objektorientierte Tier-Datenbank
\documentclass[a4paper]{article}
\usepackage{pgscript}
\usepackage{sfmath}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- 14.\ Januar 2019}
\exercise{Iterationsfunktionen}
Wir betrachten das folgende Programm (\gitfile{hp}{20190114}{aufgabe-1.c}):
\begin{minipage}[t]{0.4\textwidth}
\begin{lstlisting}[gobble=6]
#include <stdio.h>
void foreach (int *a, void (*fun) (int x))
{
for (int *p = a; *p >= 0; p++)
fun (*p);
}
void even_or_odd (int x)
{
if (x % 2)
printf ("%d ist ungerade.\n", x);
else
printf ("%d ist gerade.\n", x);
}
\end{lstlisting}
\end{minipage}\hfill
\begin{minipage}[t]{0.52\textwidth}
\begin{lstlisting}[gobble=6]
int main (void)
{
int numbers[] = { 12, 17, 32, 1, 3, 16, 19, 18, -1 };
foreach (numbers, even_or_odd);
return 0;
}
\end{lstlisting}
\begin{enumerate}[\quad(a)]
\item
Was bedeutet \lstinline{void (*fun) (int x)},
und welchen Sinn hat seine Verwendung in der Funktion \lstinline{foreach()}?
\points{2}
\item
Schreiben Sie das Hauptprogramm \lstinline{main()} so um,
daß es unter Verwendung der Funktion \lstinline{foreach()}
die Summe aller positiven Zahlen in dem Array berechnet.
Sie dürfen dabei weitere Funktionen sowie globale Variable einführen.
\points{4}
\end{enumerate}
\end{minipage}
\solution
\begin{enumerate}[\quad(a)]
\item
\textbf{Was bedeutet \lstinline{void (*fun) (int x)},
und welchen Sinn hat seine Verwendung in der Funktion \lstinline{foreach()}?}
\lstinline{void (*fun) (int x)} deklariert einen Zeiger \lstinline{fun},
der auf Funktionen zeigen kann, die einen Parameter \lstinline{x}
vom Typ \lstinline{int} erwarten und keinen Wert zurückgeben (\lstinline{void}).
Durch die Übergabe eines derartigen Parameters an die Funktion \lstinline{foreach()}
lassen wir dem Aufrufer die Wahl,
welche Aktion für alle Elemente des Arrays aufgerufen werden soll.
\item
\textbf{Schreiben Sie das Hauptprogramm \lstinline{main()} so um,
daß es unter Verwendung der Funktion \lstinline{foreach()}
die Summe aller positiven Zahlen in dem Array berechnet.
Sie dürfen dabei weitere Funktionen sowie globale Variable einführen.}
Siehe: \gitfile{hp}{20190114}{loesung-1.c}
Damit die Funktion \lstinline{add_up()} Zugriff auf die Variable \lstinline{sum} hat,
muß diese global sein
und vor der Funktion \lstinline{add_up()} deklariert werden.
Die Bedingung, daß nur positive Zahlen summiert werden sollen,
ist durch die Arbeitsweise der Funktion \lstinline{foreach()}
bereits gewährleistet, da negative Zahlen als Ende-Markierungen dienen.
Wichtig ist, daß die Variable \lstinline{sum}
vor dem Aufruf der Funktion \lstinline{foreach()}
auf den Wert \lstinline{0} gesetzt wird.
In \gitfile{hp}{20190114}{loesung-1.c} geschieht dies
durch die Initialisierung von \lstinline{sum}.
Wenn mehrere Summen berechnet werden sollen,
muß dies durch explizite Zuweisungen \lstinline{sum = 0}
vor den Aufrufen von \lstinline{foreach()} erfolgen.
\end{enumerate}
\exercise{Objektorientierte Tier-Datenbank}
Das auf der nächsten Seite in Blau dargestellte Programm (Datei: \gitfile{hp}{20190114}{aufgabe-2a.c})\\
soll Daten von Tieren verwalten.
Beim Compilieren erscheinen die folgende Fehlermeldungen:
\begin{lstlisting}[style=terminal]
$ ¡gcc -std=c99 -Wall -O aufgabe-2a.c -o aufgabe-2a¿
aufgabe-2a.c: In function 'main':
aufgabe-2a.c:31: error: 'animal' has no member named 'wings'
aufgabe-2a.c:37: error: 'animal' has no member named 'legs'
\end{lstlisting}
Der Programmierer nimmt die auf der nächsten Seite in Rot dargestellten Ersetzungen vor\\
(Datei: \gitfile{hp}{20190114}{aufgabe-2b.c}).
Daraufhin gelingt das Compilieren, und die Ausgabe des Programms lautet:
\begin{lstlisting}[style=terminal]
$ ¡gcc -std=c99 -Wall -O aufgabe-2b.c -o aufgabe-2b¿
$ ¡./aufgabe-2b¿
A duck has 2 legs.
Error in animal: cow
\end{lstlisting}
\begin{itemize}
\item[(a)]
Erklären Sie die o.\,a.\ Compiler-Fehlermeldungen.
\points{2}
\item[(b)]
Wieso verschwinden die Fehlermeldungen nach den o.\,a.\ Ersetzungen?
\points{3}
\item[(c)]
Erklären Sie die Ausgabe des Programms.
\points{5}
\item[(d)]
Beschreiben Sie -- in Worten und/oder als C-Quelltext -- einen Weg,
das Programm so zu berichtigen, daß es die Eingabedaten
(``A duck has 2 wings. A cow has 4 legs.'') korrekt speichert und ausgibt.\\
\points{4}
\item[(e)]
Schreiben Sie das Programm so um,
daß es keine expliziten Typumwandlungen mehr benötigt.\par
Hinweis: Verwenden Sie \lstinline{union}.
\points{4}
\item[(f)]
Schreiben Sie das Programm weiter um,
so daß es die Objektinstanzen \lstinline{duck} und \lstinline{cow}
dynamisch erzeugt.\par
Hinweis: Verwenden Sie \lstinline{malloc()} und schreiben Sie Konstruktoren.
\points{4}
\item[(g)]
Schreiben Sie das Programm weiter um,
so daß die Ausgabe nicht mehr direkt im Hauptprogramm erfolgt,
sondern stattdessen eine virtuelle Methode \lstinline{print()}
aufgerufen wird.\par
Hinweis: Verwenden Sie in den Objekten Zeiger auf Funktionen,
und initialisieren Sie diese in den Konstruktoren.
\points{4}
\end{itemize}
\begin{minipage}[t]{0.34\textwidth}
\begin{lstlisting}[gobble=6,xleftmargin=0pt]
#include <stdio.h>
#define ANIMAL 0
#define WITH_WINGS 1
#define WITH_LEGS 2
typedef struct animal
{
int type;
char *name;
} animal;
typedef struct with_wings
{
int wings;
} with_wings;
typedef struct with_legs
{
int legs;
} with_legs;
\end{lstlisting}
\end{minipage}\hfill
\begin{minipage}[t]{0.65\textwidth}
\begin{lstlisting}[gobble=6,xleftmargin=0pt]
int main (void)
{
animal *a[2];
animal duck;
a[0] = &duck;
a[0]->type = WITH_WINGS;
a[0]->name = "duck";
a[0]->wings = 2;
animal cow;
a[1] = &cow;
a[1]->type = WITH_LEGS;
a[1]->name = "cow";
a[1]->legs = 4;
for (int i = 0; i < 2; i++)
if (a[i]->type == WITH_LEGS)
printf ("A %s has %d legs.\n", a[i]->name,
((with_legs *) a[i])-> legs);
else if (a[i]->type == WITH_WINGS)
printf ("A %s has %d wings.\n", a[i]->name,
((with_wings *) a[i])-> wings);
else
printf ("Error in animal: %s\n", a[i]->name);
return 0;
}
\end{lstlisting}
\begin{picture}(0,0)
\color{red}
\put(3.7,6.207){\vector(-1,0){0.7}}
\put(3.8,6.207){\makebox(0,0)[l]{\lstinline[basicstyle=\color{red}]{((with_legs *) a[1])->legs = 4;}}}
\put(4.0,8.735){\vector(-1,0){0.7}}
\put(4.1,8.735){\makebox(0,0)[l]{\lstinline[basicstyle=\color{red}]{((with_wings *) a[0])->wings = 2;}}}
\end{picture}
\end{minipage}
\solution
\begin{itemize}
\item[(a)]
\textbf{Erklären Sie die o.\,a.\ Compiler-Fehlermeldungen.}
\lstinline{a[0]} und \lstinline{a[1]}
sind gemäß der Deklaration \lstinline{animal *a[2]}
Zeiger auf Variablen vom Typ \lstinline{animal} (ein \lstinline{struct}).
Wenn man diesen Zeiger dereferenziert (\lstinline{->}),
erhält man eine \lstinline{animal}-Variable.
Diese enthält keine Datenfelder \lstinline{wings} bzw.\ \lstinline{legs}.
\item[(b)]
\textbf{Wieso verschwinden die Fehlermeldungen nach den o.\,a.\ Ersetzungen?}
Durch die \emph{explizite Typumwandlung des Zeigers\/}
erhalten wir einen Zeiger auf eine \lstinline{with_wings}-
bzw.\ auf eine \lstinline{with_legs}-Variable.
Diese enthalten die Datenfelder \lstinline{wings} bzw.\ lstinline{legs}.
\item[(c)]
\textbf{Erklären Sie die Ausgabe des Programms.}
Durch die explizite Typumwandlung des Zeigers
zeigt \lstinline{a[0]} auf eine \lstinline{with_wings}-Variable.
Diese enthält nur ein einziges Datenfeld \lstinline{wings},
das an genau derselben Stelle im Speicher liegt
wie \lstinline{a[0]->type}, also das Datenfeld \lstinline{type}
der \lstinline{animal}-Variable, auf die der Zeiger \lstinline{a[0]} zeigt.
Durch die Zuweisung der Zahl \lstinline{2}
an \lstinline{((with_wings *) a[0])->wings}
überschreiben wir also \lstinline{a[0]->type},
so daß das \lstinline{if} in der \lstinline{for}-Schleife
\lstinline{a[0]} als \lstinline{WITH_LEGS} erkennt.
Bei der Ausgabe \lstinline[style=terminal]{A duck has 2 legs.}
wird das Datenfeld \lstinline{((with_legs *)a[0])->legs} als Zahl ausgegeben.
Dieses Datenfeld befindet sich in denselben Speicherzellen wie
\lstinline{a[0]->type} und \lstinline{((with_wings *)} % :-(
\lstinline{a[0]->wings}
und hat daher ebenfalls den Wert 2.
Auf die gleiche Weise überschreiben wir durch die Zuweisung der Zahl 4
an \lstinline{((with_legs *) a[1])->legs}
das Datenfeld \lstinline{a[0]->type},
so daß das \lstinline{if} in der \lstinline{for}-Schleife
\lstinline{a[1]} als unbekanntes Tier (Nr.\ 4) erkennt und
\lstinline[style=terminal]{Error in animal: cow} ausgibt.
\item[(d)]
\textbf{Beschreiben Sie -- in Worten und/oder als C-Quelltext -- einen Weg,
das Programm so zu berichtigen, daß es die Eingabedaten
(``A duck has 2 wings. A cow has 4 legs.'') korrekt speichert und ausgibt.}
Damit die \emph{Vererbung\/} zwischen den Objekten
\lstinline{animal}, \lstinline{with_wings} und \lstinline{with_legs}
funktioniert, müssen die abgeleiteten Klassen \lstinline{with_wings} und \lstinline{with_legs}
alle Datenfelder der Basisklasse \lstinline{animal} erben.
In C geschieht dies explizit; die Datenfelder müssen in den
abgeleiteten Klassen neu angegeben werden
(siehe \gitfile{hp}{20190114}{loesung-2d-1.c}):
\begin{lstlisting}[gobble=8]
typedef struct animal
{
int type;
char *name;
} animal;
typedef struct with_wings
{
int type;
char *name;
int wings;
} with_wings;
typedef struct with_legs
{
int type;
char *name;
int legs;
} with_legs;
\end{lstlisting}
Zusätzlich ist es notwendig,
die Instanzen \lstinline{duck} und \lstinline{cow}
der abgeleiteten Klassen \lstinline{with_wings} und \lstinline{with_legs}
auch als solche zu deklarieren,
damit für sie genügend Speicher reserviert wird:
\begin{lstlisting}[gobble=8]
animal *a[2];
with_wings duck;
a[0] = (animal *) &duck;
a[0]->type = WITH_WINGS;
a[0]->name = "duck";
((with_wings *) a[0])->wings = 2;
with_legs cow;
a[1] = (animal *) &cow;
a[1]->type = WITH_LEGS;
a[1]->name = "cow";
((with_legs *) a[1])->legs = 4;
\end{lstlisting}
Wenn man dies vergißt und sie nur als \lstinline{animal} deklariert,
wird auch nur Speicherplatz für (kleinere)
\lstinline{animal}-Variable angelegt.
Dadurch kommt es zu Speicherzugriffen außerhalb der
deklarierten Variablen, was letztlich zu einem Absturz führt
(siehe \gitfile{hp}{20190114}{loesung-2d-0f.c}).
Für die Zuweisung eines Zeigers auf \lstinline{duck}
an \lstinline{a[0]}, also an einen Zeiger auf \lstinline{animal}
wird eine weitere explizite Typumwandlung notwendig.
Entsprechendes gilt für die Zuweisung eines Zeigers auf \lstinline{cow}
an \lstinline{a[1]}.
Es ist sinnvoll, explizite Typumwandlungen so weit wie möglich zu vermeiden.
Es ist einfacher und gleichzeitig sicherer,
direkt in die Variablen \lstinline{duck} und \lstinline{cow}
zu schreiben, anstatt dies über die Zeiger \lstinline{a[0]}
und \lstinline{a[1]} zu tun
(siehe \gitfile{hp}{20190114}{loesung-2d-2.c}):
\begin{lstlisting}[gobble=8]
animal *a[2];
with_wings duck;
a[0] = (animal *) &duck;
duck.type = WITH_WINGS;
duck.name = "duck";
duck.wings = 2;
with_legs cow;
a[1] = (animal *) &cow;
cow.type = WITH_LEGS;
cow.name = "cow";
cow.legs = 4;
\end{lstlisting}
\item[(e)]
\textbf{Schreiben Sie das Programm so um,
daß es keine expliziten Typumwandlungen mehr benötigt.}\par
\textbf{Hinweis: Verwenden Sie \lstinline{union}.}
Siehe \gitfile{hp}{20190114}{loesung-2e.c}.
Diese Lösung basiert auf \gitfile{hp}{20190114}{loesung-2d-2.c},
da diese bereits weniger explizite Typumwandlungen enthält
als \gitfile{hp}{20190114}{loesung-2d-1.c}.
Arbeitsschritte:
\begin{itemize}
\item
Umbenennen des Basistyps \lstinline{animal} in \lstinline{base},
damit wir den Bezeichner \lstinline{animal}
für die \lstinline{union} verwenden können
\item
Schreiben einer \lstinline{union animal},
die die drei Klassen \lstinline{base},
\lstinline{with_wings} und \lstinline{with_legs}
als Datenfelder enthält
\item
Umschreiben der Initialisierungen:
Zugriff auf Datenfelder erfolgt nun durch
z.\,B.\ \lstinline{a[0]->b.name}.
Hierbei ist \lstinline{b} der Name des \lstinline{base}-Datenfelds
innerhalb der \lstinline{union animal}.
\item
Auf gleiche Weise schreiben wir die \lstinline{if}-Bedingungen
innerhalb der \lstinline{for}-Schleife
sowie die Parameter der \lstinline{printf()}-Aufrufe um.
\end{itemize}
Explizite Typumwandlungen sind nun nicht mehr nötig.
Nachteil dieser Lösung:
Jede Objekt-Variable belegt nun Speicherplatz
für die gesamte \lstinline{union animal},
anstatt nur für die benötigte Variable vom Typ
\lstinline{with_wings} oder \lstinline{with_legs}.
Dies kann zu einer Verschwendung von Speicherplatz führen,
auch wenn dies in diesem Beispielprogramm tatsächlich nicht der Fall ist.
\item[(f)]
\textbf{Schreiben Sie das Programm weiter um,
so daß es die Objektinstanzen \lstinline{duck} und \lstinline{cow}
dynamisch erzeugt.}\par
\textbf{Hinweis: Verwenden Sie \lstinline{malloc()} und schreiben Sie Konstruktoren.}
Siehe \gitfile{hp}{20190114}{loesung-2f.c}.
\item[(g)]
\textbf{Schreiben Sie das Programm weiter um,
so daß die Ausgabe nicht mehr direkt im Hauptprogramm erfolgt,
sondern stattdessen eine virtuelle Methode \lstinline{print()}
aufgerufen wird.}\par
\textbf{Hinweis: Verwenden Sie in den Objekten Zeiger auf Funktionen,
und initialisieren Sie diese in den Konstruktoren.}
Siehe \gitfile{hp}{20190114}{loesung-2g.c}.
\end{itemize}
\end{document}
#include <stdio.h>
void foreach (int *a, void (*fun) (int x))
{
for (int *p = a; *p >= 0; p++)
fun (*p);
}
void even_or_odd (int x)
{
if (x % 2)
printf ("%d ist ungerade.\n", x);
else
printf ("%d ist gerade.\n", x);
}
int sum = 0;
void add_up (int x)
{
sum += x;
}
int main (void)
{
int numbers[] = { 12, 17, 32, 1, 3, 16, 19, 18, -1 };
foreach (numbers, add_up);
printf ("Summe: %d\n", sum);
return 0;
}
#include <stdio.h>
#define ANIMAL 0
#define WITH_WINGS 1
#define WITH_LEGS 2
typedef struct animal
{
int type;
char *name;
} animal;
typedef struct with_wings
{
int type;
char *name;
int wings;
} with_wings;
typedef struct with_legs
{
int type;
char *name;
int legs;
} with_legs;
int main (void)
{
animal *a[2];
animal duck;
a[0] = &duck;
a[0]->type = WITH_WINGS;
a[0]->name = "duck";
((with_wings *) a[0])->wings = 2;
animal cow;
a[1] = &cow;
a[1]->type = WITH_LEGS;
a[1]->name = "cow";
((with_legs *) a[1])->legs = 4;
for (int i = 0; i < 2; i++)
if (a[i]->type == WITH_LEGS)
printf ("A %s has %d legs.\n", a[i]->name,
((with_legs *) a[i])-> legs);
else if (a[i]->type == WITH_WINGS)
printf ("A %s has %d wings.\n", a[i]->name,
((with_wings *) a[i])-> wings);
else
printf ("Error in animal: %s\n", a[i]->name);
return 0;
}
#include <stdio.h>
#define ANIMAL 0
#define WITH_WINGS 1
#define WITH_LEGS 2
typedef struct animal
{
int type;
char *name;
} animal;
typedef struct with_wings
{
int type;
char *name;
int wings;
} with_wings;
typedef struct with_legs
{
int type;
char *name;
int legs;
} with_legs;
int main (void)
{
animal *a[2];
with_wings duck;
a[0] = (animal *) &duck;
a[0]->type = WITH_WINGS;
a[0]->name = "duck";
((with_wings *) a[0])->wings = 2;
with_legs cow;
a[1] = (animal *) &cow;
a[1]->type = WITH_LEGS;
a[1]->name = "cow";
((with_legs *) a[1])->legs = 4;
for (int i = 0; i < 2; i++)
if (a[i]->type == WITH_LEGS)
printf ("A %s has %d legs.\n", a[i]->name,
((with_legs *) a[i])-> legs);
else if (a[i]->type == WITH_WINGS)
printf ("A %s has %d wings.\n", a[i]->name,
((with_wings *) a[i])-> wings);
else
printf ("Error in animal: %s\n", a[i]->name);
return 0;
}
#include <stdio.h>
#define ANIMAL 0
#define WITH_WINGS 1
#define WITH_LEGS 2
typedef struct animal
{
int type;
char *name;
} animal;
typedef struct with_wings
{
int type;
char *name;
int wings;
} with_wings;
typedef struct with_legs
{
int type;
char *name;
int legs;
} with_legs;
int main (void)
{
animal *a[2];
with_wings duck;
a[0] = (animal *) &duck;
duck.type = WITH_WINGS;
duck.name = "duck";
duck.wings = 2;
with_legs cow;
a[1] = (animal *) &cow;
cow.type = WITH_LEGS;
cow.name = "cow";
cow.legs = 4;
for (int i = 0; i < 2; i++)
if (a[i]->type == WITH_LEGS)
printf ("A %s has %d legs.\n", a[i]->name,
((with_legs *) a[i])-> legs);
else if (a[i]->type == WITH_WINGS)
printf ("A %s has %d wings.\n", a[i]->name,
((with_wings *) a[i])-> wings);
else
printf ("Error in animal: %s\n", a[i]->name);
return 0;
}
#include <stdio.h>
#define ANIMAL 0
#define WITH_WINGS 1
#define WITH_LEGS 2
typedef struct
{
int type;
char *name;
} base;
typedef struct
{
int type;
char *name;
int wings;
} with_wings;
typedef struct
{
int type;
char *name;
int legs;
} with_legs;
typedef union
{
base b;
with_wings w;
with_legs l;
} animal;
int main (void)
{
animal *a[2];
animal duck;
a[0] = &duck;
duck.b.type = WITH_WINGS;
duck.b.name = "duck";
duck.w.wings = 2;
animal cow;
a[1] = &cow;
cow.b.type = WITH_LEGS;
cow.b.name = "cow";
cow.l.legs = 4;
for (int i = 0; i < 2; i++)
if (a[i]->b.type == WITH_LEGS)
printf ("A %s has %d legs.\n", a[i]->b.name,
a[i]->l.legs);
else if (a[i]->b.type == WITH_WINGS)
printf ("A %s has %d wings.\n", a[i]->b.name,
a[i]->w.wings);
else
printf ("Error in animal: %s\n", a[i]->b.name);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define ANIMAL 0
#define WITH_WINGS 1
#define WITH_LEGS 2
typedef struct
{
int type;
char *name;
} base;
typedef struct
{
int type;
char *name;
int wings;
} with_wings;
typedef struct
{
int type;
char *name;
int legs;
} with_legs;
typedef union
{
base b;
with_wings w;
with_legs l;
} animal;
animal *new_with_wings (char *name, int wings)
{
animal *a = malloc (sizeof (with_wings));
a->b.type = WITH_WINGS;
a->b.name = name;
a->w.wings = wings;
return a;
}
animal *new_with_legs (char *name, int legs)
{
animal *a = malloc (sizeof (with_legs));
a->b.type = WITH_LEGS;
a->b.name = name;
a->l.legs = legs;
return a;
}
int main (void)
{
animal *a[2] = { new_with_wings ("duck", 2),
new_with_legs ("cow", 4) };
for (int i = 0; i < 2; i++)
if (a[i]->b.type == WITH_LEGS)
printf ("A %s has %d legs.\n", a[i]->b.name,
a[i]->l.legs);
else if (a[i]->b.type == WITH_WINGS)
printf ("A %s has %d wings.\n", a[i]->b.name,
a[i]->w.wings);
else
printf ("Error in animal: %s\n", a[i]->b.name);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define ANIMAL 0
#define WITH_WINGS 1
#define WITH_LEGS 2
union animal;
typedef struct
{
int type;
char *name;
void (*print) (union animal *this);
} base;
typedef struct
{
int type;
char *name;
void (*print) (union animal *this);
int wings;
} with_wings;
typedef struct
{
int type;
char *name;
void (*print) (union animal *this);
int legs;
} with_legs;
typedef union animal
{
base b;
with_wings w;
with_legs l;
} animal;
void print_with_wings (animal *this)
{
printf ("A %s has %d wings.\n", this->b.name, this->w.wings);
}
void print_with_legs (animal *this)
{
printf ("A %s has %d legs.\n", this->b.name, this->l.legs);
}
animal *new_with_wings (char *name, int wings)
{
animal *a = malloc (sizeof (with_wings));
a->b.type = WITH_WINGS;
a->b.name = name;
a->b.print = print_with_wings;
a->w.wings = wings;
return a;
}
animal *new_with_legs (char *name, int legs)
{
animal *a = malloc (sizeof (with_legs));
a->b.type = WITH_LEGS;
a->b.name = name;
a->b.print = print_with_legs;
a->l.legs = legs;
return a;
}
int main (void)
{
animal *a[2] = { new_with_wings ("duck", 2),
new_with_legs ("cow", 4) };
for (int i = 0; i < 2; i++)
a[i]->b.print (a[i]);
return 0;
}
......@@ -64,6 +64,7 @@ Musterlösungen:
* [10.12.2018: Trickprogrammierung, Thermometer-Baustein an I²C-Bus](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20181210/hp-musterloesung-20181210.pdf)
* [17.12.2018: Fakultät, Lauflicht, Länge von Strings (Neuauflage)](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20181217/hp-musterloesung-20181217.pdf)
* [07.01.2019: Speicherformate von Zahlen, Zeigerarithmetik](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20190107/hp-musterloesung-20190107.pdf)
* [14.01.2019: Iteratorfunktionen, Objektorientierte Tier-Datenbank](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20190114/hp-musterloesung-20190114.pdf)
Tafelbilder:
------------
......
No preview for this file type
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment