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

Übungsaufgaben, Musterlösungen, Beispiele und "Screenshots" 21.11.2022

parent 47023e88
No related branches found
No related tags found
No related merge requests found
Showing
with 1522 additions and 0 deletions
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, int left, int right)
{
int result = strcmp (name[left], name[right]);
comparisons++;
display (name, left, right);
usleep (200000);
return result;
}
void sort (char **name)
{
for (int i = 1; name[i]; i++)
if (compare (name, i - 1, i) > 0)
{
char *temp = name[i - 1];
name[i - 1] = name[i];
name[i] = temp;
}
}
int main (void)
{
char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
"Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
"Thomas", "Ulrich", "Zacharias", NULL };
sort (name);
display (name, -1, -1);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, int left, int right)
{
int result = strcmp (name[left], name[right]);
comparisons++;
display (name, left, right);
usleep (200000);
return result;
}
void sort (char **name)
{
for (int i = 1; name[i]; i++)
if (compare (name, i - 1, i) > 0)
{
char *temp = name[i - 1];
name[i - 1] = name[i];
name[i] = temp;
}
}
int main (void)
{
char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
"Dieter", "Hugo", "Zacharias", "Berta", "Maria", "Fritz", "Box", "Hans",
"Thomas", "Ulrich", NULL };
sort (name);
display (name, -1, -1);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, int left, int right)
{
int result = strcmp (name[left], name[right]);
comparisons++;
display (name, left, right);
usleep (200000);
return result;
}
void sort (char **name)
{
int sorted = 0;
while (name[sorted])
sorted++;
while (sorted > 0)
{
for (int i = 1; i < sorted; i++)
if (compare (name, i - 1, i) > 0)
{
char *temp = name[i - 1];
name[i - 1] = name[i];
name[i] = temp;
}
sorted--;
}
}
int main (void)
{
char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
"Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
"Thomas", "Ulrich", "Zacharias", NULL };
sort (name);
display (name, -1, -1);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, int left, int right)
{
int result = strcmp (name[left], name[right]);
comparisons++;
display (name, left, right);
usleep (200000);
return result;
}
void sort (char **name)
{
int done = 0;
int sorted = 0;
while (name[sorted])
sorted++;
while (sorted > 0 && !done)
{
done = 1;
for (int i = 1; i < sorted; i++)
if (compare (name, i - 1, i) > 0)
{
done = 0;
char *temp = name[i - 1];
name[i - 1] = name[i];
name[i] = temp;
}
sorted--;
}
}
int main (void)
{
char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
"Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
"Thomas", "Ulrich", "Zacharias", NULL };
sort (name);
display (name, -1, -1);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, int left, int right)
{
int result = strcmp (name[left], name[right]);
comparisons++;
display (name, left, right);
usleep (200000);
return result;
}
void sort (char **name)
{
int sorted = 0;
while (name[sorted])
sorted++;
while (sorted > 0)
{
int new_sorted = 0;
for (int i = 1; i < sorted; i++)
if (compare (name, i - 1, i) > 0)
{
new_sorted = i;
char *temp = name[i - 1];
name[i - 1] = name[i];
name[i] = temp;
}
sorted = new_sorted;
}
}
int main (void)
{
char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
"Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
"Thomas", "Ulrich", "Zacharias", NULL };
sort (name);
display (name, -1, -1);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, int left, int right)
{
int result = strcmp (name[left], name[right]);
comparisons++;
display (name, left, right);
usleep (200000);
return result;
}
void sort (char **name)
{
int sorted = 0;
while (name[sorted])
sorted++;
while (sorted > 0)
{
int new_sorted = 0;
for (int i = 1; i < sorted; i++)
if (compare (name, i - 1, i) > 0)
{
new_sorted = i;
char *temp = name[i - 1];
name[i - 1] = name[i];
name[i] = temp;
}
sorted = new_sorted;
}
}
int main (void)
{
char *name[] = { "Zacharias", "Ulrich", "Thomas", "Siegfried", "Peter", "Otto", "Maria",
"Lisa", "Hugo", "Heinrich", "Hans", "Fritz", "Dieter", "Box", "Berta",
"Anna", NULL };
sort (name);
display (name, -1, -1);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, int left, int right)
{
int result = strcmp (name[left], name[right]);
comparisons++;
display (name, left, right);
usleep (200000);
return result;
}
void sort (char **name)
{
int sorted = 0;
while (name[sorted])
sorted++;
while (sorted > 0)
{
int new_sorted = 0;
for (int i = 1; i < sorted; i++)
if (compare (name, i - 1, i) > 0)
{
new_sorted = i;
char *temp = name[i - 1];
name[i - 1] = name[i];
name[i] = temp;
}
sorted = new_sorted;
}
}
int main (void)
{
char *name[] = { "Anna", "Berta", "Box", "Dieter", "Fritz", "Hans", "Heinrich", "Hugo",
"Lisa", "Maria", "Otto", "Peter", "Siegfried", "Thomas", "Ulrich",
"Zacharias", NULL };
sort (name);
display (name, -1, -1);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, int left, int right)
{
int result = strcmp (name[left], name[right]);
comparisons++;
// display (name, left, right);
// usleep (200000);
return result;
}
void sort (char **name)
{
int sorted = 0;
while (name[sorted])
sorted++;
while (sorted > 0)
{
int new_sorted = 0;
for (int i = 1; i < sorted; i++)
if (compare (name, i - 1, i) > 0)
{
new_sorted = i;
char *temp = name[i - 1];
name[i - 1] = name[i];
name[i] = temp;
}
sorted = new_sorted;
}
}
int main (void)
{
char *name[] = {
#include "names.h"
NULL
};
sort (name);
display (name, -1, -1);
return 0;
}
File added
% hp-musterloesung-20221121.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 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: Kondensator, Personen-Datenbank, Fakultät
\documentclass[a4paper]{article}
\usepackage{pgscript}
\usepackage{gnuplot-lua-tikz}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- 21.\ November 2022}
\exercise{Kondensator}
Ein Kondensator der Kapazität $C = 100\,\mu{\rm F}$
ist auf die Spannung $U_0 = 5\,{\rm V}$ aufgeladen
und wird über einen Widerstand $R = 33\,{\rm k}\Omega$ entladen.
\begin{enumerate}[(a)]
\item
Schreiben Sie ein C-Programm, das
den zeitlichen Spannungsverlauf in einer Tabelle darstellt.
\points{5}
\item
Schreiben Sie ein C-Programm, das ermittelt,
wie lange es dauert, bis die Spannung unter $0.1\,{\rm V}$ gefallen ist.
\points{4}
\item
Vergleichen Sie die berechneten Werte mit der exakten theoretischen Entladekurve:
\begin{math}
U(t) = U_0 \cdot e^{-\frac{t}{RC}}
\end{math}\\
\points{3}
\end{enumerate}
Hinweise:
\begin{itemize}
\item
Für die Simulation zerlegen wir den Entladevorgang in kurze Zeitintervalle $dt$.
Innerhalb jedes Zeitintervalls betrachten wir den Strom $I$ als konstant
und berechnen, wieviel Ladung $Q$ innerhalb des Zeitintervalls
aus dem Kondensator herausfließt.
Aus der neuen Ladung berechnen wir die Spannung am Ende des Zeitintervalls.
\item
Für den Vergleich mit der exakten theoretischen Entladekurve
benötigen Sie die Exponentialfunktion \lstinline{exp()}.
Diese finden Sie in der Mathematik-Bibliothek:
\lstinline{#include <math.h>} im Quelltext,
beim \lstinline[style=cmd]{gcc}-Aufruf \lstinline[style=cmd]{-lm} mit angeben.
\item
$Q = C \cdot U$,\quad $U = R \cdot I$,\quad $I = \frac{dQ}{dt}$
\end{itemize}
\solution
\begin{itemize}
\item
\textbf{Schreiben Sie ein C-Programm, das
den zeitlichen Spannungsverlauf in einer Tabelle darstellt.}
In dem Programm \gitfile{hp}{2022ws/20221121}{loesung-1a.c}
arbeiten wir, dem ersten Hinweis folgend,
mit einem Zeitintervall von \lstinline{dt = 0.01}.
Mit dieser Schrittweite lassen wir uns eine Tabelle ausgeben,
die jeweils die Zeit und durch die Simulation berechnete Spannung ausgibt.
Wir simulieren, wie die Ladung $Q = C \cdot U$ des Kondensators
im Laufe der Zeit abfließt.
Dazu berechnen wir in jedem Zeitschritt zunächst den Strom $I = U / R$,
der aus dem Kondensator fließt.
Dieser Strom bewirkt, daß innerhalb des Zeitintervalls $dt$
die Ladung $dQ = I \cdot dt$ aus dem Kondensator abfließt.
Am Ende des Zeitintervalls berechnen wir die zur neuen Ladung $Q$
gehörende neue Spannung $U = Q / C$.
Für eine einfache Ausgabe der Tabelle
verwenden wir die Formatspezifikationen \lstinline{%10.3lf} für drei
bzw.\ \lstinline{%15.8lf} für acht Nachkommastellen Genauigkeit.
Damit schreiben wir jeweils eine \emph{lange Fließkommazahl\/} (\lstinline{%lf})
rechtsbündig in ein Feld der Breite 10 bzw.\ 15
und lassen uns 3 bzw.\ 8 Nachkommastellen ausgeben.
Wir compilieren das Programm mit:
\lstinline[style=cmd]{gcc -Wall -O loesung-1a.c -o loesung-1a}
\item
\textbf{Schreiben Sie ein C-Programm, das ermittelt,
wie lange es dauert, bis die Spannung unter \boldmath $0.1\,{\rm V}$ gefallen ist.}
Wir ändern das Programm \gitfile{hp}{2022ws/20221121}{loesung-1a.c} so ab,
daß zum einen die Schleife abbricht, sobald die Spannung
den Wert $0.1\,{\rm V}$ unterschreitet (\gitfile{hp}{2022ws/20221121}{loesung-1b.c}),
und daß zum anderen nicht jedesmal eine Zeile für die Tabelle ausgegeben wird,
sondern erst am Ende die Zeit (und die Spannung).
Der Ausgabe entnehmen wir, daß die Spannung bei etwa $t = 12.90\,{\rm s}$
den Wert $0.1\,{\rm V}$ unterschreitet.
\item
\textbf{Vergleichen Sie die berechneten Werte
mit der exakten theoretischen Entladekurve:\\[0.5\smallskipamount]
\boldmath
\begin{math}
U(t) = U_0 \cdot e^{-\frac{t}{RC}}
\end{math}}
Wir ändern das Programm \gitfile{hp}{2022ws/20221121}{loesung-1a.c} so ab,
daß es zusätzlich zur Zeit und zur simulierten Spannung
die exakte Spannung $U_0 \cdot e^{-\frac{t}{RC}}$
gemäß der theoretischen Entladekurve ausgibt (\gitfile{hp}{2022ws/20221121}{loesung-1c.c}),
Da dieses Programm die Exponentialfunktion verwendet, müssen wir nun
beim Compilieren zusätzlich \lstinline[style=cmd]{-lm}\hspace{1pt}
für das Einbinden der Mathematik-Bibliothek angeben.
Der erweiterten Tabelle können wir entnehmen,
daß die durch die Simulation berechnete Spannung
mit der Spannung $U_0 \cdot e^{-\frac{t}{RC}}$
gemäß der theoretischen Entladekurve
bis auf wenige Prozent übereinstimmt.
Dies ist für viele praktische Anwendungen ausreichend,
wenn auch nicht für Präzisionsmessungen.
Wenn Sie die Ausgabe des Programms, z.\,B.\ mit
\lstinline[style=cmd]{./loesung-1c > loesung-1c.dat},
in einer Datei \gitfile{hp}{2022ws/20221121}{loesung-1c.dat} speichern,
können Sie sich die beiden Kurven graphisch darstellen lassen,
z.\,B.\ mit \file{gnuplot} und dem folgenden Befehl:
\begin{lstlisting}[style=cmd,gobble=8]
plot "loesung-1c.dat" using 1:2 with lines title "Simulation",
"loesung-1c.dat" using 1:3 with lines title "Theorie"
\end{lstlisting}
\vspace*{-\bigskipamount}
\begin{center}
\input{loesung-1c.tikz}
\end{center}
Der Unterschied zwischen der simulierten und der theoretischen Entladungskurve
ist mit bloßem Auge nicht sichtbar.
\end{itemize}
\exercise{Personen-Datenbank}
Wir betrachten das folgende Programm (\gitfile{hp}{2022ws/20221121}{aufgabe-2.c}):
\begin{lstlisting}
#include <stdio.h>
#include <string.h>
typedef struct
{
char first_name[10];
char family_name[20];
char day, month;
int year;
} person;
int main (void)
{
person sls;
sls.day = 26;
sls.month = 7;
sls.year = 1951;
strcpy (sls.first_name, "Sabine");
strcpy (sls.family_name, "Leutheusser-Schnarrenberger");
printf ("%s %s wurde am %d.%d.%d geboren.\n",
sls.first_name, sls.family_name, sls.day, sls.month, sls.year);
return 0;
}
\end{lstlisting}
Die Standard-Funktion \lstinline{strcpy()} bewirkt ein Kopieren eines Strings
von rechts nach links, hier also z.\,B.\ die Zuweisung der String-Konstanten
\lstinline{"Sabine"} an die String-Variable \lstinline{sls.first_name[]}.
Das Programm wird für einen 32-Bit-Rechner compiliert und ausgeführt.\\
(Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m32} sorgt dafür,
daß \lstinline[style=cmd]{gcc} Code für einen 32-Bit-Prozessor erzeugt.)
\begin{lstlisting}[style=terminal]
$ ¡gcc -Wall -O -m32 aufgabe-2.c -o aufgabe-2¿
$ ¡./aufgabe-2¿
Sabine Leutheusser-Schnarrenberger wurde am 110.98.1701278309 geboren.
Speicherzugriffsfehler
\end{lstlisting}
\begin{enumerate}[\quad(a)]
\item
Erklären Sie die Ausgabe des Programms einschließlich der Zahlenwerte.
\points{4}
\item
Welche Endianness hat der verwendete Rechner?
Begründen Sie Ihre Antwort.
\points{1}
\item
Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus?
\points{2}
\item
Erklären Sie den Speicherzugriffsfehler.
(Es kann sein, daß sich der Fehler auf Ihrem Rechner nicht bemerkbar macht.
Er ist aber trotzdem vorhanden.)
\points{2}
\end{enumerate}
\goodbreak
\solution
\begin{enumerate}[\quad(a)]
\item
\textbf{Erklären Sie die Ausgabe des Programms einschließlich der Zahlenwerte.}
Der String \lstinline{"Leutheusser-Schnarrenberger"}
hat 27 Zeichen und daher mehr als die in der Variablen
\lstinline{sls.family_name} vorgesehenen 20 Zeichen.
Das \lstinline{"nberger"} paßt nicht mehr in die String-Variable.
Die Zuweisung \lstinline{strcpy (sls.family_name, "Leutheusser-Schnarrenberger")}
überschreibt daher 8 Speicherzellen außerhalb der String-Variablen
\lstinline{sls.family_name} mit dem String \lstinline{"nberger"}
(7 Buchstaben zzgl.\ String-Ende-Symbol) -- und damit insbesondere die Variablen
\lstinline{sls.day}, \lstinline{sls.month} und \lstinline{sls.year}.
Die überschriebenen Speicherzellen sehen demnach folgendermaßen aus:
\begin{center}
\begin{picture}(8,1.5)(0,-0.5)
\put(0,0){\line(1,0){8}}
\put(0,1){\line(1,0){8}}
\multiput(0,0)(1,0){9}{\line(0,1){1}}
\put(0.4,0.38){\lstinline{n}}
\put(1.4,0.38){\lstinline{b}}
\put(2.4,0.38){\lstinline{e}}
\put(3.4,0.38){\lstinline{r}}
\put(4.4,0.38){\lstinline{g}}
\put(5.4,0.38){\lstinline{e}}
\put(6.4,0.38){\lstinline{r}}
\put(7.5,0.5){\makebox(0,0){\lstinline{0x00}}}
\put(0.5,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{0.95cm}{0pt}}_{\mbox{\lstinline{day}}}$}}
\put(1.5,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{0.95cm}{0pt}}_{\mbox{\lstinline{month}}}$}}
\put(4.0,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{3.95cm}{0pt}}_{\mbox{\lstinline{year}}}$}}
\put(7.0,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{1.95cm}{0pt}}_{\mbox{?}}$}}
\end{picture}
\end{center}
("`?"' steht für zwei Speicherzellen, von denen wir nicht wissen,
wofür sie genutzt werden.)
Wenn wir die ASCII-Zeichen in Hexadezimalzahlen umrechnen, entspricht dies:
\begin{center}
\begin{picture}(7,1.5)(0,-0.5)
\put(0,0){\line(1,0){8}}
\put(0,1){\line(1,0){8}}
\multiput(0,0)(1,0){9}{\line(0,1){1}}
\put(0.5,0.5){\makebox(0,0){\lstinline{0x6e}}}
\put(1.5,0.5){\makebox(0,0){\lstinline{0x62}}}
\put(2.5,0.5){\makebox(0,0){\lstinline{0x65}}}
\put(3.5,0.5){\makebox(0,0){\lstinline{0x72}}}
\put(4.5,0.5){\makebox(0,0){\lstinline{0x67}}}
\put(5.5,0.5){\makebox(0,0){\lstinline{0x65}}}
\put(6.5,0.5){\makebox(0,0){\lstinline{0x72}}}
\put(7.5,0.5){\makebox(0,0){\lstinline{0x00}}}
\put(0.5,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{0.95cm}{0pt}}_{\mbox{\lstinline{day}}}$}}
\put(1.5,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{0.95cm}{0pt}}_{\mbox{\lstinline{month}}}$}}
\put(4.0,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{3.95cm}{0pt}}_{\mbox{\lstinline{year}}}$}}
\put(7.0,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{1.95cm}{0pt}}_{\mbox{?}}$}}
\end{picture}
\end{center}
Dies entspricht bereits genau den Werten \lstinline{110} und \lstinline{98}
für die Variablen \lstinline{sls.day} bzw.\ \lstinline{sls.month}.
Für die Variable \lstinline{sls.year} müssen wir ihre vier Speicherzellen
unter der Berücksichtigung der Endianness des Rechners zusammenziehen.
Für Big-Endian ergibt dies \lstinline{0x65726765 == 1701996389}.
Für Little-Endian ergibt sich der Wert \lstinline{0x65677265 == 1701278309},
der auch in der Ausgabe des Programms auftaucht.
\item
\textbf{Welche Endianness hat der verwendete Rechner?
Begründen Sie Ihre Antwort.}
Wie in (a) begründet, ergibt sich die Ausgabe von
\lstinline[style=terminal]{1701278309} für das Jahr
aus dem Speicherformat Little-Endian.
\item
\textbf{Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus?}
Wie in (a) begründet, ergäbe sich aus dem Speicherformat Big-Endian
die Ausgabe von \lstinline[style=terminal]{1701996389} für das Jahr.
\item
\textbf{Erklären Sie den Speicherzugriffsfehler.
(Es kann sein, daß sich der Fehler auf Ihrem Rechner nicht bemerkbar macht.
Er ist aber trotzdem vorhanden.)}
Die zwei in (a) mit "`?"' bezeichneten Speicherzellen
wurden ebenfalls überschrieben.
Dies ist in der Ausgabe zunächst nicht sichtbar,
bewirkt aber später den Speicherzugriffsfehler.
(Tatsächlich handelt es sich bei den überschriebenen Speicherzellen
um einen Teil der Rücksprungadresse, die \lstinline{main()} verwendet,
um mit \lstinline{return 0} an das Betriebssystem zurückzugeben.)
\end{enumerate}
\textbf{Hinweis 1:}
Um auf einen solchen Lösungsweg zu kommen, wird empfohlen,
"`geheimnisvolle"' Zahlen nach hexadezimal umzurechnen
und in Speicherzellen (Zweiergruppen von Hex-Ziffern) zu zerlegen.
Oft erkennt man dann direkt ASCII-Zeichen:
Großbuchstaben beginnen mit der Hex-Ziffer \lstinline{4} oder \lstinline{5},
Kleinbuchstaben mit \lstinline{6} oder \lstinline{7}.
\textbf{Hinweis 2:}
Um derartige Programmierfehler in der Praxis von vorneherein zu vermeiden,
wird empfohlen, anstelle von \lstinline{strcpy()}
grundsätzlich die Funktion \lstinline{strncpy()} zu verwenden.
Diese erwartet einen zusätzlichen Parameter,
der die maximal zulässige Länge des Strings enthält.
Ohne einen derartigen expliziten Parameter kann die Funktion nicht wissen,
wie lang die Variable ist, in der der String gespeichert werden soll.
\exercise{Fakultät}
Die Fakultät $n!$ einer ganzen Zahl $n \ge 0$ ist definiert als:
\begin{eqnarray*}
1 & \mbox{für} & n = 0, \\
n \cdot (n-1)! & \mbox{für} & n > 0.
\end{eqnarray*}
Mit anderen Worten: $n! = 1\cdot2\cdot3\cdot\dots\cdot n$.
Die folgende Funktion \lstinline{fak()} berechnet die Fakultät \emph{rekursiv}
(Datei: \gitfile{hp}{2022ws/20221121}{aufgabe-3.c}):
\begin{lstlisting}
int fak (int n)
{
if (n <= 0)
return 1;
else
return n * fak (n - 1);
}
\end{lstlisting}
\begin{enumerate}[\quad(a)]
\item
Schreiben Sie eine Funktion, die die Fakultät \emph{iterativ} berechnet,\\
d.\,h.\ mit Hilfe einer Schleife anstelle von Rekursion.
\points{3}
\item
Wie viele Multiplikationen (Landau-Symbol)
erfordern beide Versionen der Fakultätsfunktion\\
in Abhängigkeit von \lstinline$n$?
Begründen Sie Ihre Antwort.
\points{2}
\item
Wieviel Speicherplatz (Landau-Symbol)
erfordern beide Versionen der Fakultätsfunktion\\
in Abhängigkeit von \lstinline$n$?
Begründen Sie Ihre Antwort.
\points{3}
\end{enumerate}
\solution
\begin{itemize}
\item[(a)]
\textbf{Schreiben Sie eine Funktion, die die Fakultät \emph{iterativ} berechnet,\\
d.\,h.\ mit Hilfe einer Schleife anstelle von Rekursion.}
Datei: \gitfile{hp}{2022ws/20221121}{loesung-3.c}
\begin{lstlisting}[gobble=8]
int fak (int n)
{
int f = 1;
for (int i = 2; i <= n; i++)
f *= i;
return f;
}
\end{lstlisting}
\item[(b)]
\textbf{Wie viele Multiplikationen (Landau-Symbol)
erfordern beide Versionen der Fakultätsfunktion\\
in Abhängigkeit von \lstinline$n$?
Begründen Sie Ihre Antwort.}
In beiden Fällen werden $n$ Zahlen miteinander multipliziert --
oder $n - 1$, wenn man Multiplikationen mit 1 ausspart.
In jedem Fall hängt die Anzahl der Multiplikationen
linear von $n$ ab; es sind $\mathcal{O}(n)$ Multiplikationen.
Insbesondere arbeiten also beide Versionen gleich schnell.
\item[(c)]
\textbf{Wieviel Speicherplatz (Landau-Symbol)
erfordern beide Versionen der Fakultätsfunktion\\
in Abhängigkeit von \lstinline$n$?
Begründen Sie Ihre Antwort.}
Die iterative Version der Funktion benötigt 2 Variable vom Typ \lstinline{int},
nämlich \lstinline{n} und \lstinline{f}.
Dies ist eine konstante Zahl;
der Speicherplatzverbrauch ist daher $\mathcal{O}(1)$.
Die rekursive Version der Funktion erzeugt
jedesmal, wenn sie sich selbst aufruft,
eine zusätzliche Variable \lstinline{n}.
Es sind $n + 1$ Aufrufe; die Anzahl der Variablen \lstinline{n}
hängt linear von $n$ ab; der Speicherplatzverbrauch ist also $\mathcal{O}(n)$.
\end{itemize}
\end{document}
File added
% hp-uebung-20221121.pdf - Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 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: Kondensator, Personen-Datenbank, Fakultät
\documentclass[a4paper]{article}
\usepackage{pgscript}
\begin{document}
\thispagestyle{empty}
\section*{Hardwarenahe Programmierung\\
Übungsaufgaben -- 21.\ November 2022}
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{Kondensator}
Ein Kondensator der Kapazität $C = 100\,\mu{\rm F}$
ist auf die Spannung $U_0 = 5\,{\rm V}$ aufgeladen
und wird über einen Widerstand $R = 33\,{\rm k}\Omega$ entladen.
\begin{enumerate}[(a)]
\item
Schreiben Sie ein C-Programm, das
den zeitlichen Spannungsverlauf in einer Tabelle darstellt.
\points{5}
\item
Schreiben Sie ein C-Programm, das ermittelt,
wie lange es dauert, bis die Spannung unter $0.1\,{\rm V}$ gefallen ist.
\points{4}
\item
Vergleichen Sie die berechneten Werte mit der exakten theoretischen Entladekurve:
\begin{math}
U(t) = U_0 \cdot e^{-\frac{t}{RC}}
\end{math}\\
\points{3}
\end{enumerate}
Hinweise:
\begin{itemize}
\item
Für die Simulation zerlegen wir den Entladevorgang in kurze Zeitintervalle $dt$.
Innerhalb jedes Zeitintervalls betrachten wir den Strom $I$ als konstant
und berechnen, wieviel Ladung $Q$ innerhalb des Zeitintervalls
aus dem Kondensator herausfließt.
Aus der neuen Ladung berechnen wir die Spannung am Ende des Zeitintervalls.
\item
Für den Vergleich mit der exakten theoretischen Entladekurve
benötigen Sie die Exponentialfunktion \lstinline{exp()}.
Diese finden Sie in der Mathematik-Bibliothek:
\lstinline{#include <math.h>} im Quelltext,
beim \lstinline[style=cmd]{gcc}-Aufruf \lstinline[style=cmd]{-lm} mit angeben.
\item
$Q = C \cdot U$,\quad $U = R \cdot I$,\quad $I = \frac{dQ}{dt}$
\end{itemize}
\exercise{Personen-Datenbank}
Wir betrachten das folgende Programm (\gitfile{hp}{2022ws/20221121}{aufgabe-2.c}):
\begin{lstlisting}
#include <stdio.h>
#include <string.h>
typedef struct
{
char first_name[10];
char family_name[20];
char day, month;
int year;
} person;
int main (void)
{
person sls;
sls.day = 26;
sls.month = 7;
sls.year = 1951;
strcpy (sls.first_name, "Sabine");
strcpy (sls.family_name, "Leutheusser-Schnarrenberger");
printf ("%s %s wurde am %d.%d.%d geboren.\n",
sls.first_name, sls.family_name, sls.day, sls.month, sls.year);
return 0;
}
\end{lstlisting}
Die Standard-Funktion \lstinline{strcpy()} bewirkt ein Kopieren eines Strings
von rechts nach links, hier also z.\,B.\ die Zuweisung der String-Konstanten
\lstinline{"Sabine"} an die String-Variable \lstinline{sls.first_name[]}.
Das Programm wird für einen 32-Bit-Rechner compiliert und ausgeführt.\\
(Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m32} sorgt dafür,
daß \lstinline[style=cmd]{gcc} Code für einen 32-Bit-Prozessor erzeugt.)
\begin{lstlisting}[style=terminal]
$ ¡gcc -Wall -O -m32 aufgabe-2.c -o aufgabe-2¿
$ ¡./aufgabe-2¿
Sabine Leutheusser-Schnarrenberger wurde am 110.98.1701278309 geboren.
Speicherzugriffsfehler
\end{lstlisting}
\begin{enumerate}[\quad(a)]
\item
Erklären Sie die Ausgabe des Programms einschließlich der Zahlenwerte.
\points{4}
\item
Welche Endianness hat der verwendete Rechner?
Begründen Sie Ihre Antwort.
\points{1}
\item
Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus?
\points{2}
\item
Erklären Sie den Speicherzugriffsfehler.
(Es kann sein, daß sich der Fehler auf Ihrem Rechner nicht bemerkbar macht.
Er ist aber trotzdem vorhanden.)
\points{2}
\end{enumerate}
\exercise{Fakultät}
Die Fakultät $n!$ einer ganzen Zahl $n \ge 0$ ist definiert als:
\begin{eqnarray*}
1 & \mbox{für} & n = 0, \\
n \cdot (n-1)! & \mbox{für} & n > 0.
\end{eqnarray*}
Mit anderen Worten: $n! = 1\cdot2\cdot3\cdot\dots\cdot n$.
Die folgende Funktion \lstinline{fak()} berechnet die Fakultät \emph{rekursiv}
(Datei: \gitfile{hp}{2022ws/20221121}{aufgabe-3.c}):
\begin{lstlisting}
int fak (int n)
{
if (n <= 0)
return 1;
else
return n * fak (n - 1);
}
\end{lstlisting}
\begin{enumerate}[\quad(a)]
\item
Schreiben Sie eine Funktion, die die Fakultät \emph{iterativ} berechnet,\\
d.\,h.\ mit Hilfe einer Schleife anstelle von Rekursion.
\points{3}
\item
Wie viele Multiplikationen (Landau-Symbol)
erfordern beide Versionen der Fakultätsfunktion\\
in Abhängigkeit von \lstinline$n$?
Begründen Sie Ihre Antwort.
\points{2}
\item
Wieviel Speicherplatz (Landau-Symbol)
erfordern beide Versionen der Fakultätsfunktion\\
in Abhängigkeit von \lstinline$n$?
Begründen Sie Ihre Antwort.
\points{3}
\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>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, char *pivot, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (name[i] == pivot)
printf (" <==");
else if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, char *pivot, int left, int right)
{
int result = strcmp (name[left], pivot);
comparisons++;
display (name, pivot, left, right);
usleep (200000);
return result;
}
void quicksort (char **name, int left, int right)
{
int p = (left + right) / 2;
char *pivot = name[p];
int l = left;
int r = right;
while (l < r)
{
while (l < r && compare (name, pivot, l, r - 1) < 0)
l++;
while (l < r && compare (name, pivot, r - 1, l) > 0)
r--;
if (l < r)
{
char *temp = name[r - 1];
name[r - 1] = name[l];
name[l] = temp;
l++;
r--;
}
}
}
void sort (char **name)
{
int r = 0;
while (name[r])
r++;
quicksort (name, 0, r);
}
int main (void)
{
char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
"Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
"Thomas", "Ulrich", "Zacharias", NULL };
sort (name);
display (name, NULL, -1, -1);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, char *pivot, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (name[i] == pivot)
printf (" <==");
else if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, char *pivot, int left, int right)
{
int result = strcmp (name[left], pivot);
comparisons++;
display (name, pivot, left, right);
usleep (200000);
return result;
}
void quicksort (char **name, int left, int right)
{
int p = (left + right) / 2 - 1;
char *pivot = name[p];
int l = left;
int r = right;
while (l < r)
{
while (l < r && compare (name, pivot, l, r - 1) < 0)
l++;
while (l < r && compare (name, pivot, r - 1, l) > 0)
r--;
if (l < r)
{
char *temp = name[r - 1];
name[r - 1] = name[l];
name[l] = temp;
l++;
r--;
}
}
}
void sort (char **name)
{
int r = 0;
while (name[r])
r++;
quicksort (name, 0, r);
}
int main (void)
{
char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
"Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
"Thomas", "Ulrich", "Zacharias", NULL };
sort (name);
display (name, NULL, -1, -1);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, char *pivot, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (name[i] == pivot)
printf (" <==");
else if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, char *pivot, int left, int right)
{
int result = strcmp (name[left], pivot);
comparisons++;
display (name, pivot, left, right);
usleep (200000);
return result;
}
void quicksort (char **name, int left, int right)
{
int p = (left + right) / 2;
char *pivot = name[p];
int l = left;
int r = right;
while (l < r)
{
while (l < r && compare (name, pivot, l, r - 1) < 0)
l++;
while (l < r && compare (name, pivot, r - 1, l) > 0)
r--;
if (l < r)
{
char *temp = name[r - 1];
name[r - 1] = name[l];
name[l] = temp;
l++;
r--;
}
}
if (l < right)
quicksort (name, l, right);
}
void sort (char **name)
{
int r = 0;
while (name[r])
r++;
quicksort (name, 0, r);
}
int main (void)
{
char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
"Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
"Thomas", "Ulrich", "Zacharias", NULL };
sort (name);
display (name, NULL, -1, -1);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, char *pivot, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (name[i] == pivot)
printf (" <==");
else if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, char *pivot, int left, int right)
{
int result = strcmp (name[left], pivot);
comparisons++;
display (name, pivot, left, right);
usleep (200000);
return result;
}
void quicksort (char **name, int left, int right)
{
int p = (left + right) / 2;
char *pivot = name[p];
int l = left;
int r = right;
while (l < r)
{
while (l < r && compare (name, pivot, l, r - 1) < 0)
l++;
while (l < r && compare (name, pivot, r - 1, l) > 0)
r--;
if (l < r)
{
char *temp = name[r - 1];
name[r - 1] = name[l];
name[l] = temp;
l++;
r--;
}
}
if (r > left)
quicksort (name, left, r);
if (l < right)
quicksort (name, l, right);
}
void sort (char **name)
{
int r = 0;
while (name[r])
r++;
quicksort (name, 0, r);
}
int main (void)
{
char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
"Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
"Thomas", "Ulrich", "Zacharias", NULL };
sort (name);
display (name, NULL, -1, -1);
return 0;
}
cassini/home/peter/bo/2022ws/hp/20221121> bc
bc 1.07.1
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
16 / 2
8
8 / 2
4
4 / 2
2
2 / 2
1
cassini/home/peter/bo/2022ws/hp/20221121>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, char *pivot, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (name[i] == pivot)
printf (" <==");
else if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, char *pivot, int left, int right)
{
int result = strcmp (name[left], pivot);
comparisons++;
display (name, pivot, left, right);
usleep (200000);
return result;
}
void quicksort (char **name, int left, int right)
{
int p = (left + right) / 2;
char *pivot = name[p];
int l = left;
int r = right;
while (l < r)
{
while (l < r && compare (name, pivot, l, r - 1) < 0)
l++;
while (l < r && compare (name, pivot, r - 1, l) > 0)
r--;
if (l < r)
{
char *temp = name[r - 1];
name[r - 1] = name[l];
name[l] = temp;
l++;
r--;
}
}
if (r > left)
quicksort (name, left, r);
if (l < right)
quicksort (name, l, right);
}
void sort (char **name)
{
int r = 0;
while (name[r])
r++;
quicksort (name, 0, r);
}
int main (void)
{
char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
"Dieter", "Berta", "Hugo", "Maria", "Fritz", "Box", "Hans",
"Thomas", "Ulrich", "Zacharias", NULL };
sort (name);
display (name, NULL, -1, -1);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int comparisons = 0;
void display (char **name, char *pivot, int left, int right)
{
printf ("\e[H\e[J");
for (int i = 0; name[i]; i++)
{
printf ("%s", name[i]);
if (name[i] == pivot)
printf (" <==");
else if (i == left || i == right)
printf (" <--");
printf ("\n");
}
printf ("%d\n", comparisons);
}
int compare (char **name, char *pivot, int left, int right)
{
int result = strcmp (name[left], pivot);
comparisons++;
// display (name, pivot, left, right);
// usleep (200000);
return result;
}
void quicksort (char **name, int left, int right)
{
int p = (left + right) / 2;
char *pivot = name[p];
int l = left;
int r = right;
while (l < r)
{
while (l < r && compare (name, pivot, l, r - 1) < 0)
l++;
while (l < r && compare (name, pivot, r - 1, l) > 0)
r--;
if (l < r)
{
char *temp = name[r - 1];
name[r - 1] = name[l];
name[l] = temp;
l++;
r--;
}
}
if (r > left)
quicksort (name, left, r);
if (l < right)
quicksort (name, l, right);
}
void sort (char **name)
{
int r = 0;
while (name[r])
r++;
quicksort (name, 0, r);
}
int main (void)
{
char *name[] = {
#include "names.h"
NULL
};
sort (name);
display (name, NULL, -1, -1);
return 0;
}
cassini/home/peter/bo/2022ws/hp/20221121> ./sort-6 | tail -1
4950
cassini/home/peter/bo/2022ws/hp/20221121> ./bsort-4c | tail -1
4792
cassini/home/peter/bo/2022ws/hp/20221121> ./qsort-3b | tail -1
1130
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment