diff --git a/20231214/aufgabe-2a.c b/20231214/aufgabe-2a.c new file mode 100644 index 0000000000000000000000000000000000000000..61b6e79400afbb8ac0609eb1b72c04b83a0fce41 --- /dev/null +++ b/20231214/aufgabe-2a.c @@ -0,0 +1,50 @@ +#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; +} diff --git a/20231214/aufgabe-2b.c b/20231214/aufgabe-2b.c new file mode 100644 index 0000000000000000000000000000000000000000..2cf3b56f4540f399d3761b0de929d80a1f1de611 --- /dev/null +++ b/20231214/aufgabe-2b.c @@ -0,0 +1,50 @@ +#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; +} diff --git a/20231214/hp-20231214.pdf b/20231214/hp-20231214.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b6d6d49611933ec9543ecdfcadb6cb4c8c625d41 Binary files /dev/null and b/20231214/hp-20231214.pdf differ diff --git a/20231214/hp-20231214.tex b/20231214/hp-20231214.tex new file mode 100644 index 0000000000000000000000000000000000000000..ea69ab90e96f387b0cc8f85ba59cd7a037a3cbf0 --- /dev/null +++ b/20231214/hp-20231214.tex @@ -0,0 +1,835 @@ +% hp-20231214.pdf - Lecture Slides on Low-Level Programming +% Copyright (C) 2012, 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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 Programmierung: Einführung + +\documentclass[10pt,t]{beamer} + +\usepackage{pgslides} +\usepackage{tikz} +\usepackage{rotating} + +\newcommand{\redurl}[1]{\href{#1}{\color{red}\nolinkurl{#1}}} + +\title{Hardwarenahe Programmierung} +\author{Prof.\ Dr.\ rer.\ nat.\ Peter Gerwinski} +\date{14.\ Dezember 2023} + +\begin{document} + +\maketitleframe + +\title{Hardwarenahe Programmierung} + +\nosectionnonumber{\inserttitle} + +\begin{frame} + + \shownosectionnonumber + + \begin{itemize} + \item[\textbf{1}] \textbf{Einführung} + \hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}} + \item[\textbf{2}] \textbf{Einführung in C} + \item[\textbf{3}] \textbf{Bibliotheken} + \item[\textbf{4}] \textbf{Hardwarenahe Programmierung} + \item[\textbf{5}] \textbf{Algorithmen} + \begin{itemize} + \item[5.1] Differentialgleichungen + \item[5.2] Rekursion + \color{medgreen} + \item[5.3] Aufwandsabschätzungen + \end{itemize} + \item[\textbf{6}] \textbf{Objektorientierte Programmierung} + \begin{itemize} + \color{red} + \item[6.0] Dynamische Speicherverwaltung + \item[6.1] Konzepte und Ziele + \item[6.2] Beispiel: Zahlen und Buchstaben + \color{black} + \item[6.3] Unions + \item[6.4] Virtuelle Methoden + \vspace*{-\smallskipamount} + \item[\dots] + \end{itemize} + \item[\textbf{7}] \textbf{Datenstrukturen} + \end{itemize} + +\end{frame} + +\setcounter{section}{4} +\section{Algorithmen} +\setcounter{subsection}{2} +\subsection{Aufwandsabschätzungen \protect\color{gray}-- Komplexitätsanalyse} + +\begin{frame}[fragile] + +% \newcommand{\w}{\hspace*{0.75pt}} + + \showsubsection + + \begin{picture}(0,0) + \put(7.6,-0.5){% + \begin{minipage}[t]{5.3cm} +% \vspace*{-1.0cm}\includegraphics{landau-symbols.pdf} + \vspace*{-1.0cm}\alt<16->{\includegraphics{landau-symbols-3.pdf}}% + {\alt<15->{\includegraphics{landau-symbols-2.pdf}}% + {\includegraphics{landau-symbols.pdf}}} + \small + \begin{description}\itemsep0pt\leftskip-0.5cm + \item[$n$:] Eingabedaten + \item[$g(n)$:] Rechenzeit + \end{description} + \end{minipage}} + \end{picture} + + \vspace*{-\bigskipamount} + + Wann ist ein Programm "`schnell"'? + + \medskip + + \begin{onlyenv}<1-2> + Türme von Hanoi: $\mathcal{O}(2^n)$ + \par\medskip + Für jede zusätzliche Scheibe\\verdoppelt sich die Rechenzeit! + \begin{itemize} + \arrowitem + $\frac{30,672\,\text{s}\,\cdot\,2^{32}}{3600\,\cdot\,24\,\cdot\,365,25} \approx 4174$ + Jahre\\[\smallskipamount] + für 64 Scheiben + \end{itemize} + + \bigskip + \end{onlyenv} + + \begin{onlyenv}<2-> + Faustregel:\\Schachtelung der Schleifen zählen\\ + $k$ Schleifen ineinander \textarrow\ $\mathcal{O}(n^k)$ + + \bigskip + \end{onlyenv} + + \begin{onlyenv}<3-13> + \textbf{Beispiel: Sortieralgorithmen} + + \smallskip + + Anzahl der Vergleiche bei $n$ Strings + \begin{itemize} + \item + Maximum suchen \pause[4]mit Schummeln\pause: $\mathcal{O}(1)$ + \pause + \item + Maximum suchen\pause: $\mathcal{O}(n)$ + \pause + \item + Selection-Sort\pause: $\mathcal{O}(n^2)$ + \pause + \item + Bubble-Sort\pause: $\mathcal{O}(n)$ bis $\mathcal{O}(n^2)$ + \pause + \item + Quicksort\pause: $\mathcal{O}(n\log n)$ bis $\mathcal{O}(n^2)$ + \end{itemize} + + \end{onlyenv} + + \begin{onlyenv}<14> + \textbf{Wie schnell ist RSA-Verschlüsselung?} + + \smallskip + + \begin{math} + c = m^e\,\%\,N + \end{math} + \quad + ("`$\%$"' = "`modulo"') + + \medskip + + \begin{lstlisting}[gobble=6,xleftmargin=2em] + int c = 1; + for (int i = 0; i < e; i++) + c = (c * m) % N; + \end{lstlisting} + + \smallskip + + \begin{itemize} + \item + $\mathcal{O}(e)$ Iterationen +% \item +% wenn $n$ die Anzahl der Binärziffern (Bits) von $e$ ist: +% $\mathcal{O}(2^n)$ Iterationen + \item + mit Trick: + $\mathcal{O}(\log e)$ Iterationen ($\log e$ = Anzahl der Ziffern von $e$) + \end{itemize} + + \smallskip + + Jede Iteration enthält eine Multiplikation und eine Division.\\ + Aufwand dafür: $\mathcal{O}(\log e)$\\ + \textarrow\ Gesamtaufwand: $\mathcal{O}\bigl((\log e)^2\bigr)$ + + \end{onlyenv} + + \begin{onlyenv}<15-> + + \textbf{Wie schnell ist RSA?}\\ + + \smallskip + + ($n$ = typische beteiligte Zahl, z.\,B. $e,p,q$) + + \begin{itemize} + \item + Ver- und Entschlüsselung (Exponentiation):\\ + \strut\hbox to 3.5cm{\color{red}$\mathcal{O}\!\left((\log n)^2\right)$\hss} + \only<16->{{\color{magenta}$\mathcal{O}(n^2)$}} + \item + Schlüsselerzeugung (Berechnung von $d$):\\ + \strut\hbox to 3.5cm{\color{red}$\mathcal{O}\!\left((\log n)^2\right)$\hss} + \only<16->{{\color{magenta}$\mathcal{O}(n^2)$}} + \item + Verschlüsselung brechen (Primfaktorzerlegung):\\ + \strut\hbox to 3.5cm{\color{red}$\mathcal{O}\bigl(2^{\sqrt{\log n\,\cdot\,\log\log n}}\bigr)$\hss} + \only<16->{{\color{magenta}$\mathcal{O}\bigl(2^{\sqrt{n\log n}}\bigr)$}} + \end{itemize} + + \vspace{0cm plus 1filll} + + \textbf{Die Sicherheit von RSA beruht darauf, + daß das Brechen der Verschlüsselung aufwendiger ist als + \boldmath$\mathcal{O}\bigl((\log n)^k\bigr)$ (für beliebiges $k$).} + + \vspace*{0.65cm} + + \end{onlyenv} + +\end{frame} + +\section{Objektorientierte Programmierung} + +\addtocounter{subsection}{-1} +\subsection{Dynamische Speicherverwaltung} + +\begin{frame}[fragile] + + \showsection + \showsubsection + + \begin{itemize} + \item + Array: feste Anzahl von Elementen desselben Typs (z.\,B.\ 3 ganze Zahlen) + \item + Dynamisches Array: variable Anzahl von Elementen desselben Typs + \end{itemize} + + \bigskip + + \begin{lstlisting} + char *name[] = { "Anna", "Berthold", "Caesar" }; + + ... + + name[3] = "Dieter"; + \end{lstlisting} + + \begin{picture}(0,0) + \color{red} + \put(0,0){\line(3,1){3.5}} + \put(0,1){\line(3,-1){3.5}} + \end{picture} + +\end{frame} + +\begin{frame}[fragile] + + \showsection + \showsubsection + + \bigskip + + \begin{lstlisting} + #include <stdlib.h> + + ... + + char **name = malloc (3 * sizeof (char *)); + /* Speicherplatz für 3 Zeiger anfordern */ + + ... + + free (name); + /* Speicherplatz freigeben */ + + \end{lstlisting} + +\end{frame} + +\subsection{Konzepte und Ziele} + +\begin{frame} + + \showsection + \showsubsection + + \begin{itemize} + \item +% Array: feste Anzahl von Elementen desselben Typs (z.\,B.\ 3 ganze Zahlen) + Array: Elemente desselben Typs (z.\,B.\ 3 ganze Zahlen) +% \item +% Dynamisches Array: variable Anzahl von Elementen desselben Typs + \item + Problem: Elemente unterschiedlichen Typs + \item + Lösung: den Typ des Elements zusätzlich speichern \textarrow\ \newterm{Objekt} + \item + Problem: Die Elemente sind unterschiedlich groß (Speicherplatz). + \item + Lösung: Im Array nicht die Objekte selbst speichern, sondern Zeiger darauf. + \end{itemize} + \begin{itemize} + \item + Funktionen, die mit dem Objekt arbeiten: \newterm{Methoden} + \begin{onlyenv}<1> + \item + Was die Funktion bewirkt,\\ + hängt vom Typ des Objekts ab + \item + Realisierung über endlose \lstinline{if}-Ketten + \end{onlyenv} + \begin{onlyenv}<2> + \item + Was die Funktion bewirkt + \begin{picture}(0,0) + \color{red} + \put(-4.00,-0.05){\tikz{\draw[thick](0,0.25)--(3.75,-0.05);% + \draw[thick](-0.1,-0.05)--(3.75,0.3);}} + \end{picture}% + Welche Funktion aufgerufen wird,\\ + hängt vom Typ des Objekts ab: \newterm{virtuelle Methode} + \item + Realisierung über endlose \lstinline{if}-Ketten% + \begin{picture}(0,0) + \color{red} + \put(-2.75,-0.05){\tikz{\draw[thick](0,0.25)--(2.5,-0.05);% + \draw[thick](-0.1,-0.05)--(2.5,0.3);}} + \put(1.5,-1.1){\begin{rotate}{7}\large\bf\textarrow\ +% kommt gleich + nächste Woche + \end{rotate}} + \end{picture} + Zeiger, die im Objekt gespeichert sind\\ + (Genaugenommen: Tabelle von Zeigern) + \end{onlyenv} + \end{itemize} + +\end{frame} + +\begin{frame} + + \showsection + \showsubsection + + \begin{itemize} + \item + Problem: Elemente unterschiedlichen Typs + \item + Lösung: den Typ des Elements zusätzlich speichern \textarrow\ \newterm{Objekt} + \item + \newterm{Methoden\/} und \newterm{virtuelle Methoden} + \end{itemize} + + \begin{itemize} + \item + Zeiger auf verschiedene Strukturen\\ + mit einem gemeinsamen Anteil von Datenfeldern\\ + \textarrow\ "`verwandte"' \newterm{Objekte}, \newterm{Klassenhierarchie} von Objekten + \item + Struktur, die \emph{nur\/} den gemeinsamen Anteil enthält\\ + \textarrow\ "`Vorfahr"', \newterm{Basisklasse}, \newterm{Vererbung} + \item +% Explizite Typumwandlung eines Zeigers auf die Basisklasse\\ +% in einen Zeiger auf die \newterm{abgeleitete Klasse}\\ +% \textarrow\ Man kann ein Array unterschiedlicher Objekte\\ +% \strut\phantom{\textarrow} in einer Schleife abarbeiten.\\ + Zeiger auf die Basisklasse dürfen auf Objekte\\ + der \newterm{abgeleiteten Klasse} zeigen\\ + \textarrow\ \newterm{Polymorphie} + \end{itemize} + +\end{frame} + +\subsection{Beispiel: Zahlen und Buchstaben} + +\begin{frame}[fragile] + + \showsection + \showsubsection + + \begin{center} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + } t_base;¿ + \end{lstlisting} + \end{minipage}\\[0.5cm] + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + int content; + } t_integer;¿ + \end{lstlisting} + \end{minipage} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + char *content; + } t_string;¿ + \end{lstlisting} + \end{minipage} + \end{center} + +\end{frame} + +\begin{frame}[fragile] + \begin{center} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + } t_base;¿ + \end{lstlisting} + \end{minipage}\\[0.5cm] + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + int content; + } t_integer;¿ + \end{lstlisting} + \end{minipage} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + char *content; + } t_string;¿ + \end{lstlisting} + \end{minipage}\\[0.7cm] + \begin{onlyenv}<1> + \begin{minipage}{8cm} + \begin{lstlisting}[gobble=10] + ¡t_integer i = { 1, 42 }; + t_string s = { 2, "Hello, world!" }; + + t_base *object[] = { (t_base *) &i, (t_base *) &s };¿ + \end{lstlisting} + \end{minipage}% + \begin{picture}(0,0) + \color{red} + \put(-5.4,-0.8){\mbox{$\underbrace{\rule{1.45cm}{0pt}}_{\shortstack{\strut explizite\\Typumwandlung}}$}} + \end{picture} + \end{onlyenv} +% \begin{onlyenv}<2> +% \begin{minipage}{5cm} +% \begin{lstlisting}[gobble=10] +% ¡typedef union +% { +% t_base base; +% t_integer integer; +% t_string string; +% } t_object;¿ +% \end{lstlisting} +% \end{minipage} +% \end{onlyenv} + \end{center} + +\end{frame} + +\iffalse + +\subsection{Unions} + +\begin{frame}[fragile] + + \showsubsection + + Variable teilen sich denselben Speicherplatz. + + \medskip + + \begin{minipage}[t]{3.7cm} + \begin{lstlisting}[gobble=6] + ¡typedef union + { + int8_t i; + uint8_t u; + } num8_t;¿ + \end{lstlisting} + \end{minipage}% + \begin{minipage}[t]{4.5cm} + \begin{lstlisting}[gobble=6] + ¡int main (void) + { + num8_t test; + test.i = -1; + printf ("%d\n", test.u); + return 0; + }¿ + \end{lstlisting} + \end{minipage} + +\end{frame} + +\begin{frame}[fragile] + + \showsubsection + + Variable teilen sich denselben Speicherplatz. + + \medskip + + \begin{minipage}[t]{3.7cm} + \begin{lstlisting}[gobble=6] + ¡typedef union + { + char s[8]; + uint64_t x; + } num_char_t;¿ + \end{lstlisting} + \end{minipage}% + \begin{minipage}[t]{4.5cm} + \begin{lstlisting}[gobble=6] + ¡int main (void) + { + num_char_t test = { "Hello!" }; + printf ("%lx\n", test.x); + return 0; + }¿ + \end{lstlisting} + \end{minipage} + +\end{frame} + +\begin{frame}[fragile] + + \showsubsection + + Variable teilen sich denselben Speicherplatz. + + \medskip + + \begin{minipage}[t]{3.7cm} + \begin{lstlisting}[gobble=6] + ¡typedef union + { + t_base base; + t_integer integer; + t_string string; + } t_object;¿ + \end{lstlisting} + \end{minipage}% + \begin{minipage}[t]{3.0cm} + \begin{lstlisting}[gobble=6] + + ¡typedef struct + { + int type; + } t_base;¿ + \end{lstlisting} + \end{minipage}% + \begin{minipage}[t]{3.0cm} + \begin{lstlisting}[gobble=6] + + ¡typedef struct + { + int type; + int content; + } t_integer;¿ + \end{lstlisting} + \end{minipage}% + \begin{minipage}[t]{3.0cm} + \begin{lstlisting}[gobble=6] + + ¡typedef struct + { + int type; + char *content; + } t_string;¿ + \end{lstlisting} + \end{minipage} + + \bigskip + + \begin{center} + \begin{minipage}{8.5cm} + \begin{lstlisting}[gobble=8] + ¡if (this->base.type == T_INTEGER) + printf ("Integer: %d\n", this->integer.content); + else if (this->base.type == T_STRING) + printf ("String: \"%s\"\n", this->string.content);¿ + \end{lstlisting} + \end{minipage} + \end{center} + +\end{frame} + +\subsection{Virtuelle Methoden} + +\begin{frame}[fragile] + \showsubsection + + \begin{lstlisting} + void print_object (t_object *this) + { + if (this->base.type == T_INTEGER) + printf ("Integer: %d\n", this->integer.content); + else if (this->base.type == T_STRING) + printf ("String: \"%s\"\n", this->string.content); + } + \end{lstlisting} + + \begin{picture}(0,0) + \color{red} + \put(9,1.7){\shortstack[l]{if-Kette:\\\strut wird unübersichtlich}} + \put(1,-2){\mbox{\textarrow}} + \put(0,-3){\mbox{Zeiger auf Funktionen}} + \end{picture} + + \begin{lstlisting}[xleftmargin=4cm] + void print_integer (t_object *this) + { + printf ("Integer: %d\n", this->integer.content); + } + + void print_string (t_object *this) + { + printf ("String: \"%s\"\n", this->string.content); + } + \end{lstlisting} + +\end{frame} + +\begin{frame}[fragile] + \showsubsection + + Zeiger auf Funktionen + + \medskip + + \begin{lstlisting} + void (* print) (t_object *this); + \end{lstlisting} + \begin{picture}(0,1.2)(0,-0.9) + \color{red} + \put(0.95,0.3){\mbox{$\underbrace{\rule{1cm}{0pt}}$}} + \put(0.2,-0.7){\shortstack{das, worauf print zeigt,\\ist eine Funktion}} + \end{picture} + + \begin{itemize} + \item + Objekt enthält Zeiger auf Funktion + \begin{onlyenv}<1> + \medskip + \begin{lstlisting}[gobble=10] + typedef struct + { + void (* print) (union t_object *this); + int content; + } t_integer; + \end{lstlisting} + \end{onlyenv} + \begin{onlyenv}<2-> + \vspace*{-3.5cm} % Why doesn't a picture environment work here??? :-( + \begin{lstlisting}[gobble=10,xleftmargin=5.5cm] + typedef struct + { + void (* print) (union t_object *this); + int content; + } t_integer; + \end{lstlisting} + \vspace*{0.85cm} + \bigskip + \smallskip + \end{onlyenv} + \pause + \item + Konstruktor initialisiert diesen Zeiger + \begin{onlyenv}<2> + \medskip + \begin{lstlisting}[gobble=10] + t_object *new_integer (int i) + { + t_object *p = malloc (sizeof (t_integer)); + p->integer.print = print_integer; + p->integer.content = i; + return p; + } + \end{lstlisting} + \vspace*{-2cm} + \end{onlyenv} + \pause + \item + Aufruf: "`automatisch"' die richtige Funktion + \begin{onlyenv}<3> + \medskip + \begin{lstlisting}[gobble=10] + for (int i = 0; object[i]; i++) + object[i]->base.print (object[i]); + \end{lstlisting} + \end{onlyenv} + \pause + \medskip + \item + in größeren Projekten:\\ + Objekt enthält Zeiger auf Tabelle von Funktionen + \end{itemize} +\end{frame} + +\subsection{Beispiel: Graphische Benutzeroberfläche (GUI)} + +\begin{frame}[fragile] + + \showsubsection + + \scriptsize + \begin{lstlisting} + #include <gtk/gtk.h> + + int main (int argc, char **argv) + { + gtk_init (&argc, &argv); + GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "Hello"); + g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); + GtkWidget *vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 10); + GtkWidget *label = gtk_label_new ("Hello, world!"); + gtk_container_add (GTK_CONTAINER (vbox), label); + GtkWidget *button = gtk_button_new_with_label ("Quit"); + g_signal_connect (button, "clicked", G_CALLBACK (gtk_main_quit), NULL); + gtk_container_add (GTK_CONTAINER (vbox), button); + gtk_widget_show (button); + gtk_widget_show (label); + gtk_widget_show (vbox); + gtk_widget_show (window); + gtk_main (); + return 0; + } + \end{lstlisting} + + \vspace*{-6cm}\strut\hfill + \includegraphics[scale=0.85]{hello-gtk.png}\\[2cm] + \begin{flushright} + \normalsize\bf Praktikumsversuch:\\ + Objektorientiertes Zeichenprogramm + \end{flushright} + +\end{frame} + +\subsection{Ausblick: C++} + +\begin{frame}[fragile] + \showsubsection + + \begin{center} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + void (* print) (union t_object *this); + } t_base;¿ + \end{lstlisting} + \end{minipage}\\[0.5cm] + \begin{minipage}{5.5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + void (* print) (...); + int content; + } t_integer;¿ + \end{lstlisting} + \end{minipage} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + void (* print) (union t_object *this); + char *content; + } t_string;¿ + \end{lstlisting} + \end{minipage} + \end{center} + +\end{frame} + +\begin{frame}[fragile] + \showsubsection + + \begin{center} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡struct TBase + { + virtual void print (void); + };¿ + \end{lstlisting} + \end{minipage}\\[0.5cm] + \begin{minipage}{5.5cm} + \begin{lstlisting}[gobble=8] + ¡struct TInteger: public TBase + { + virtual void print (void); + int content; + };¿ + \end{lstlisting} + \end{minipage} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡struct TString: public TBase + { + virtual void print (void); + char *content; + };¿ + \end{lstlisting} + \end{minipage} + \end{center} + +\end{frame} + +\fi + +\end{document} diff --git a/20231214/hp-musterloesung-20231214.pdf b/20231214/hp-musterloesung-20231214.pdf new file mode 100644 index 0000000000000000000000000000000000000000..300f360709ed082ffd0fb1709acbaf32ed04237b Binary files /dev/null and b/20231214/hp-musterloesung-20231214.pdf differ diff --git a/20231214/hp-musterloesung-20231214.tex b/20231214/hp-musterloesung-20231214.tex new file mode 100644 index 0000000000000000000000000000000000000000..c704b037e61cc21aefc8a4f22bd81f4d36ce7d16 --- /dev/null +++ b/20231214/hp-musterloesung-20231214.tex @@ -0,0 +1,538 @@ +% hp-musterloesung-20231214.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences +% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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: Länge von Strings, Einfügen in Strings (Ergänzung) + +\documentclass[a4paper]{article} + +\usepackage{pgscript} +\usepackage{gnuplot-lua-tikz} + +\begin{document} + + \section*{Hardwarenahe Programmierung\\ + Musterlösung zu den Übungsaufgaben -- 14.\ Dezember 2023} + + \exercise{Dynamisches Bit-Array} + + Schreiben Sie die folgenden Funktionen zur Verwaltung eines dynamischen Bit-Arrays: + \begin{itemize} + \item + \lstinline{void bit_array_init (int n)}\\ + Das Array initialisieren, so daß man \lstinline{n} Bits darin speichern kann.\\ + Die Array-Größe \lstinline{n} ist keine Konstante, sondern erst im laufenden Programm bekannt.\\ + Die Bits sollen auf den Anfangswert 0 initialisiert werden. + \item + \lstinline{void bit_array_set (int i, int value)}\\ + Das Bit mit dem Index \lstinline{i} auf den Wert \lstinline{value} setzen.\\ + Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen; + der Wert \lstinline{value} darf 1 oder 0 sein. + \item + \lstinline{void bit_array_flip (int i)}\\ + Das Bit mit dem Index \lstinline{i} auf den entgegengesetzten Wert setzen,\\ + also auf 1, wenn er vorher 0 ist, bzw.\ auf 0, wenn er vorher 1 ist.\\ + Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen. + \item + \lstinline{int bit_array_get (int i)}\\ + Den Wert des Bit mit dem Index \lstinline{i} zurückliefern.\\ + Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen. + \item + \lstinline{void bit_array_resize (int new_n)}\\ + Die Größe des Arrays auf \lstinline{new_n} Bits ändern.\\ + Dabei soll der Inhalt des Arrays, soweit er in die neue Größe paßt, erhalten bleiben.\\ + Neu hinzukommende Bits sollen auf 0 initialisiert werden. + \item + \lstinline{void bit_array_done (void)}\\ + Den vom Array belegten Speicherplatz wieder freigeben. + \end{itemize} + Bei Bedarf dürfen Sie den Funktionen zusätzliche Parameter mitgeben, + beispielsweise um mehrere Arrays parallel verwalten zu können. + (In der objektorientierten Programmierung wäre dies der implizite Parameter \lstinline{this}, + der auf die Objekt-Struktur zeigt.) + + Die Bits sollen möglichst effizient gespeichert werden, + z.\,B.\ jeweils 8 Bits in einer \lstinline{uint8_t}-Variablen. + + Die Funktionen sollen möglichst robust sein, + d.\,h.\ das Programm darf auch bei unsinnigen Parameterwerten nicht abstürzen, + sondern soll eine Fehlermeldung ausgeben. + + \medskip + + Die folgenden \textbf{Hinweise} beschreiben + einen möglichen Weg, die Aufgabe zu lösen. + Es seht Ihnen frei, die Aufgabe auch auf andere Weise zu lösen. + \begin{itemize} + \item + Setzen Sie zunächst voraus, daß das Array die konstante Länge 8 hat, + und schreiben Sie zunächst nur die Funktionen + \lstinline{bit_array_set()}, \lstinline{bit_array_flip()} und + \lstinline{bit_array_get()}. + \item + Verallgemeinern Sie nun auf eine konstante Länge, + bei der es sich um ein Vielfaches von 8 handelt. + \item + Implementieren Sie nun die Überprüfung auf unsinnige Parameterwerte. + Damit können Sie sich gleichzeitig von der Bedingung lösen, + daß die Länge des Arrays ein Vielfaches von 8 sein muß. + \item + Gehen Sie nun von einem statischen zu einem dynamischen Array über, + und implementieren sie die Funktionen \lstinline{bit_array_init()}, + \lstinline{bit_array_done()} und \lstinline{bit_array_resize()}. + \end{itemize} + +% \points{14} +% +% \medskip +% +% (Hinweis für die Klausur: +% Abgabe in digitaler Form ist erwünscht, aber nicht zwingend.) + + \clearpage + + \solution + + Die hier vorgestellte Lösung folgt den Hinweisen. + \begin{itemize} + \item + \textbf{Setzen Sie zunächst voraus, daß das Array die konstante Länge 8 hat, + und schreiben Sie zunächst nur die Funktionen + \lstinline{bit_array_set()}, \lstinline{bit_array_flip()} und + \lstinline{bit_array_get()}.} + + Siehe: \gitfile{hp}{2023ws/20231214}{loesung-1-1.c} + + Wir speichern in jedem der acht Bit einer \lstinline{uint8_t}-Variablen + jeweils eine Zahl, die 0 oder 1 sein kann. + Dies geschieht durch Setzen bzw.\ Löschen bzw.\ Umklappen einzelner Bits + in der Variablen. + + Das Programm enthält zusätzlich eine Funktion \lstinline{output()}, + mit der man sich den Inhalt des Arrays anzeigen lassen kann, + sowie ein Hauptprogramm \lstinline{main()}, um die Funktionen zu testen. + + \item + \textbf{Verallgemeinern Sie nun auf eine konstante Länge, + bei der es sich um ein Vielfaches von 8 handelt.} + + Siehe: \gitfile{hp}{2023ws/20231214}{loesung-1-2.c} + + In diesem Programm setzen wir die Länge auf konstant \lstinline{LENGTH} Bits, + wobei es sich um eine Präprozessor-Konstante mit dem Wert 32 handelt. + + Um \lstinline{LENGTH} Bits zu speichern, benötigen wir ein Array + der Länge \lstinline{LENGTH / 8} Bytes. + + Um auf ein einzelnes Bit zuzugreifen, müssen wir zunächst ermitteln, + in welchem der Bytes sich befindet. Außerdem interessieren wir uns + für die Nummer des Bits innerhalb des Bytes. + Den Array-Index des Bytes erhalten wir, indem wir den Index des Bits + durch 8 dividieren. Der bei dieser Division verbleibende Rest ist die + Nummer des Bits innerhalb des Bytes. + + Diese Rechnungen führen wir in den drei Funktionen + \lstinline{bit_array_set()}, \lstinline{bit_array_flip()} und + \lstinline{bit_array_get()} durch. + (Diese ist eine eher unelegante Code-Verdopplung -- hier sogar eine Verdreifachung. + Für den Produktiveinsatz lohnt es sich, darüber nachzudenken, + wie man diese vermeiden kann, ohne gleichzeitig an Effizienz einzubüßen. + Hierfür käme z.\,B.\ ein Präprozessor-Makro in Frage. + Für die Lösung der Übungsaufgabe wird dies hingegen nicht verlangt.) + + \item + \textbf{Implementieren Sie nun die Überprüfung auf unsinnige Parameterwerte. + Damit können Sie sich gleichzeitig von der Bedingung lösen, + daß die Länge des Arrays ein Vielfaches von 8 sein muß.} + + Siehe: \gitfile{hp}{2023ws/20231214}{loesung-1-3.c} + + Um weitere Code-Verdopplungen zu vermeiden, + führen wir eine Funktion \lstinline{check_index()} ein, + die alle Prüfungen durchführt. + + Wenn die Länge des Arrays kein Vielfaches von 8 ist, + wird das letzte Byte nicht vollständig genutzt. + Die einzige Schwierigkeit besteht darin, die korrekte Anzahl von Bytes + zu ermitteln, nämlich die Länge dividiert durch 8, aber nicht ab-, sondern + aufgerundet. Am elegantesten geht dies durch vorherige Addition von 7: + \lstinline{#define BYTES ((LENGTH + 7) / 8)}. + Es ist aber auch zulässig, die Anzahl der Bytes mit Hilfe einer + \lstinline{if}-Anweisung zu ermitteln: Länge durch 8 teilen und abrunden; + falls die Division nicht glatt aufging, um 1 erhöhen. + + \item + \textbf{Gehen Sie nun von einem statischen zu einem dynamischen Array über, + und implementieren sie die Funktionen \lstinline{bit_array_init()}, + \lstinline{bit_array_done()} und \lstinline{bit_array_resize()}.} + + Siehe: \gitfile{hp}{2023ws/20231214}{loesung-1-4.c}. + Damit ist die Aufgabe gelöst. + + Aus den Präprozessor-Konstanten \lstinline{LENGTH} und \lstinline{BYTES} + werden nun globale \lstinline{int}-Variable. + Die Funktion \lstinline{bit_array_init()} berechnet die korrekten Werte + für diese Variablen und legt das Array mittels \lstinline{malloc()} dynamisch + an. Eine Größenänderung des Arrays erfolgt mittels \lstinline{realloc()}, + das Freigeben mittels \lstinline{free()}. + + Das Programm setzt Variable, die aktuell nicht verwendet werden, + auf den Wert \lstinline{0} bzw.\ \lstinline{NULL}. + Dies ermöglicht es der Funktion \lstinline{check_index()}, + auch zu prüfen, ob das Array vorher korrekt mit \lstinline{bit_array_init()} + erzeugt wurde -- oder ob es vielleicht schon wieder mit + \lstinline{bit_array_done()} freigegeben wurde. + + \end{itemize} + + \clearpage + + \exercise{Objektorientierte Tier-Datenbank} + + Das unten dargestellte Programm (Datei: \gitfile{hp}{2023ws/20231214}{aufgabe-3a.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 in Rot dargestellten Ersetzungen vor\\ + (Datei: \gitfile{hp}{2023ws/20231214}{aufgabe-3b.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}{2023ws/20231214}{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}{2023ws/20231214}{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}{2023ws/20231214}{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}{2023ws/20231214}{loesung-2e.c}. + + Diese Lösung basiert auf \gitfile{hp}{2023ws/20231214}{loesung-2d-2.c}, + da diese bereits weniger explizite Typumwandlungen enthält + als \gitfile{hp}{2023ws/20231214}{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}{2023ws/20231214}{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}{2023ws/20231214}{loesung-2g.c}. + + \end{itemize} + +\end{document} diff --git a/20231214/hp-uebung-20231214.pdf b/20231214/hp-uebung-20231214.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1d3c327e01e726f080d97393780326be8dfe5505 Binary files /dev/null and b/20231214/hp-uebung-20231214.pdf differ diff --git a/20231214/hp-uebung-20231214.tex b/20231214/hp-uebung-20231214.tex new file mode 100644 index 0000000000000000000000000000000000000000..406fb68367ba09e7b9b0d772ecc5f90e051f95cc --- /dev/null +++ b/20231214/hp-uebung-20231214.tex @@ -0,0 +1,253 @@ +% hp-uebung-20231214.pdf - Exercises on Low-Level Programming / Applied Computer Sciences +% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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: dynamisches Bit-Array, objektorientierte Tier-Datenbank + +\documentclass[a4paper]{article} + +\usepackage{pgscript} +\usepackage{gensymb} + +\newcommand{\ItwoC}{I\raisebox{0.5ex}{\footnotesize 2}C} +\newcommand{\ITWOC}{I\raisebox{0.5ex}{\normalsize 2}C} + +\begin{document} + + \thispagestyle{empty} + + \section*{Hardwarenahe Programmierung\\ + Übungsaufgaben -- 14.\ Dezember 2023} + + Diese Übung enthält Punkteangaben wie in einer Klausur. + Um zu "`bestehen"', müssen Sie innerhalb von 80 Minuten + unter Verwendung ausschließlich zugelassener Hilfsmittel + 14 Punkte (von insgesamt \totalpoints) erreichen. + + \exercise{Dynamisches Bit-Array} + + Schreiben Sie die folgenden Funktionen zur Verwaltung eines dynamischen Bit-Arrays: + \begin{itemize} + \item + \lstinline{void bit_array_init (int n)}\\ + Das Array initialisieren, so daß man \lstinline{n} Bits darin speichern kann.\\ + Die Array-Größe \lstinline{n} ist keine Konstante, sondern erst im laufenden Programm bekannt.\\ + Die Bits sollen auf den Anfangswert 0 initialisiert werden. + \item + \lstinline{void bit_array_set (int i, int value)}\\ + Das Bit mit dem Index \lstinline{i} auf den Wert \lstinline{value} setzen.\\ + Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen; + der Wert \lstinline{value} darf 1 oder 0 sein. + \item + \lstinline{void bit_array_flip (int i)}\\ + Das Bit mit dem Index \lstinline{i} auf den entgegengesetzten Wert setzen,\\ + also auf 1, wenn er vorher 0 ist, bzw.\ auf 0, wenn er vorher 1 ist.\\ + Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen. + \item + \lstinline{int bit_array_get (int i)}\\ + Den Wert des Bit mit dem Index \lstinline{i} zurückliefern.\\ + Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen. + \item + \lstinline{void bit_array_resize (int new_n)}\\ + Die Größe des Arrays auf \lstinline{new_n} Bits ändern.\\ + Dabei soll der Inhalt des Arrays, soweit er in die neue Größe paßt, erhalten bleiben.\\ + Neu hinzukommende Bits sollen auf 0 initialisiert werden. + \item + \lstinline{void bit_array_done (void)}\\ + Den vom Array belegten Speicherplatz wieder freigeben. + \end{itemize} + Bei Bedarf dürfen Sie den Funktionen zusätzliche Parameter mitgeben, + beispielsweise um mehrere Arrays parallel verwalten zu können. + (In der objektorientierten Programmierung wäre dies der implizite Parameter \lstinline{this}, + der auf die Objekt-Struktur zeigt.) + + Die Bits sollen möglichst effizient gespeichert werden, + z.\,B.\ jeweils 8 Bits in einer \lstinline{uint8_t}-Variablen. + + Die Funktionen sollen möglichst robust sein, + d.\,h.\ das Programm darf auch bei unsinnigen Parameterwerten nicht abstürzen, + sondern soll eine Fehlermeldung ausgeben. + + \medskip + + Die folgenden \textbf{Hinweise} beschreiben + einen möglichen Weg, die Aufgabe zu lösen. + Es seht Ihnen frei, die Aufgabe auch auf andere Weise zu lösen. + \begin{itemize} + \item + Setzen Sie zunächst voraus, daß das Array die konstante Länge 8 hat, + und schreiben Sie zunächst nur die Funktionen + \lstinline{bit_array_set()}, \lstinline{bit_array_flip()} und + \lstinline{bit_array_get()}. + \item + Verallgemeinern Sie nun auf eine konstante Länge, + bei der es sich um ein Vielfaches von 8 handelt. + \item + Implementieren Sie nun die Überprüfung auf unsinnige Parameterwerte. + Damit können Sie sich gleichzeitig von der Bedingung lösen, + daß die Länge des Arrays ein Vielfaches von 8 sein muß. + \item + Gehen Sie nun von einem statischen zu einem dynamischen Array über, + und implementieren Sie die Funktionen \lstinline{bit_array_init()}, + \lstinline{bit_array_done()} und \lstinline{bit_array_resize()}. + \end{itemize} + + \points{14} + + \medskip + + (Hinweis für die Klausur: + Abgabe in digitaler Form ist erwünscht, aber nicht zwingend.) + + \clearpage + \exercise{Objektorientierte Tier-Datenbank} + + Das unten dargestellte Programm (Datei: \gitfile{hp}{2023ws/20231214}{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 in Rot dargestellten Ersetzungen vor + (Datei: \gitfile{hp}{2023ws/20231214}{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} + + \begin{flushright} + \textit{Viel Erfolg!} + \end{flushright} + + \makeatletter + \immediate\write\@mainaux{\string\gdef\string\totalpoints{\arabic{points}}} + \makeatother + +\end{document} diff --git a/20231214/landau-symbols-2.pdf b/20231214/landau-symbols-2.pdf new file mode 120000 index 0000000000000000000000000000000000000000..6b458b6efd8e274824a6dfcaabc4b9c27d196dc4 --- /dev/null +++ b/20231214/landau-symbols-2.pdf @@ -0,0 +1 @@ +../common/landau-symbols-2.pdf \ No newline at end of file diff --git a/20231214/landau-symbols-3.pdf b/20231214/landau-symbols-3.pdf new file mode 120000 index 0000000000000000000000000000000000000000..46efa409b35ff5df763c744a423599cba515d886 --- /dev/null +++ b/20231214/landau-symbols-3.pdf @@ -0,0 +1 @@ +../common/landau-symbols-3.pdf \ No newline at end of file diff --git a/20231214/landau-symbols.pdf b/20231214/landau-symbols.pdf new file mode 120000 index 0000000000000000000000000000000000000000..ca145425bf07439c680632aa0663f84be601a565 --- /dev/null +++ b/20231214/landau-symbols.pdf @@ -0,0 +1 @@ +../common/landau-symbols.pdf \ No newline at end of file diff --git a/20231214/loesung-1-1.c b/20231214/loesung-1-1.c new file mode 100644 index 0000000000000000000000000000000000000000..11ad08a28a2c16e645e4b55c1b0f4556246fd692 --- /dev/null +++ b/20231214/loesung-1-1.c @@ -0,0 +1,50 @@ +#include <stdio.h> +#include <stdint.h> + +uint8_t buffer = 0; + +void bit_array_set (int i, int value) +{ + uint8_t mask = 1 << i; + if (value) + buffer |= mask; + else + buffer &= ~mask; +} + +void bit_array_flip (int i) +{ + uint8_t mask = 1 << i; + buffer ^= mask; +} + +int bit_array_get (int i) +{ + uint8_t mask = 1 << i; + if (buffer & mask) + return 1; + else + return 0; +} + +void output (void) +{ + for (int i = 0; i < 8; i++) + { + if (i % 4 == 0) + printf (" "); + printf ("%d", bit_array_get (i)); + } + printf ("\n"); +} + +int main (void) +{ + output (); + bit_array_set (2, 1); + output (); + bit_array_flip (7); + output (); + bit_array_set (2, 0); + output (); +} diff --git a/20231214/loesung-1-2.c b/20231214/loesung-1-2.c new file mode 100644 index 0000000000000000000000000000000000000000..e510904b033cf7d55737cee55ad08ecb9510f324 --- /dev/null +++ b/20231214/loesung-1-2.c @@ -0,0 +1,58 @@ +#include <stdio.h> +#include <stdint.h> + +#define LENGTH 32 + +uint8_t buffer[LENGTH / 8] = { 0, 0, 0, 0 }; + +void bit_array_set (int i, int value) +{ + int byte_index = i / 8; + int bit_index = i % 8; + uint8_t mask = 1 << bit_index; + if (value) + buffer[byte_index] |= mask; + else + buffer[byte_index] &= ~mask; +} + +void bit_array_flip (int i) +{ + int byte_index = i / 8; + int bit_index = i % 8; + uint8_t mask = 1 << bit_index; + buffer[byte_index] ^= mask; +} + +int bit_array_get (int i) +{ + int byte_index = i / 8; + int bit_index = i % 8; + uint8_t mask = 1 << bit_index; + if (buffer[byte_index] & mask) + return 1; + else + return 0; +} + +void output (void) +{ + for (int i = 0; i < LENGTH; i++) + { + if (i % 4 == 0) + printf (" "); + printf ("%d", bit_array_get (i)); + } + printf ("\n"); +} + +int main (void) +{ + output (); + bit_array_set (12, 1); + output (); + bit_array_flip (31); + output (); + bit_array_set (12, 0); + output (); +} diff --git a/20231214/loesung-1-3.c b/20231214/loesung-1-3.c new file mode 100644 index 0000000000000000000000000000000000000000..4177464aebf41205169a6bb02b27ac972e3a4f4e --- /dev/null +++ b/20231214/loesung-1-3.c @@ -0,0 +1,71 @@ +#include <stdio.h> +#include <stdint.h> +#include <error.h> + +#define LENGTH 29 +#define BYTES ((LENGTH + 7) / 8) + +uint8_t buffer[BYTES] = { 0, 0, 0, 0 }; + +void check_index (int i) +{ + if (i < 0 || i >= LENGTH) + error (1, 0, "index %d out of range (0, ..., %d)", i, LENGTH - 1); +} + +void bit_array_set (int i, int value) +{ + check_index (i); + int byte_index = i / 8; + int bit_index = i % 8; + uint8_t mask = 1 << bit_index; + if (value) + buffer[byte_index] |= mask; + else + buffer[byte_index] &= ~mask; +} + +void bit_array_flip (int i) +{ + check_index (i); + int byte_index = i / 8; + int bit_index = i % 8; + uint8_t mask = 1 << bit_index; + buffer[byte_index] ^= mask; +} + +int bit_array_get (int i) +{ + check_index (i); + int byte_index = i / 8; + int bit_index = i % 8; + uint8_t mask = 1 << bit_index; + if (buffer[byte_index] & mask) + return 1; + else + return 0; +} + +void output (void) +{ + for (int i = 0; i < LENGTH; i++) + { + if (i % 4 == 0) + printf (" "); + printf ("%d", bit_array_get (i)); + } + printf ("\n"); +} + +int main (void) +{ + output (); + bit_array_set (12, 1); + output (); + bit_array_flip (28); + output (); + bit_array_set (12, 0); + output (); + bit_array_flip (31); + output (); +} diff --git a/20231214/loesung-1-4.c b/20231214/loesung-1-4.c new file mode 100644 index 0000000000000000000000000000000000000000..1930580aae8e8b24528852d1dacf58051f6bd6cc --- /dev/null +++ b/20231214/loesung-1-4.c @@ -0,0 +1,101 @@ +#include <stdio.h> +#include <stdint.h> +#include <error.h> +#include <stdlib.h> + +int length = 0; +int bytes = 0; +uint8_t *buffer = NULL; + +void bit_array_init (int n) +{ + length = n; + bytes = (length + 7) / 8; + if (buffer) + free (buffer); + buffer = malloc (bytes * sizeof (uint8_t)); + for (int i = 0; i < bytes; i++) + buffer[i] = 0; +} + +void bit_array_resize (int new_n) +{ + length = new_n; + bytes = (length + 7) / 8; + buffer = realloc (buffer, bytes * sizeof (uint8_t)); +} + +void bit_array_done (void) +{ + free (buffer); + buffer = NULL; + length = 0; + bytes = 0; +} + +void check_index (int i) +{ + if (!buffer) + error (1, 0, "array not initialised"); + if (i < 0 || i >= length) + error (1, 0, "index %d out of range (0, ..., %d)", i, length - 1); +} + +void bit_array_set (int i, int value) +{ + check_index (i); + int byte_index = i / 8; + int bit_index = i % 8; + uint8_t mask = 1 << bit_index; + if (value) + buffer[byte_index] |= mask; + else + buffer[byte_index] &= ~mask; +} + +void bit_array_flip (int i) +{ + check_index (i); + int byte_index = i / 8; + int bit_index = i % 8; + uint8_t mask = 1 << bit_index; + buffer[byte_index] ^= mask; +} + +int bit_array_get (int i) +{ + check_index (i); + int byte_index = i / 8; + int bit_index = i % 8; + uint8_t mask = 1 << bit_index; + if (buffer[byte_index] & mask) + return 1; + else + return 0; +} + +void output (void) +{ + for (int i = 0; i < length; i++) + { + if (i % 4 == 0) + printf (" "); + printf ("%d", bit_array_get (i)); + } + printf ("\n"); +} + +int main (void) +{ + bit_array_init (29); + output (); + bit_array_set (12, 1); + output (); + bit_array_flip (28); + output (); + bit_array_set (12, 0); + output (); + bit_array_flip (31); + output (); + bit_array_done (); +} diff --git a/20231214/loesung-2d-0f.c b/20231214/loesung-2d-0f.c new file mode 100644 index 0000000000000000000000000000000000000000..04b2d3e8956f4790b3f2ffdf3a314994c640513e --- /dev/null +++ b/20231214/loesung-2d-0f.c @@ -0,0 +1,54 @@ +#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; +} diff --git a/20231214/loesung-2d-1.c b/20231214/loesung-2d-1.c new file mode 100644 index 0000000000000000000000000000000000000000..349523a7d99e33ba81094ffbc8907773b5a3a251 --- /dev/null +++ b/20231214/loesung-2d-1.c @@ -0,0 +1,54 @@ +#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; +} diff --git a/20231214/loesung-2d-2.c b/20231214/loesung-2d-2.c new file mode 100644 index 0000000000000000000000000000000000000000..f831a75eda1f3e784c8e6c1f24a83d9d6b55ee6c --- /dev/null +++ b/20231214/loesung-2d-2.c @@ -0,0 +1,54 @@ +#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; +} diff --git a/20231214/loesung-2e.c b/20231214/loesung-2e.c new file mode 100644 index 0000000000000000000000000000000000000000..b984d9253b9c379a88f0fc0ca130c88c3103f8f3 --- /dev/null +++ b/20231214/loesung-2e.c @@ -0,0 +1,61 @@ +#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; +} diff --git a/20231214/loesung-2f.c b/20231214/loesung-2f.c new file mode 100644 index 0000000000000000000000000000000000000000..7b949e6365fc3839e6adc7661e0f8b4dd0c059df --- /dev/null +++ b/20231214/loesung-2f.c @@ -0,0 +1,69 @@ +#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; +} diff --git a/20231214/loesung-2g.c b/20231214/loesung-2g.c new file mode 100644 index 0000000000000000000000000000000000000000..b453a52dbe0ef27399255819808b3f6e562ba3ef --- /dev/null +++ b/20231214/loesung-2g.c @@ -0,0 +1,77 @@ +#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; +} diff --git a/20231214/logo-hochschule-bochum-cvh-text-v2.pdf b/20231214/logo-hochschule-bochum-cvh-text-v2.pdf new file mode 120000 index 0000000000000000000000000000000000000000..4aa99b8f81061aca6dcaf43eed2d9efef40555f8 --- /dev/null +++ b/20231214/logo-hochschule-bochum-cvh-text-v2.pdf @@ -0,0 +1 @@ +../common/logo-hochschule-bochum-cvh-text-v2.pdf \ No newline at end of file diff --git a/20231214/logo-hochschule-bochum.pdf b/20231214/logo-hochschule-bochum.pdf new file mode 120000 index 0000000000000000000000000000000000000000..b6b9491e370e499c9276918182cdb82cb311bcd1 --- /dev/null +++ b/20231214/logo-hochschule-bochum.pdf @@ -0,0 +1 @@ +../common/logo-hochschule-bochum.pdf \ No newline at end of file diff --git a/20231214/pgscript.sty b/20231214/pgscript.sty new file mode 120000 index 0000000000000000000000000000000000000000..95c888478c99ea7fda0fd11ccf669ae91be7178b --- /dev/null +++ b/20231214/pgscript.sty @@ -0,0 +1 @@ +../common/pgscript.sty \ No newline at end of file diff --git a/20231214/pgslides.sty b/20231214/pgslides.sty new file mode 120000 index 0000000000000000000000000000000000000000..5be1416f4216f076aa268901f52a15d775e43f64 --- /dev/null +++ b/20231214/pgslides.sty @@ -0,0 +1 @@ +../common/pgslides.sty \ No newline at end of file