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

Vorbereitung 11.1.2024

parent 42229110
No related branches found
No related tags found
No related merge requests found
Showing
with 2532 additions and 3 deletions
......@@ -20,7 +20,7 @@
% Attribution-ShareAlike 3.0 Unported License along with this
% document. If not, see <http://creativecommons.org/licenses/>.
% README: Objektorientierte Programmierung: Einführung
% README: Objektorientierte Programmierung
\documentclass[10pt,t]{beamer}
......
No preview for this file type
......@@ -556,7 +556,7 @@
- 7R_{\mu\nu\rho\sigma}R^{\mu\nu\rho\sigma})$
\vspace{-\medskipamount}
\begin{displaymath}
\Rightarrow V_{\text{CC}}(r) \approx -\frac{c^2\beta}{r} + \fr12 c^2 \gamma\,r
\Rightarrow V(r) \approx -\frac{c^2\beta}{r} + \fr12 c^2 \gamma\,r
\qquad
\text{(Newton + \only<2->{winzige }konstante Kraft)}
\end{displaymath}
......@@ -728,7 +728,7 @@
\vspace{-\smallskipamount}
\begin{itemize}
\item
\file{adl2xsm.c}\\
\file{adl2xym.c}\\
astronomische in kartesische Koordinaten\\
und Leuchtkraft in Masse umrechnen
\item
......
#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;
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;
}
#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;
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>
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 main (void)
{
int numbers[] = { 12, 17, 32, 1, 3, 16, 19, 18, -1 };
foreach (numbers, even_or_odd);
return 0;
}
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
void show (void)
{
printf ("stack content:");
for (int i = 0; i < stack_pointer; i++)
printf (" %d", stack[i]);
if (stack_pointer)
printf ("\n");
else
printf (" (empty)\n");
}
void insert (int x, int pos)
{
for (int i = pos; i < stack_pointer; i++)
stack[i + 1] = stack[i];
stack[pos] = x;
stack_pointer++;
}
void insert_sorted (int x)
{
int i = 0;
while (i < stack_pointer && x < stack[i])
i++;
insert (x, i);
}
int main (void)
{
push (3);
push (7);
push (137);
show ();
insert (5, 1);
show ();
insert_sorted (42);
show ();
insert_sorted (2);
show ();
return 0;
}
../common/hello-gtk.png
\ No newline at end of file
File added
This diff is collapsed.
File added
% hp-musterloesung-20240111.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 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: Objektorientierte Tier-Datenbank (Ergänzung), Iterationsfunktionen, Stack-Operationen
\documentclass[a4paper]{article}
\usepackage{pgscript}
\usepackage{gnuplot-lua-tikz}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- 11.\ Januar 2024}
\exercise{Objektorientierte Tier-Datenbank (Ergänzung)}
Diese Aufgabe ist eine Neuauflage
der Übungsaufgabe 3 vom 14.\ Dezember 2023,
ergänzt um die Teilaufgaben (e) bis (g).
\medskip
Das auf der nächsten Seite dargestellte Programm
(Datei: \gitfile{hp}{2023ws/20240111}{aufgabe-1a.c})
soll Daten von Tieren verwalten.
Beim Compilieren erscheinen die folgende Fehlermeldungen:
\begin{lstlisting}[style=terminal]
$ ¡gcc -std=c99 -Wall -O aufgabe-1a.c -o aufgabe-1a¿
aufgabe-1a.c: In function 'main':
aufgabe-1a.c:31: error: 'animal' has no member named 'wings'
aufgabe-1a.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}{2023ws/20240111}{aufgabe-1b.c}).
Daraufhin gelingt das Compilieren, und die Ausgabe des Programms lautet:
\begin{lstlisting}[style=terminal]
$ ¡gcc -std=c99 -Wall -O aufgabe-1b.c -o aufgabe-1b¿
$ ¡./aufgabe-1b¿
A duck has 2 legs.
Error in animal: cow
\end{lstlisting}
\begin{itemize}
\color{gray}
\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}
\color{black}
\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[(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}{2023ws/20240111}{loesung-1e.c}.
Diese Lösung basiert auf \gitfile{hp}{2023ws/20240111}{loesung-3d-2.c},
da diese bereits weniger explizite Typumwandlungen enthält
als \gitfile{hp}{2023ws/20240111}{loesung-3d-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}{2023ws/20240111}{loesung-1f.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}{2023ws/20240111}{loesung-1g.c}.
\end{itemize}
\exercise{Iterationsfunktionen}
Wir betrachten das folgende Programm (\gitfile{hp}{2023ws/20240111}{aufgabe-2.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}
\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}{2023ws/20240111}{loesung-2.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}{2023ws/20240111}{loesung-2.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{Stack-Operationen}
Das folgende Programm (\gitfile{hp}{2023ws/20240111}{aufgabe-3.c})
implementiert einen Stapelspeicher (Stack).
Dies ist ein Array, das nur bis zu einer variablen Obergrenze (Stack-Pointer)
tatsächlich genutzt wird.
An dieser Obergrenze kann man Elemente hinzufügen (push).
In dieser Aufgabe sollen zusätzlich Elemente
in der Mitte eingefügt werden (insert).
Die dafür bereits existierenden Funktionen \lstinline{insert()}
und \lstinline{insert_sorted()} sind jedoch fehlerhaft.
\begin{minipage}[t]{0.5\textwidth}
\begin{lstlisting}[gobble=6]
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
void show (void)
{
printf ("stack content:");
for (int i = 0; i < stack_pointer; i++)
printf (" %d", stack[i]);
if (stack_pointer)
printf ("\n");
else
printf (" (empty)\n");
}
\end{lstlisting}
\end{minipage}\hfill
\begin{minipage}[t]{0.5\textwidth}
\begin{lstlisting}[gobble=6]
void insert (int x, int pos)
{
for (int i = pos; i < stack_pointer; i++)
stack[i + 1] = stack[i];
stack[pos] = x;
stack_pointer++;
}
void insert_sorted (int x)
{
int i = 0;
while (i < stack_pointer && x < stack[i])
i++;
insert (x, i);
}
int main (void)
{
push (3);
push (7);
push (137);
show ();
insert (5, 1);
show ();
insert_sorted (42);
show ();
insert_sorted (2);
show ();
return 0;
}
\end{lstlisting}
\end{minipage}
\begin{enumerate}[\quad(a)]
\item
Korrigieren Sie das Programm so,
daß die Funktion \lstinline{insert()} ihren Parameter \lstinline{x}
an der Stelle \lstinline{pos} in den Stack einfügt
und den sonstigen Inhalt des Stacks verschiebt, aber nicht zerstört.
\points{3}
\item
Korrigieren Sie das Programm so,
daß die Funktion \lstinline{insert_sorted()} ihren Parameter \lstinline{x}
an derjenigen Stelle einfügt, an die er von der Sortierung her gehört.
(Der Stack wird hierbei vor dem Funktionsaufruf als sortiert vorausgesetzt.)
\points{2}
\item
Schreiben Sie eine zusätzliche Funktion \lstinline{int search (int x)},
die die Position (Index) des Elements \lstinline{x}
innerhalb des Stack zurückgibt -- oder die Zahl
\lstinline{-1}, wenn \lstinline{x} nicht im Stack enthalten ist.
Der Rechenaufwand darf höchstens $\mathcal{O}(n)$ betragen.
\points{3}
\item
Wie (c), aber der Rechenaufwand darf höchstens $\mathcal{O}(\log n)$ betragen.
\points{4}
\end{enumerate}
\solution
\begin{enumerate}[\quad(a)]
\item
\textbf{Korrigieren Sie das Programm so,
daß die Funktion \lstinline{insert()} ihren Parameter \lstinline{x}
an der Stelle \lstinline{pos} in den Stack einfügt,
und den sonstigen Inhalt des Stacks verschiebt, aber nicht zerstört.}
Die \lstinline{for}-Schleife in der Funktion \lstinline{insert()}
durchläuft das Array von unten nach oben.
Um den Inhalt des Arrays von unten nach oben zu verschieben,
muß man die Schleife jedoch von oben nach unten durchlaufen.
\goodbreak
Um die Funktion zu reparieren, ersetze man also
\begin{lstlisting}[gobble=8]
for (int i = pos; i < stack_pointer; i++)
\end{lstlisting}
durch:
\begin{lstlisting}[gobble=8]
for (int i = stack_pointer - 1; i >= pos; i--)
\end{lstlisting}
(Siehe auch: \gitfile{hp}{2023ws/20240111}{loesung-3.c})
\item
\textbf{Korrigieren Sie das Programm so,
daß die Funktion \lstinline{insert_sorted()} ihren Parameter \lstinline{x}
an derjenigen Stelle einfügt, an die er von der Sortierung her gehört.
(Der Stack wird hierbei vor dem Funktionsaufruf als sortiert vorausgesetzt.)}
Der Vergleich \lstinline{x < stack[i]}
als Bestandteil der \lstinline{while}-Bedingung
paßt nicht zur Durchlaufrichtung der Schleife (von unten nach oben).
Um die Funktion zu reparieren, kann man daher entweder
das Kleinerzeichen durch ein Größerzeichen ersetzen
(\lstinline{x > stack[i]} -- siehe \gitfile{hp}{2023ws/20240111}{loesung-3b-1.c})
oder die Schleife von oben nach unten durchlaufen
(siehe \gitfile{hp}{2023ws/20240111}{loesung-3b-2.c}).
Eine weitere Möglichkeit besteht darin,
das Suchen nach der Einfügeposition
mit dem Verschieben des Arrays zu kombinieren
(siehe \gitfile{hp}{2023ws/20240111}{loesung-3.c}).
Hierdurch spart man sich eine Schleife; das Programm wird schneller.
(Es bleibt allerdings bei $\mathcal{O}(n)$.)
\item
\textbf{Schreiben Sie eine zusätzliche Funktion \lstinline{int search (int x)},
die die Position (Index) des Elements \lstinline{x}
innerhalb des Stack zurückgibt
-- oder \lstinline{-1}, wenn \lstinline{x} nicht im Stack enthalten ist.
Der Rechenaufwand darf höchstens $\mathcal{O}(n)$ betragen.}
Man geht in einer Schleife den Stack (= den genutzten Teil des Arrays) durch.
Bei Gleichheit gibt man direkt mit \lstinline{return} den Index zurück.
Nach dem Schleifendurchlauf steht fest,
daß \lstinline{x} nicht im Stack vorhanden ist;
man kann dann direkt \lstinline{-1} zurückgeben
(siehe \gitfile{hp}{2023ws/20240111}{loesung-3c.c}).
Da es sich um eine einzelne Schleife handelt,
ist die Ordnung $\mathcal{O}(n)$.
\item
\textbf{Wie (c), aber der Rechenaufwand darf höchstens $\mathcal{O}(\log n)$ betragen.}
Um $\mathcal{O}(\log n)$ zu erreichen,
halbiert man fortwährend das Intervall von (einschließlich) \lstinline{0}
bis (ausschließlich) \lstinline{stack_pointer}
(siehe \gitfile{hp}{2023ws/20240111}{loesung-3d.c}). % --
% wie in der Funktion \lstinline{push_sorted()}
% im Beispiel-Programm \gitfile{hp}{2023ws/20240111}{stack-11.c}.
% Ein wichtiger Unterschied besteht darin,
Wichtig ist,
daß man nach dem Durchlauf der Schleife noch auf die Gleichheit
\lstinline{x == stack[left]} (insbesondere nicht: \lstinline{stack[right]})
prüfen und ggf.\ \lstinline{left} bzw.\ \lstinline{-1} zurückgeben muß.
\end{enumerate}
\end{document}
File added
% hp-uebung-20240111.pdf - Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 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: Objektorientierte Tier-Datenbank (Ergänzung), Iterationsfunktionen, Stack-Operationen
\documentclass[a4paper]{article}
\usepackage{pgscript}
\begin{document}
\thispagestyle{empty}
\section*{Hardwarenahe Programmierung\\
Übungsaufgaben -- 11.\ Januar 2024}
Diese Übung enthält Punkteangaben wie in einer Klausur.
Um zu "`bestehen"', müssen Sie innerhalb von 85 Minuten
unter Verwendung ausschließlich zugelassener Hilfsmittel
15 Punkte (von insgesamt \totalpoints) erreichen.
\exercise{Objektorientierte Tier-Datenbank (Ergänzung)}
Diese Aufgabe ist eine Neuauflage
der Übungsaufgabe 3 vom 14.\ Dezember 2023,
ergänzt um die Teilaufgaben (e) bis (g).
\medskip
Das auf der nächsten Seite dargestellte Programm
(Datei: \gitfile{hp}{2023ws/20240111}{aufgabe-1a.c})
soll Daten von Tieren verwalten.
Beim Compilieren erscheinen die folgende Fehlermeldungen:
\begin{lstlisting}[style=terminal]
$ ¡gcc -std=c99 -Wall -O aufgabe-1a.c -o aufgabe-1a¿
aufgabe-1a.c: In function 'main':
aufgabe-1a.c:31: error: 'animal' has no member named 'wings'
aufgabe-1a.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}{2023ws/20240111}{aufgabe-1b.c}).
Daraufhin gelingt das Compilieren, und die Ausgabe des Programms lautet:
\begin{lstlisting}[style=terminal]
$ ¡gcc -std=c99 -Wall -O aufgabe-1b.c -o aufgabe-1b¿
$ ¡./aufgabe-1b¿
A duck has 2 legs.
Error in animal: cow
\end{lstlisting}
\begin{itemize}
\color{gray}
\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}
\color{black}
\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}
\vfil
\exercise{Iterationsfunktionen}
Wir betrachten das folgende Programm (\gitfile{hp}{2023ws/20240111}{aufgabe-2.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}
\clearpage
\exercise{Stack-Operationen}
Das folgende Programm (\gitfile{hp}{2023ws/20240111}{aufgabe-3.c})
implementiert einen Stapelspeicher (Stack).
Dies ist ein Array, das nur bis zu einer variablen Obergrenze (Stack-Pointer)
tatsächlich genutzt wird.
An dieser Obergrenze kann man Elemente hinzufügen (push).
In dieser Aufgabe sollen zusätzlich Elemente
in der Mitte eingefügt werden (insert).
Die dafür bereits existierenden Funktionen \lstinline{insert()}
und \lstinline{insert_sorted()} sind jedoch fehlerhaft.
\begin{minipage}[t]{0.5\textwidth}
\begin{lstlisting}[gobble=6]
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
void show (void)
{
printf ("stack content:");
for (int i = 0; i < stack_pointer; i++)
printf (" %d", stack[i]);
if (stack_pointer)
printf ("\n");
else
printf (" (empty)\n");
}
\end{lstlisting}
\end{minipage}\hfill
\begin{minipage}[t]{0.5\textwidth}
\begin{lstlisting}[gobble=6]
void insert (int x, int pos)
{
for (int i = pos; i < stack_pointer; i++)
stack[i + 1] = stack[i];
stack[pos] = x;
stack_pointer++;
}
void insert_sorted (int x)
{
int i = 0;
while (i < stack_pointer && x < stack[i])
i++;
insert (x, i);
}
int main (void)
{
push (3);
push (7);
push (137);
show ();
insert (5, 1);
show ();
insert_sorted (42);
show ();
insert_sorted (2);
show ();
return 0;
}
\end{lstlisting}
\end{minipage}
\begin{enumerate}[\quad(a)]
\item
Korrigieren Sie das Programm so,
daß die Funktion \lstinline{insert()} ihren Parameter \lstinline{x}
an der Stelle \lstinline{pos} in den Stack einfügt
und den sonstigen Inhalt des Stacks verschiebt, aber nicht zerstört.
\points{3}
\item
Korrigieren Sie das Programm so,
daß die Funktion \lstinline{insert_sorted()} ihren Parameter \lstinline{x}
an derjenigen Stelle einfügt, an die er von der Sortierung her gehört.
(Der Stack wird hierbei vor dem Funktionsaufruf als sortiert vorausgesetzt.)
\points{2}
\item
Schreiben Sie eine zusätzliche Funktion \lstinline{int search (int x)},
die die Position (Index) des Elements \lstinline{x}
innerhalb des Stack zurückgibt -- oder die Zahl
\lstinline{-1}, wenn \lstinline{x} nicht im Stack enthalten ist.
Der Rechenaufwand darf höchstens $\mathcal{O}(n)$ betragen.
\points{3}
\item
Wie (c), aber der Rechenaufwand darf höchstens $\mathcal{O}(\log n)$ betragen.
\points{4}
\end{enumerate}
\begin{flushright}
\textit{Viel Erfolg!}
\end{flushright}
\makeatletter
\immediate\write\@mainaux{\string\gdef\string\totalpoints{\arabic{points}}}
\makeatother
\end{document}
#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;
}
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
int pop (void)
{
return stack[--stack_pointer];
}
void show (void)
{
printf ("stack content:");
for (int i = 0; i < stack_pointer; i++)
printf (" %d", stack[i]);
if (stack_pointer)
printf ("\n");
else
printf (" (empty)\n");
}
void insert (int x, int pos)
{
for (int i = stack_pointer - 1; i >= pos; i--)
stack[i + 1] = stack[i];
stack[pos] = x;
stack_pointer++;
}
void insert_sorted (int x)
{
int i = stack_pointer - 1;
while (i >= 0 && x < stack[i])
{
stack[i + 1] = stack[i];
i--;
}
stack[i + 1] = x;
stack_pointer++;
}
int main (void)
{
push (3);
push (7);
push (137);
show ();
insert (5, 1);
show ();
insert_sorted (42);
show ();
insert_sorted (2);
show ();
return 0;
}
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
int pop (void)
{
return stack[--stack_pointer];
}
void show (void)
{
printf ("stack content:");
for (int i = 0; i < stack_pointer; i++)
printf (" %d", stack[i]);
if (stack_pointer)
printf ("\n");
else
printf (" (empty)\n");
}
void insert (int x, int pos)
{
for (int i = stack_pointer - 1; i >= pos; i--)
stack[i + 1] = stack[i];
stack[pos] = x;
stack_pointer++;
}
void insert_sorted (int x)
{
int i = 0;
while (i < stack_pointer && x > stack[i])
i++;
insert (x, i);
}
int main (void)
{
push (3);
push (7);
push (137);
show ();
insert (5, 1);
show ();
insert_sorted (42);
show ();
insert_sorted (2);
show ();
return 0;
}
#include <stdio.h>
#define STACK_SIZE 10
int stack[STACK_SIZE];
int stack_pointer = 0;
void push (int x)
{
stack[stack_pointer++] = x;
}
int pop (void)
{
return stack[--stack_pointer];
}
void show (void)
{
printf ("stack content:");
for (int i = 0; i < stack_pointer; i++)
printf (" %d", stack[i]);
if (stack_pointer)
printf ("\n");
else
printf (" (empty)\n");
}
void insert (int x, int pos)
{
for (int i = stack_pointer - 1; i >= pos; i--)
stack[i + 1] = stack[i];
stack[pos] = x;
stack_pointer++;
}
void insert_sorted (int x)
{
int i = stack_pointer - 1;
while (i >= 0 && x < stack[i])
i--;
insert (x, i + 1);
}
int main (void)
{
push (3);
push (7);
push (137);
show ();
insert (5, 1);
show ();
insert_sorted (42);
show ();
insert_sorted (2);
show ();
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment