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

Vorbereitung 19.12.2024

parent 2e3f8003
No related branches found
No related tags found
No related merge requests found
Showing
with 1883 additions and 0 deletions
../common/Tower_of_Hanoi.jpeg
\ No newline at end of file
#include <stdio.h>
/* ... */
int main (void)
{
pbm_open (14, 14, "test.pbm");
pbm_line (" ");
pbm_line (" XXXXXX ");
pbm_line (" X X ");
pbm_line (" X X ");
pbm_line (" X X ");
pbm_line (" X XX XX X ");
pbm_line (" X X X X ");
pbm_line (" X X ");
pbm_line (" X X X X ");
pbm_line (" X X X X ");
pbm_line (" X XXXX X ");
pbm_line (" X X ");
pbm_line (" XXXXXX ");
pbm_line (" ");
pbm_close ();
return 0;
}
File added
20241219/aufgabe-1.png

162 B

#include <stdio.h>
int fak (int n)
{
if (n <= 0)
return 1;
else
return n * fak (n - 1);
}
int main (void)
{
for (int n = 0; n <= 5; n++)
printf ("%d\n", fak (n));
return 0;
}
#include <stdio.h>
#include <stdint.h>
typedef struct
{
uint32_t a;
uint64_t b;
uint8_t c;
} three_numbers;
int main (void)
{
three_numbers xyz = { 1819042120, 2410670883059281007, 0 };
printf ("%s\n", &xyz);
return 0;
}
File added
This diff is collapsed.
File added
% hp-musterloesung-20241219.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015-2023, 2024 Peter Gerwinski
%
% This document is free software: you can redistribute it and/or
% modify it either under the terms of the Creative Commons
% Attribution-ShareAlike 3.0 License, or under the terms of the
% GNU General Public License as published by the Free Software
% Foundation, either version 3 of the License, or (at your option)
% any later version.
%
% This document is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this document. If not, see <http://www.gnu.org/licenses/>.
%
% You should have received a copy of the Creative Commons
% Attribution-ShareAlike 3.0 Unported License along with this
% document. If not, see <http://creativecommons.org/licenses/>.
% README: 9: PBM-Grafik, Fakultät, Speicherformate von Zahlen
\documentclass[a4paper]{article}
\usepackage{pgscript}
\usepackage{gensymb}
\usepackage{gnuplot-lua-tikz}
\newcommand{\ItwoC}{I\raisebox{0.5ex}{\footnotesize 2}C}
\newcommand{\ITWOC}{I\raisebox{0.5ex}{\normalsize 2}C}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben 9 -- 19.\ Dezember 2024}
\thispagestyle{empty}
\exercise{PBM-Grafik}
Bei einer PBM-Grafikdatei handelt es sich
um ein abgespeichertes C-Array von Bytes (\lstinline{uint8_t}),
das die Bildinformationen enthält:
\begin{itemize}\itemsep0pt
\item Die Datei beginnt mit der Kennung \lstinline{P4},
danach folgen Breite und Höhe in Pixel als ASCII-Zahlen,
danach ein Trennzeichen und die eigentlichen Bilddaten.
\item Jedes Bit entspricht einem Pixel.
\item Nullen stehen für Weiß, Einsen für Schwarz.
\item MSB first.
\item Jede Zeile des Bildes wird auf ganze Bytes aufgefüllt.
\end{itemize}
Viele Grafikprogramme können PBM-Dateien öffnen und bearbeiten.
Der Anfang der Datei (Kennung, Breite und Höhe)
ist auch in einem Texteditor lesbar.
Beispiel (\gitfile{hp}{2024ws/20241219}{aufgabe-1.pbm}):\hfill
\makebox(0,0)[tr]{\framebox{\includegraphics[scale=3]{aufgabe-1.png}}}
\begin{lstlisting}
P4
14 14
<Bilddaten>
\end{lstlisting}
In dem untenstehenden Programmfragment (\gitfile{hp}{2024ws/20241219}{aufgabe-1.c})
wird eine Grafik aus Textzeilen zusammengesetzt,
so daß man mit einem Texteditor "`malen"' kann:
\begin{lstlisting}
#include <stdio.h>
/* ... */
int main (void)
{
pbm_open (14, 14, "test.pbm");
pbm_line (" ");
pbm_line (" XXXXXX ");
pbm_line (" X X ");
pbm_line (" X X ");
pbm_line (" X X ");
pbm_line (" X XX XX X ");
pbm_line (" X X X X ");
pbm_line (" X X ");
pbm_line (" X X X X ");
pbm_line (" X X X X ");
pbm_line (" X XXXX X ");
pbm_line (" X X ");
pbm_line (" XXXXXX ");
pbm_line (" ");
pbm_close ();
return 0;
}
\end{lstlisting}
Ergänzen Sie das Programmfragment so,
daß es eine Datei \file{test.pbm} erzeugt, die die Grafik enthält.
Das Programm soll typische Benutzerfehler abfangen
(z.\,B.\ weniger Zeilen als in \lstinline{pbm_open} angegeben),
keine fehlerhaften Ausgaben produzieren oder abstürzen,
sondern stattdessen sinnvolle Fehlermeldungen ausgeben.
Zum Vergleich liegt eine Datei \gitfile{hp}{2024ws/20241219}{aufgabe-1.pbm}
mit dem gewünschten Ergebnis bei,\\
und die Datei \gitfile{hp}{2024ws/20241219}{aufgabe-1.png} enthält dasselbe Bild.
\points{10}
Hinweis für die Klausur:
Abgabe in digitaler Form ist erwünscht, aber nicht zwingend.
\solution
Die Datei \gitfile{hp}{2024ws/20241219}{loesung-1.c} enthält eine richtige Lösung.
Man beachte die Aufrufe der Funktion \lstinline{error()} im Falle von
falscher Benutzung der Bibliotheksfunktionen.
Weitere Erklärungen finden Sie als Kommentare im Quelltext.
Die Datei \gitfile{hp}{2024ws/20241219}{loesung-1f.c} enthält eine falsche Lösung.
(Beide Dateien unterscheiden sich nur in Zeile 46.)
Dieses Programm speichert die Bits in den Bytes von rechts nach links (LSB first).
Richtig wäre von links nach rechts (MBS first).
Das erzeugte Bild ist dementsprechend fehlerhaft.
\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}{2024ws/20241219}{aufgabe-2.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}{2024ws/20241219}{loesung-2.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}
\exercise{Speicherformate von Zahlen}
Wir betrachten das folgende Programm (\gitfile{hp}{2024ws/20241219}{aufgabe-3.c}):
\begin{lstlisting}
#include <stdio.h>
#include <stdint.h>
typedef struct
{
uint32_t a;
uint64_t b;
uint8_t c;
} three_numbers;
int main (void)
{
three_numbers xyz = { 1819042120, 2410670883059281007, 0 };
printf ("%s\n", &xyz);
return 0;
}
\end{lstlisting}
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 -m32 aufgabe-2.c -o aufgabe-2¿
aufgabe-2.c: In function "main":
aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *", but
argument 2 has type "three_numbers * {aka struct <anonymous> *}" [-Wformat=]
printf ("%s\n", &xyz);
^
$ ¡./aufgabe-2¿
Hallo, Welt!
\end{lstlisting}
\begin{enumerate}[\quad(a)]
\item
Erklären Sie die beim Compilieren auftretende Warnung.
\points{2}
\item
Erklären Sie die Ausgabe des Programms.
\points{4}
\item
Welche Endianness hat der verwendete Rechner?
Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus?
\points{2}
\item
Dasselbe Programm wird nun für einen 64-Bit-Rechner compiliert und ausgeführt.\\
(Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m64} sorgt dafür,
daß \lstinline[style=cmd]{gcc} Code für einen 64-Bit-Prozessor erzeugt.)
\begin{lstlisting}[style=terminal,gobble=8]
$ ¡gcc -Wall -m64 aufgabe-2.c -o aufgabe-2¿
aufgabe-2.c: In function "main":
aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *",
but argument 2 has type "three_numbers * {aka struct <anonymous> *}"
[-Wformat=]
printf ("%s\n", &xyz);
^
$ ¡./aufgabe-2¿
Hall5V
\end{lstlisting}
(Es ist möglich, daß die konkrete Ausgabe auf Ihrem Rechner anders aussieht.)\par
Erklären Sie die geänderte Ausgabe des Programms.
\points{3}
\end{enumerate}
\solution
\begin{enumerate}[\quad(a)]
\item
\textbf{Erklären Sie die beim Compilieren auftretende Warnung.}
Die Funktion \lstinline{printf()} mit der Formatspezifikation \lstinline{%s}
erwartet als Parameter einen String, d.\,h.\ einen Zeiger auf \lstinline{char}.
Die Adresse (\lstinline{&}) der Variablen \lstinline{xyz}
ist zwar ein Zeiger, aber nicht auf \lstinline{char},
sondern auf einen \lstinline{struct} vom Typ \lstinline{three_numbers}.
Eine implizite Umwandlung des Zeigertyps ist zwar möglich,
aber normalerweise nicht das, was man beabsichtigt.
\item
\textbf{Erklären Sie die Ausgabe des Programms.}
Ein String in C ist ein Array von \lstinline{char}s
bzw.\ ein Zeiger auf \lstinline{char}.
Da die Funktion \lstinline{printf()} mit der Formatspezifikation \lstinline{%s}
einen String erwartet, wird sie das, worauf der übergebene Zeiger zeigt,
als ein Array von \lstinline{char}s interpretieren.
Ein \lstinline{char} entspricht einer 8-Bit-Speicherzelle.
Um die Ausgabe des Programms zu erklären, müssen wir daher
die Speicherung der Zahlen in den einzelnen 8-Bit-Speicherzellen betrachten.
Hierfür wandeln wir zunächst die Zahlen von Dezimal nach Hexadezimal um.
Sofern nötig (hier nicht der Fall) füllen wir von links mit Nullen auf,
um den gesamten von der Variablen belegten Speicherplatz zu füllen
(hier: 32 Bit, 64 Bit, 8 Bit).
Jeweils 2 Hex-Ziffern stehen für 8 Bit.
\begin{center}
\begin{tabular}{rcl}
dezimal & & hexadezimal \\[\smallskipamount]
1\,819\,042\,120 & = & 6C\,6C\,61\,48 \\
2\,410\,670\,883\,059\,281\,007 & = & 21\,74\,6C\,65\,57\,20\,2C\,6F \\
0 & = & 00
\end{tabular}
\end{center}
Die Anordnung dieser 8-Bit-Zellen im Speicher lautet
\textbf{auf einem Big-Endian-Rechner} wie folgt:
\begin{center}
\begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline
\raisebox{0.5ex}{\strut}
6C & 6C & 61 & 48 &
21 & 74 & 6C & 65 & 57 & 20 & 2C & 6F &
00
\\\hline
\end{tabular}\\[-4.2ex]
\kern1.7em%
$\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt%
$\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt%
$\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$%
\end{center}
\textbf{Auf einem Little-Endian-Rechner} lautet sie hingegen:
\begin{center}
\begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline
% \raisebox{0.5ex}{\strut}
% H & a & l & l &
% o & , & & W & e & l & t & ! & \\\hline
\raisebox{0.5ex}{\strut}
48 & 61 & 6C & 6C &
6F & 2C & 20 & 57 & 65 & 6C & 74 & 21 &
00
\\\hline
\end{tabular}\\[-4.2ex]
\kern1.7em%
$\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt%
$\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt%
$\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$%
\end{center}
Anhand einer ASCII-Tabelle erkennt man,
daß die Big-Endian-Variante dem String \lstinline{"llaH!tleW ,o"}
und die Little-Endian-Variante dem String \lstinline{"Hallo, Welt!"}
entspricht -- jeweils mit einem Null-Symbol am Ende,
das von der Variablen \lstinline{c} herrührt.
Auf einem Little-Endian-Rechner wird daher
\lstinline[style=terminal]{Hallo, Welt!} ausgegeben.
\item
\textbf{Welche Endianness hat der verwendete Rechner?}
Little-Endian (Begründung siehe oben)
\textbf{Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus?}
\lstinline[style=terminal]{llaH!tleW ,o} (Begründung siehe oben)
\item
\textbf{Dasselbe Programm wird nun für einen 64-Bit-Rechner compiliert und ausgeführt.\\
(Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m64} sorgt dafür,
daß \lstinline[style=cmd]{gcc} Code für einen 64-Bit-Prozessor erzeugt.)}
\begin{lstlisting}[style=terminal,gobble=8]
$ ¡gcc -Wall -m64 aufgabe-2.c -o aufgabe-2¿
aufgabe-2.c: In function "main":
aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *",
but argument 2 has type "three_numbers * {aka struct <anonymous> *}"
[-Wformat=]
printf ("%s\n", &xyz);
^
$ ¡./aufgabe-2¿
Hall5V
\end{lstlisting}
\textbf{(Es ist möglich, daß die konkrete Ausgabe auf Ihrem Rechner anders aussieht.)}\par
\textbf{Erklären Sie die geänderte Ausgabe des Programms.}
\goodbreak
Auf einem 64-Bit-Rechner hat eine 64-Bit-Variable
ein \textbf{64-Bit-Alignment},
d.\,h.\ ihre Speicheradresse muß durch 8 teilbar sein.
Der Compiler legt die Variablen daher wie folgt im Speicher ab (Little-Endian):
\begin{center}
\begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline
\raisebox{0.5ex}{\strut}
48 & 61 & 6C & 6C & ?? & ?? & ?? & ?? &
6F & 2C & 20 & 57 & 65 & 6C & 74 & 21 &
00
\\\hline
\end{tabular}\\[-4.2ex]
\kern1.7em%
$\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt%
$\underbrace{\rule{9.1em}{0pt}}_{\mbox{Füll-Bytes}}$\kern1pt%
$\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt%
$\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$%
\end{center}
Der Inhalt der Füll-Bytes ist undefiniert.
Im Beispiel aus der Aufgabenstellung entsteht hier die Ausgabe
\lstinline[style=terminal]{5V}, was den (zufälligen) hexadezimalen Werten
35 56 entspricht:
\begin{center}
\begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline
\raisebox{0.5ex}{\strut}
48 & 61 & 6C & 6C & 35 & 56 & 00 & ?? &
6F & 2C & 20 & 57 & 65 & 6C & 74 & 21 &
00
\\\hline
\end{tabular}\\[-4.2ex]
\kern1.7em%
$\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt%
$\underbrace{\rule{9.1em}{0pt}}_{\mbox{Füll-Bytes}}$\kern1pt%
$\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt%
$\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$%
\end{center}
Da danach die Ausgabe aufhört, muß an der nächsten Stelle
ein Null-Symbol stehen, das das Ende des Strings anzeigt.
Der Inhalt der darauf folgenden Speicherzelle bleibt unbekannt.
\end{enumerate}
\end{document}
File added
% hp-uebung-20241219.pdf - Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015-2023, 2024 Peter Gerwinski
%
% This document is free software: you can redistribute it and/or
% modify it either under the terms of the Creative Commons
% Attribution-ShareAlike 3.0 License, or under the terms of the
% GNU General Public License as published by the Free Software
% Foundation, either version 3 of the License, or (at your option)
% any later version.
%
% This document is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this document. If not, see <http://www.gnu.org/licenses/>.
%
% You should have received a copy of the Creative Commons
% Attribution-ShareAlike 3.0 Unported License along with this
% document. If not, see <http://creativecommons.org/licenses/>.
% README: 9: PBM-Grafik, Fakultät, Speicherformate von Zahlen
\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}
\section*{Hardwarenahe Programmierung\\
Übungsaufgaben 9 -- 19.\ Dezember 2024}
Diese Übung enthält Punkteangaben wie in einer Klausur.
Um zu "`bestehen"', müssen Sie innerhalb von 90 Minuten
unter Verwendung ausschließlich zugelassener Hilfsmittel
16 Punkte (von insgesamt \totalpoints) erreichen.
% \thispagestyle{empty}
\exercise{PBM-Grafik}
Bei einer PBM-Grafikdatei handelt es sich
um ein abgespeichertes C-Array von Bytes (\lstinline{uint8_t}),
das die Bildinformationen enthält:
\begin{itemize}\itemsep0pt
\item Die Datei beginnt mit der Kennung \lstinline{P4},
danach folgen Breite und Höhe in Pixel als ASCII-Zahlen,
danach ein Trennzeichen und die eigentlichen Bilddaten.
\item Jedes Bit entspricht einem Pixel.
\item Nullen stehen für Weiß, Einsen für Schwarz.
\item MSB first.
\item Jede Zeile des Bildes wird auf ganze Bytes aufgefüllt.
\end{itemize}
Viele Grafikprogramme können PBM-Dateien öffnen und bearbeiten.
Der Anfang der Datei (Kennung, Breite und Höhe)
ist auch in einem Texteditor lesbar.
Beispiel (\gitfile{hp}{2024ws/20241219}{aufgabe-1.pbm}):\hfill
\makebox(0,0)[tr]{\framebox{\includegraphics[scale=3]{aufgabe-1.png}}}
\begin{lstlisting}
P4
14 14
<Bilddaten>
\end{lstlisting}
In dem untenstehenden Programmfragment (\gitfile{hp}{2024ws/20241219}{aufgabe-1.c})
wird eine Grafik aus Textzeilen zusammengesetzt,
so daß man mit einem Texteditor "`malen"' kann:
\begin{lstlisting}
#include <stdio.h>
/* ... */
int main (void)
{
pbm_open (14, 14, "test.pbm");
pbm_line (" ");
pbm_line (" XXXXXX ");
pbm_line (" X X ");
pbm_line (" X X ");
pbm_line (" X X ");
pbm_line (" X XX XX X ");
pbm_line (" X X X X ");
pbm_line (" X X ");
pbm_line (" X X X X ");
pbm_line (" X X X X ");
pbm_line (" X XXXX X ");
pbm_line (" X X ");
pbm_line (" XXXXXX ");
pbm_line (" ");
pbm_close ();
return 0;
}
\end{lstlisting}
Ergänzen Sie das Programmfragment so,
daß es eine Datei \file{test.pbm} erzeugt, die die Grafik enthält.
Das Programm soll typische Benutzerfehler abfangen
(z.\,B.\ weniger Zeilen als in \lstinline{pbm_open} angegeben),
keine fehlerhaften Ausgaben produzieren oder abstürzen,
sondern stattdessen sinnvolle Fehlermeldungen ausgeben.
Zum Vergleich liegt eine Datei \gitfile{hp}{2024ws/20241219}{aufgabe-1.pbm}
mit dem gewünschten Ergebnis bei,\\
und die Datei \gitfile{hp}{2024ws/20241219}{aufgabe-1.png} enthält dasselbe Bild.
\points{10}
Hinweis für die Klausur:
Abgabe in digitaler Form ist erwünscht, aber nicht zwingend.
\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}{2024ws/20241219}{aufgabe-2.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}
\exercise{Speicherformate von Zahlen}
Wir betrachten das folgende Programm (\gitfile{hp}{2024ws/20241219}{aufgabe-3.c}):
\begin{lstlisting}
#include <stdio.h>
#include <stdint.h>
typedef struct
{
uint32_t a;
uint64_t b;
uint8_t c;
} three_numbers;
int main (void)
{
three_numbers xyz = { 1819042120, 2410670883059281007, 0 };
printf ("%s\n", &xyz);
return 0;
}
\end{lstlisting}
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 -m32 aufgabe-2.c -o aufgabe-2¿
aufgabe-2.c: In function "main":
aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *", but
argument 2 has type "three_numbers * {aka struct <anonymous> *}" [-Wformat=]
printf ("%s\n", &xyz);
^
$ ¡./aufgabe-2¿
Hallo, Welt!
\end{lstlisting}
\begin{enumerate}[\quad(a)]
\item
Erklären Sie die beim Compilieren auftretende Warnung.
\points{2}
\item
Erklären Sie die Ausgabe des Programms.
\points{4}
\item
Welche Endianness hat der verwendete Rechner?
Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus?
\points{2}
\item
Dasselbe Programm wird nun für einen 64-Bit-Rechner compiliert und ausgeführt.\\
(Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m64} sorgt dafür,
daß \lstinline[style=cmd]{gcc} Code für einen 64-Bit-Prozessor erzeugt.)
\begin{lstlisting}[style=terminal,gobble=8]
$ ¡gcc -Wall -m64 aufgabe-2.c -o aufgabe-2¿
aufgabe-2.c: In function "main":
aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *",
but argument 2 has type "three_numbers * {aka struct <anonymous> *}"
[-Wformat=]
printf ("%s\n", &xyz);
^
$ ¡./aufgabe-2¿
Hall5V
\end{lstlisting}
(Es ist möglich, daß die konkrete Ausgabe auf Ihrem Rechner anders aussieht.)\par
Erklären Sie die geänderte Ausgabe des Programms.
\points{3}
\end{enumerate}
\bigskip
\begin{flushright}
\textit{Viel Erfolg!}
\end{flushright}
\makeatletter
\immediate\write\@mainaux{\string\gdef\string\totalpoints{\arabic{points}}}
\makeatother
\end{document}
../common/landau-symbols-2.pdf
\ No newline at end of file
../common/landau-symbols-3.pdf
\ No newline at end of file
../common/landau-symbols.pdf
\ No newline at end of file
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <error.h>
/* Die Aufgabe besteht darin, die Funktionen pbm_open(),
* pbm_line() und pbm_close() zu schreiben.
*/
int pbm_width = 0;
int pbm_height = 0;
int line_no = 0;
FILE *pbm_file = NULL; /* globale Variable für die PBM-Datei */
void pbm_open (int width, int height, char *filename)
{
pbm_file = fopen (filename, "w");
if (!pbm_file)
error (errno, errno, "pbm_open(): cannot open file %s for writing", filename);
pbm_width = width;
pbm_height = height;
fprintf (pbm_file, "P4\n%d %d\n", pbm_width, pbm_height);
}
void pbm_line (char *line)
{
if (!pbm_file)
error (1, 0, "pbm_line(): PBM file not open");
if (!line)
error (1, 0, "pbm_line(): line is NULL");
if (strlen (line) != pbm_width)
error (1, 0, "pbm_line(): line length does not match width");
if (line_no >= pbm_height)
error (1, 0, "pbm_line(): too many lines");
int pbm_bytes = (pbm_width + 7) / 8; /* benötigte Bytes pro Zeile (immer aufrunden) */
uint8_t buffer[pbm_bytes];
for (int i = 0; i < pbm_bytes; i++) /* Puffer auf 0 initialisieren */
buffer[i] = 0;
line_no++;
for (int x = 0; line[x]; x++)
{
int i = x / 8; /* In welches Byte des Puffers gehört dieses Pixel? */
int b = x % 8; /* Welches Bit innerhalb des Bytes ist dieses Pixel? */
if (line[x] != ' ') /* Kein Leerzeichen --> Bit auf 1 setzen */
buffer[i] |= 0x80 >> b; /* MSB first. LSB first wäre 1 << b. */
}
for (int i = 0; i < pbm_bytes; i++) /* Puffer in Datei ausgeben */
fprintf (pbm_file, "%c", buffer[i]);
}
void pbm_close (void)
{
if (!pbm_file)
error (1, 0, "pbm_close(): PBM file not open");
if (line_no < pbm_height)
error (1, 0, "pbm_close(): too few lines");
fclose (pbm_file);
}
int main (void)
{
pbm_open (14, 14, "test.pbm");
pbm_line (" ");
pbm_line (" XXXXXX ");
pbm_line (" X X ");
pbm_line (" X X ");
pbm_line (" X X ");
pbm_line (" X XX XX X ");
pbm_line (" X X X X ");
pbm_line (" X X ");
pbm_line (" X X X X ");
pbm_line (" X X X X ");
pbm_line (" X XXXX X ");
pbm_line (" X X ");
pbm_line (" XXXXXX ");
pbm_line (" ");
pbm_close ();
return 0;
}
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <error.h>
/* Die Aufgabe besteht darin, die Funktionen pbm_open(),
* pbm_line() und pbm_close() zu schreiben.
*/
int pbm_width = 0;
int pbm_height = 0;
int line_no = 0;
FILE *pbm_file = NULL; /* globale Variable für die PBM-Datei */
void pbm_open (int width, int height, char *filename)
{
pbm_file = fopen (filename, "w");
if (!pbm_file)
error (errno, errno, "pbm_open(): cannot open file %s for writing", filename);
pbm_width = width;
pbm_height = height;
fprintf (pbm_file, "P4\n%d %d\n", pbm_width, pbm_height);
}
void pbm_line (char *line)
{
if (!pbm_file)
error (1, 0, "pbm_line(): PBM file not open");
if (!line)
error (1, 0, "pbm_line(): line is NULL");
if (strlen (line) != pbm_width)
error (1, 0, "pbm_line(): line length does not match width");
if (line_no >= pbm_height)
error (1, 0, "pbm_line(): too many lines");
int pbm_bytes = (pbm_width + 7) / 8; /* benötigte Bytes pro Zeile (immer aufrunden) */
uint8_t buffer[pbm_bytes];
for (int i = 0; i < pbm_bytes; i++) /* Puffer auf 0 initialisieren */
buffer[i] = 0;
line_no++;
for (int x = 0; line[x]; x++)
{
int i = x / 8; /* In welches Byte des Puffers gehört dieses Pixel? */
int b = x % 8; /* Welches Bit innerhalb des Bytes ist dieses Pixel? */
if (line[x] != ' ') /* Kein Leerzeichen --> Bit auf 1 setzen */
buffer[i] |= 1 << b;
}
for (int i = 0; i < pbm_bytes; i++) /* Puffer in Datei ausgeben */
fprintf (pbm_file, "%c", buffer[i]);
}
void pbm_close (void)
{
if (!pbm_file)
error (1, 0, "pbm_close(): PBM file not open");
if (line_no < pbm_height)
error (1, 0, "pbm_close(): too few lines");
fclose (pbm_file);
}
int main (void)
{
pbm_open (14, 14, "test.pbm");
pbm_line (" ");
pbm_line (" XXXXXX ");
pbm_line (" X X ");
pbm_line (" X X ");
pbm_line (" X X ");
pbm_line (" X XX XX X ");
pbm_line (" X X X X ");
pbm_line (" X X ");
pbm_line (" X X X X ");
pbm_line (" X X X X ");
pbm_line (" X XXXX X ");
pbm_line (" X X ");
pbm_line (" XXXXXX ");
pbm_line (" ");
pbm_close ();
return 0;
}
#include <stdio.h>
int fak (int n)
{
int f = 1;
for (int i = 2; i <= n; i++)
f *= i;
return f;
}
int main (void)
{
for (int n = 0; n <= 5; n++)
printf ("%d\n", fak (n));
return 0;
}
../common/logo-hochschule-bochum-cvh-text-v2.pdf
\ No newline at end of file
../common/logo-hochschule-bochum.pdf
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment