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

Vorbereitung 12.12.2022

parent b89b1037
Branches
No related tags found
No related merge requests found
Showing
with 1812 additions and 0 deletions
#include <gtk/gtk.h>
#define WIDTH 320
#define HEIGHT 240
double t = 0.0;
double dt = 0.2;
int r = 5;
double x = 10;
double y = 200;
double vx = 20;
double vy = -60;
double g = 9.81;
gboolean draw (GtkWidget *widget, cairo_t *c, gpointer data)
{
GdkRGBA blue = { 0.0, 0.5, 1.0, 1.0 };
gdk_cairo_set_source_rgba (c, &blue);
cairo_arc (c, x, y, r, 0, 2 * G_PI);
cairo_fill (c);
return FALSE;
}
gboolean timer (GtkWidget *widget)
{
t += dt;
x += vx * dt;
y += vy * dt;
vx = vx;
vy = 0.5 * g * (t * t);
if (y + r >= HEIGHT)
vy = -vy * 0.9;
if (x + r >= WIDTH)
vx = -vx * 0.9;
if (x - r <= 0)
vx = -vx * 0.9;
gtk_widget_queue_draw_area (widget, 0, 0, WIDTH, HEIGHT);
g_timeout_add (50, (GSourceFunc) timer, widget);
return FALSE;
}
int main (int argc, char **argv)
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_show (window);
gtk_window_set_title (GTK_WINDOW (window), "Hello");
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
GtkWidget *drawing_area = gtk_drawing_area_new ();
gtk_widget_show (drawing_area);
gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_widget_set_size_request (drawing_area, WIDTH, HEIGHT);
gtk_main ();
return 0;
}
#include <string.h>
int fun_1 (char *s)
{
int x = 0;
for (int i = 0; i < strlen (s); i++)
x += s[i];
return x;
}
int fun_2 (char *s)
{
int i = 0, x = 0;
int len = strlen (s);
while (i < len)
x += s[i++];
return x;
}
#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
20221212/aufgabe-3.png

162 B

../common/hello-gtk.png
\ No newline at end of file
File added
This diff is collapsed.
File added
% hp-musterloesung-20221212.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: Länge von Strings (Neuauflage), Text-Grafik-Bibliothek, PBM-Grafik
\documentclass[a4paper]{article}
\usepackage{pgscript}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- 12.\ Dezember 2022}
\exercise{Länge von Strings}
Diese Aufgabe ist eine Neuauflage von Aufgabe 2 der
Übung vom 7.\ November 2022,\\
ergänzt um die Teilaufgaben (f) und (g).
\medskip
Strings werden in der Programmiersprache C durch Zeiger auf \lstinline{char}-Variable realisiert.
Beispiel: \lstinline{char *hello_world = "Hello, world!\n"}
Die Systembibliothek stellt eine Funktion \lstinline{strlen()} zur Ermittlung der Länge von Strings\\
zur Verfügung (\lstinline{#include <string.h>}).
\begin{enumerate}[\quad(a)]
\item
Auf welche Weise ist die Länge eines Strings gekennzeichnet?
\points{1}
\item
Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"},
und wieviel Speicherplatz belegt sie?\\
\points{2}
\item
Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)},
die die Länge eines Strings zurückgibt.\\
\points{3}
\end{enumerate}
\goodbreak
Wir betrachten nun die folgenden Funktionen (Datei: \gitfile{hp}{2022ws/20221212}{aufgabe-2.c}):
\begin{center}
\begin{minipage}{8cm}
\begin{lstlisting}[gobble=8]
int fun_1 (char *s)
{
int x = 0;
for (int i = 0; i < strlen (s); i++)
x += s[i];
return x;
}
\end{lstlisting}
\end{minipage}%
\begin{minipage}{6cm}
\vspace*{-1cm}
\begin{lstlisting}[gobble=8]
int fun_2 (char *s)
{
int i = 0, x = 0;
int len = strlen (s);
while (i < len)
x += s[i++];
return x;
}
\end{lstlisting}
\vspace*{-1cm}
\end{minipage}
\end{center}
\begin{enumerate}[\quad(a)]\setcounter{enumi}{3}
\item
Was bewirken die beiden Funktionen?
\points{2}
\item
Schreiben Sie eine eigene Funktion,
die dieselbe Aufgabe erledigt wie \lstinline{fun_2()},\\
nur effizienter.
\points{4}
\item
Von welcher Ordnung (Landau-Symbol) sind die beiden Funktionen
hinsichtlich der Anzahl ihrer Zugriffe auf die Zeichen im String?
Begründen Sie Ihre Antwort.
Sie dürfen für \lstinline{strlen()} Ihre eigene Version der Funktion voraussetzen.
\points{3}
\item
Von welcher Ordnung (Landau-Symbol) ist Ihre effizientere Funktion?\\
Begründen Sie Ihre Antwort.
\points{1}
\end{enumerate}
\solution
\begin{itemize}
\item[(a)]
\textbf{Auf welche Weise ist die Länge eines Strings gekennzeichnet?}
Ein String ist ein Array von \lstinline{char}s.
Nach den eigentlichen Zeichen des Strings enthält das Array
\textbf{ein Null-Symbol} (Zeichen mit Zahlenwert 0,
nicht zu verwechseln mit der Ziffer \lstinline{'0'}) als Ende-Markierung.
Die Länge eines Strings ist die Anzahl der Zeichen
\emph{vor\/} diesem Symbol.
\item[(b)]
{\bf Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"},
und wieviel Speicherplatz belegt sie?}
Sie ist 14 Zeichen lang (\lstinline{'\n'} ist nur 1 Zeichen;
das Null-Symbol, das das Ende markiert, zählt hier nicht mit)
und belegt Speicherplatz für 15 Zeichen
(15 Bytes -- einschließlich Null-Symbol / Ende-Markierung).
\item[(c)]
\textbf{Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)},
die die Länge eines Strings zurückgibt.}
Siehe die Dateien \gitfile{hp}{2022ws/20221212}{loesung-2c-1.c} (mit Array-Index)
und \gitfile{hp}{2022ws/20221212}{loesung-2c-2.c} (mit Zeiger-Arithmetik).
Beide Lösungen sind korrekt und arbeiten gleich schnell.
Die Warnung \lstinline[style=terminal]{conflicting types for built-in function "strlen"}
kann normalerweise ignoriert werden;
auf manchen Systemen (z.\,B.\ MinGW) hat jedoch die eingebaute Funktion \lstinline{strlen()}
beim Linken Vorrang vor der selbstgeschriebenen,
so daß die selbstgeschriebene Funktion nie aufgerufen wird.
In solchen Fällen ist es zulässig, die selbstgeschriebene Funktion
anders zu nennen (z.\,B.\ \lstinline{my_strlen()}).
\item[(d)]
\textbf{Was bewirken die beiden Funktionen?}
Beide addieren die Zahlenwerte der im String enthaltenen Zeichen
und geben die Summe als Funktionsergebnis zurück.
Im Falle des Test-Strings \lstinline{"Hello, world!\n"}
lautet der Rückgabewert 1171 (siehe \gitfile{hp}{2022ws/20221212}{loesung-2d-1.c} und \gitfile{hp}{2022ws/20221212}{loesung-2d-2.c}).
\item[(e)]
\textbf{Schreiben Sie eine eigene Funktion,
die dieselbe Aufgabe erledigt wie \lstinline{fun_2()},
nur effizienter.}
Die Funktion wird effizienter,
wenn man auf den Aufruf von \lstinline{strlen()} verzichtet
und stattdessen die Ende-Prüfung in derselben Schleife vornimmt,
in der man auch die Zahlenwerte der Zeichen des Strings aufsummiert.
Die Funktion \lstinline{fun_3()} in der Datei \gitfile{hp}{2022ws/20221212}{loesung-2e-1.c}
realisiert dies mit einem Array-Index,
Die Funktion \lstinline{fun_4()} in der Datei \gitfile{hp}{2022ws/20221212}{loesung-2e-2.c}
mit Zeiger-Arithmetik.
Beide Lösungen sind korrekt und arbeiten gleich schnell.
\textbf{Bemerkung:} Die effizientere Version der Funktion
arbeitet doppelt so schnell wie die ursprüngliche,
hat aber ebenfalls die Ordnung $\mathcal{O}(n)$ -- siehe unten.
\item[(f)]
\textbf{Von welcher Ordnung (Landau-Symbol) sind die beiden Funktionen
hinsichtlich der Anzahl ihrer Zugriffe auf die Zeichen im String?
Begründen Sie Ihre Antwort.
Sie dürfen für \lstinline{strlen()} Ihre eigene Version der Funktion voraussetzen.}
Vorüberlegung: \lstinline{strlen()} greift in einer Schleife
auf alle Zeichen des Strings der Länge $n$ zu,
hat also $\mathcal{O}(n)$.
\lstinline{fun_1()} ruft in jedem Schleifendurchlauf
(zum Prüfen der \lstinline{while}-Bedingung) einmal \lstinline{strlen()} auf
und greift anschließend auf ein Zeichen des Strings zu,
hat also $\mathcal{O}\bigl(n\cdot(n+1)\bigr) = \mathcal{O}(n^2)$.
\lstinline{fun_2()} ruft einmalig \lstinline{strlen()} auf
und greift anschließend in einer Schleife auf alle Zeichen des Strings zu,
hat also $\mathcal{O}(n+n) = \mathcal{O}(n)$.
\item[(g)]
\textbf{Von welcher Ordnung (Landau-Symbol) ist Ihre effizientere Funktion?\\
Begründen Sie Ihre Antwort.}
In beiden o.\,a.\ Lösungsvarianten
-- \gitfile{hp}{2022ws/20221212}{loesung-2e-1.c}
und \gitfile{hp}{2022ws/20221212}{loesung-2e-2.c} --
arbeitet die Funktion mit einer einzigen Schleife,
die gleichzeitig die Zahlenwerte addiert und das Ende des Strings sucht.
Mit jeweils einer einzigen Schleife
haben beide Funktionen die Ordnung $\mathcal{O}(n)$.
\end{itemize}
\exercise{Text-Grafik-Bibliothek}
Schreiben Sie eine Bibliothek für "`Text-Grafik"' mit folgenden Funktionen:\vspace*{-\medskipamount}
\begin{itemize}
\item
\lstinline|void clear (char c)|\\
Bildschirm auf Zeichen \lstinline|c| löschen,\\
also komplett mit diesem Zeichen (z.\,B.: Leerzeichen) füllen
\item
\lstinline|void put_point (int x, int y, char c)|\\
Punkt setzen (z.\,B.\ einen Stern (\lstinline{*}) an die Stelle $(x,y)$ "`malen"')
\item
\lstinline|char get_point (int x, int y)|\\
Punkt lesen
% \item
% \lstinline|void fill (int x, int y, char c, char o)|\\
% Fläche in der "`Farbe"' \lstinline|o|,
% die den Punkt \lstinline|(x, y)| enthält,
% mit der "`Farbe"' \lstinline|c| ausmalen
\item
\lstinline|void display (void)|\\
das Gezeichnete auf dem Bildschirm ausgeben
\end{itemize}
\goodbreak
Hinweise:\vspace*{-\medskipamount}
\begin{itemize}
\item
Eine C-Bibliothek besteht aus (mindestens)
einer \file{.h}-Datei und einer \file{.c}-Datei.
\item
Verwenden Sie ein Array als "`Bildschirm"'.
Vor dem Aufruf der Funktion \lstinline|display()| ist nichts zu sehen;\\
alle Grafikoperationen erfolgen auf dem Array.
\item
Verwenden Sie Präprozessor-Konstante,
z.\,B.\ \lstinline{WIDTH} und \lstinline{HEIGHT},\\
um Höhe und Breite des "`Bildschirms"' festzulegen:
\begin{lstlisting}[gobble=8]
#define WIDTH 72
#define HEIGHT 24
\end{lstlisting}
\item
Schreiben Sie zusätzlich ein Test-Programm,
das alle Funktionen der Bibliothek benutzt,\\
um ein hübsches Bild (z.\,B.\ ein stilisiertes Gesicht -- "`Smiley"')
auszugeben.
\end{itemize}
\points{8}
\solution
Siehe die Dateien \gitfile{hp}{2022ws/20221212}{textgraph.c} und \gitfile{hp}{2022ws/20221212}{textgraph.h} (Bibliothek)
sowie \gitfile{hp}{2022ws/20221212}{test-textgraph.c} (Test-Programm).
Diese Lösung erfüllt zusätzlich die Aufgabe,
bei fehlerhafter Benutzung (Koordinaten außerhalb des Zeichenbereichs)
eine sinnvolle Fehlermeldung auszugeben,
anstatt unkontrolliert Speicher zu überschreiben und abzustürzen.
Das Schlüsselwort \lstinline{static}
bei der Deklaration der Funktion \lstinline{check_coordinates()}
bedeutet, daß diese Funktion nur lokal (d.\,h.\ innerhalb der Bibliothek)
verwendet und insbesondere nicht nach außen
(d.\,h.\ für die Benutzung durch das Hauptprogramm) exportiert wird.
Dies dient dazu, nicht unnötig Bezeichner zu reservieren
(Vermeidung von "`Namensraumverschmutzung"').
Man beachte die Verwendung einfacher Anführungszeichen (Apostrophe)
bei der Angabe von \lstinline{char}-Kon"-stanten (\lstinline{'*'})
im Gegensatz zur Verwendung doppelter Anführungszeichen
bei der Angabe von String-Konstanten
(String = Array von \lstinline{char}s, abgeschlossen mit Null-Symbol).
Um das einfache Anführungszeichen selbst als \lstinline{char}-Konstante anzugeben,
ist ein vorangestellter Backslash erforderlich: \lstinline{'\''} ("`Escape-Sequenz"').
Entsprechendes gilt für die Verwendung doppelter Anführungszeichen
innerhalb von String-Konstanten:
\lstinline{printf ("Your name is: \"%s\"", name);}
\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}{2022ws/20221212}{aufgabe-3.pbm}):\hfill
\makebox(0,0)[tr]{\framebox{\includegraphics[scale=3]{aufgabe-3.png}}}
\begin{lstlisting}
P4
14 14
<Bilddaten>
\end{lstlisting}
In dem untenstehenden Programmfragment (\gitfile{hp}{2022ws/20221212}{aufgabe-3.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}{2022ws/20221212}{aufgabe-3.pbm}
mit dem gewünschten Ergebnis bei,\\
und die Datei \gitfile{hp}{2022ws/20221212}{aufgabe-3.png} enthält dasselbe Bild.
\points{10}
\solution
Die Datei \gitfile{hp}{2022ws/20221212}{loesung-3.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}{2022ws/20221212}{loesung-3f.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.
\end{document}
File added
% hp-uebung-20221212.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: Länge von Strings (Neuauflage), Text-Grafik-Bibliothek, PBM-Grafik
% ? Hüpfender Ball (20211206-3)
% ! Text-Grafik-Bibliothek (20211213-2)
% ! PBM-Grafik (20211213-3)
% ! Länge von Strings (Neuauflage) (20211220-2)
% ? Hexdumps (20220110-3)
% ? einfach und doppelt verkettete Listen (20220117-2)
% ? ternärer Baum (20220117-3)
\documentclass[a4paper]{article}
\usepackage{pgscript}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Übungsaufgaben -- 12.\ Dezember 2022}
Diese Übung enthält Punkteangaben wie in einer Klausur.
Um zu "`bestehen"', müssen Sie innerhalb von 100 Minuten
unter Verwendung ausschließlich zugelassener Hilfsmittel
17 Punkte (von insgesamt \totalpoints) erreichen.
\exercise{Länge von Strings}
Diese Aufgabe ist eine Neuauflage von Aufgabe 2 der
Übung vom 7.\ November 2022,\\
ergänzt um die Teilaufgaben (f) und (g).
\medskip
Strings werden in der Programmiersprache C durch Zeiger auf \lstinline{char}-Variable realisiert.
Beispiel: \lstinline{char *hello_world = "Hello, world!\n"}
Die Systembibliothek stellt eine Funktion \lstinline{strlen()} zur Ermittlung der Länge von Strings\\
zur Verfügung (\lstinline{#include <string.h>}).
\begin{enumerate}[\quad(a)]
\item
Auf welche Weise ist die Länge eines Strings gekennzeichnet?
\points{1}
\item
Wie lang ist die Beispiel-String-Konstante \lstinline{"Hello, world!\n"},
und wieviel Speicherplatz belegt sie?\\
\points{2}
\item
Schreiben Sie eine eigene Funktion \lstinline{int strlen (char *s)},
die die Länge eines Strings zurückgibt.\\
\points{3}
\end{enumerate}
\goodbreak
Wir betrachten nun die folgenden Funktionen (Datei: \gitfile{hp}{2022ws/20221212}{aufgabe-2.c}):
\begin{center}
\begin{minipage}{8cm}
\begin{lstlisting}[gobble=8]
int fun_1 (char *s)
{
int x = 0;
for (int i = 0; i < strlen (s); i++)
x += s[i];
return x;
}
\end{lstlisting}
\end{minipage}%
\begin{minipage}{6cm}
\vspace*{-1cm}
\begin{lstlisting}[gobble=8]
int fun_2 (char *s)
{
int i = 0, x = 0;
int len = strlen (s);
while (i < len)
x += s[i++];
return x;
}
\end{lstlisting}
\vspace*{-1cm}
\end{minipage}
\end{center}
\begin{enumerate}[\quad(a)]\setcounter{enumi}{3}
\item
Was bewirken die beiden Funktionen?
\points{2}
\item
Schreiben Sie eine eigene Funktion,
die dieselbe Aufgabe erledigt wie \lstinline{fun_2()},\\
nur effizienter.
\points{4}
\item
Von welcher Ordnung (Landau-Symbol) sind die beiden Funktionen
hinsichtlich der Anzahl ihrer Zugriffe auf die Zeichen im String?
Begründen Sie Ihre Antwort.
Sie dürfen für \lstinline{strlen()} Ihre eigene Version der Funktion voraussetzen.
\points{3}
\item
Von welcher Ordnung (Landau-Symbol) ist Ihre effizientere Funktion?\\
Begründen Sie Ihre Antwort.
\points{1}
\end{enumerate}
\clearpage
\exercise{Text-Grafik-Bibliothek}
Schreiben Sie eine Bibliothek für "`Text-Grafik"' mit folgenden Funktionen:\vspace*{-\medskipamount}
\begin{itemize}
\item
\lstinline|void clear (char c)|\\
Bildschirm auf Zeichen \lstinline|c| löschen,\\
also komplett mit diesem Zeichen (z.\,B.: Leerzeichen) füllen
\item
\lstinline|void put_point (int x, int y, char c)|\\
Punkt setzen (z.\,B.\ einen Stern (\lstinline{*}) an die Stelle $(x,y)$ "`malen"')
\item
\lstinline|char get_point (int x, int y)|\\
Punkt lesen
% \item
% \lstinline|void fill (int x, int y, char c, char o)|\\
% Fläche in der "`Farbe"' \lstinline|o|,
% die den Punkt \lstinline|(x, y)| enthält,
% mit der "`Farbe"' \lstinline|c| ausmalen
\item
\lstinline|void display (void)|\\
das Gezeichnete auf dem Bildschirm ausgeben
\end{itemize}
Hinweise:\vspace*{-\medskipamount}
\begin{itemize}
\item
Eine C-Bibliothek besteht aus (mindestens)
einer \file{.h}-Datei und einer \file{.c}-Datei.
\item
Verwenden Sie ein Array als "`Bildschirm"'.
Vor dem Aufruf der Funktion \lstinline|display()| ist nichts zu sehen;\\
alle Grafikoperationen erfolgen auf dem Array.
\item
Verwenden Sie Präprozessor-Konstante,
z.\,B.\ \lstinline{WIDTH} und \lstinline{HEIGHT},\\
um Höhe und Breite des "`Bildschirms"' festzulegen:
\begin{lstlisting}[gobble=8]
#define WIDTH 72
#define HEIGHT 24
\end{lstlisting}
\item
Schreiben Sie zusätzlich ein Test-Programm,
das alle Funktionen der Bibliothek benutzt,\\
um ein hübsches Bild (z.\,B.\ ein stilisiertes Gesicht -- "`Smiley"')
auszugeben.
\end{itemize}
\points{8}
\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}{2022ws/20221212}{aufgabe-3.pbm}):\hfill
\makebox(0,0)[tr]{\framebox{\includegraphics[scale=3]{aufgabe-3.png}}}
\begin{lstlisting}
P4
14 14
<Bilddaten>
\end{lstlisting}
In dem untenstehenden Programmfragment (\gitfile{hp}{2022ws/20221212}{aufgabe-3.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}{2022ws/20221212}{aufgabe-3.pbm}
mit dem gewünschten Ergebnis bei,\\
und die Datei \gitfile{hp}{2022ws/20221212}{aufgabe-3.png} enthält dasselbe Bild.
\points{10}
\begin{flushright}
\textit{Viel Erfolg!}
\end{flushright}
\makeatletter
\immediate\write\@mainaux{\string\gdef\string\totalpoints{\arabic{points}}}
\makeatother
\end{document}
#include <stdio.h>
int strlen (char *s)
{
int l = 0;
while (s[l])
l++;
return l;
}
int main (void)
{
printf ("%d\n", strlen ("Hello, world!\n"));
return 0;
}
#include <stdio.h>
int strlen (char *s)
{
char *s0 = s;
while (*s)
s++;
return s - s0;
}
int main (void)
{
printf ("%d\n", strlen ("Hello, world!\n"));
return 0;
}
#include <stdio.h>
int strlen (char *s)
{
int l = 0;
while (s[l])
l++;
return l;
}
int fun_1 (char *s)
{
int x = 0;
for (int i = 0; i < strlen (s); i++)
x += s[i];
return x;
}
int fun_2 (char *s)
{
int i = 0, x = 0;
int len = strlen (s);
while (i < len)
x += s[i++];
return x;
}
int main (void)
{
printf ("%d\n", fun_1 ("Hello, world!\n"));
printf ("%d\n", fun_2 ("Hello, world!\n"));
return 0;
}
#include <stdio.h>
int strlen (char *s)
{
char *s0 = s;
while (*s)
s++;
return s - s0;
}
int fun_1 (char *s)
{
int x = 0;
for (int i = 0; i < strlen (s); i++)
x += s[i];
return x;
}
int fun_2 (char *s)
{
int i = 0, x = 0;
int len = strlen (s);
while (i < len)
x += s[i++];
return x;
}
int main (void)
{
printf ("%d\n", fun_1 ("Hello, world!\n"));
printf ("%d\n", fun_2 ("Hello, world!\n"));
return 0;
}
#include <stdio.h>
int fun_3 (char *s)
{
int i = 0, x = 0;
while (s[i])
x += s[i++];
return x;
}
int main (void)
{
printf ("%d\n", fun_3 ("Hello, world!\n"));
return 0;
}
#include <stdio.h>
int fun_4 (char *s)
{
int x = 0;
while (*s)
x += *s++;
return x;
}
int main (void)
{
printf ("%d\n", fun_4 ("Hello, world!\n"));
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] |= 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;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment