diff --git a/20191017/hp-musterloesung-20191017.pdf b/20191017/hp-musterloesung-20191017.pdf new file mode 100644 index 0000000000000000000000000000000000000000..38060c39b7bf1fd78f53a2173883e32c7aeb5b09 Binary files /dev/null and b/20191017/hp-musterloesung-20191017.pdf differ diff --git a/20191017/hp-musterloesung-20191017.tex b/20191017/hp-musterloesung-20191017.tex new file mode 100644 index 0000000000000000000000000000000000000000..dceca2f3abeb745cd10938ca5d27d6e43c028dcd --- /dev/null +++ b/20191017/hp-musterloesung-20191017.tex @@ -0,0 +1,326 @@ +% hp-musterloesung-20191017.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences +% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019 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: Schaltjahr ermitteln, Multiplikationstabelle, Fibonacci-Zahlen, fehlerhaftes Programm + +\documentclass[a4paper]{article} + +\usepackage{pgscript} + +\begin{document} + + \section*{Hardwarenahe Programmierung\\ + Musterlösung zu den Übungsaufgaben -- 17.\ Oktober 2019} + + \exercise{Schaltjahr ermitteln} + + Schreiben Sie ein C-Programm, das eine Jahreszahl erfragt + und ausgibt, ob es sich um ein Schaltjahr handelt. + \begin{itemize} + \item Wenn die Jahreszahl durch 4 teilbar ist, ist das Jahr zunächst einmal ein Schaltjahr. + \item Ausnahme: Wenn die Jahreszahl durch 100 teilbar ist, ist das Jahr kein Schaltjahr. + \item Ausnahme von der Ausnahme: Wenn die Jahreszahl durch 400 teilbar ist,\\ + ist das Jahr doch wieder ein Schaltjahr. + \end{itemize} + + \solution + + Am einfachsten ist es, die Aufgabenstellung in geschachtelte + \lstinline{if}-Verzweigungen zu übersetzen. + Im folgenden finden Sie eine Funktion \lstinline{is_leap_year()}, + der man das Jahr übergibt und die für Schaltjahre \lstinline{1} + zurückgibt und für Nicht-Schaltjahre \lstinline{0}. + \begin{lstlisting} + #include <stdio.h> + + int is_leap_year (int year) + { + int leap_year = 0; + if (year % 4 == 0) + { + leap_year = 1; + if (year % 100 == 0) + { + leap_year = 0; + if (year % 400 == 0) + leap_year = 1; + } + } + return leap_year; + } + \end{lstlisting} + (In C steht \lstinline{0} für den Wahrheitswert "`falsch"' + und jeder Wert ungleich \lstinline{0} für den Wahrheitswert "`wahr'"; + die Zeile \lstinline{leap_year = 0} steht daher wörtlich und + selbsterklärend für "`ist kein Schaltjahr"'.) + + Unter Verwendung von \lstinline{else} läßt sich dies verkürzen zu: + \begin{lstlisting} + #include <stdio.h> + + int is_leap_year (int year) + { + if (year % 4 == 0) + { + if (year % 100 == 0) + { + if (year % 400 == 0) + return 1; + else + return 0; + } + else + return 1; + } + else + return 0; + } + \end{lstlisting} + + Eine andere Möglichkeit ist es, die Schaltjahr-Bedingung in eine + Kette von "`und"'- und "`oder"'-Verknüpfungen + (C-Operatoren \lstinline{&&} und \lstinline{||}) zu übersetzen: + \begin{lstlisting} + int is_leap_year (int year) + { + if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) + return 1; + else + return 0; + } + \end{lstlisting} + Dies ist zwar kürzer, aber nicht unbedingt übersichtlicher. + Der erzeugte Code ist übrigens \emph{nicht\/} kürzer und/oder + effizienter als bei der Verwendung mehrerer + \lstinline{if}-Verzweigungen. + Wir empfehlen, daß Sie immer so programmieren, + daß Sie selbst den maximalen Überblick über Ihr Programm behalten. + + \goodbreak + + Ein Hauptprogramm, das die o.\,a.\ Funktion aufruft, + könnte dann wie folgt aussehen: + \begin{lstlisting} + int main (void) + { + int year; + printf ("Bitte geben Sie eine Jahreszahl ein: "); + scanf ("%d", &year); + if (is_leap_year (year)) + printf ("Das Jahr %d ist ein Schaltjahr.\n", year); + else + printf ("Das Jahr %d ist kein Schaltjahr.\n", year); + return 0; + } + \end{lstlisting} + In den Dateien \gitfile{hp}{20191017}{loesung-1-1.c} bis \gitfile{hp}{20191017}{loesung-1-3.c} + finden Sie lauffähige Programme, die die o.\,a.\ Funktionen aufrufen. + Beachten Sie, daß die Funktion \emph{vor\/} dem Hauptprogramm + deklariert werden muß, damit das Hauptprogramm sie kennt. + (Es gibt Tricks, mit denen es auch anders geht, + aber was hätten wir in diesem Zusammenhang davon?) + + In \gitfile{hp}{20191017}{loesung-1-4.c} und \gitfile{hp}{20191017}{loesung-1-5.c} + findet die Schaltjahr-Prüfung direkt im Hauptprogramm statt. + Dies ist ebenfalls eine richtige Lösung der Aufgabe, + schränkt aber die Wiederverwertbarkeit des Codes ein. + + Die Datei \gitfile{hp}{20191017}{loesung-1-4.c} enthält darüberhinaus Codeverdopplungen, + nämlich mehrere identische \lstinline{printf()}-Auf"-rufe + an unterschiedlichen Stellen. + Dies ist schlechter Programmierstil ("`Cut-and-paste-Programmierung"'). + + Die besten Lösungen sind \gitfile{hp}{20191017}{loesung-1-2.c} + und \gitfile{hp}{20191017}{loesung-1-3.c}. + + \goodbreak + + Zum Testen:\vspace*{-\medskipamount} + \begin{itemize}\itemsep0pt + \item 1900 ist kein Schaltjahr. + \item 1902 ist kein Schaltjahr. + \item 1904 ist ein Schaltjahr. + \item 1996 ist ein Schaltjahr. + \item 1998 ist kein Schaltjahr. + \item 2000 ist ein Schaltjahr. + \item 2002 ist kein Schaltjahr. + \item 2004 ist ein Schaltjahr. + \item 2016 ist ein Schaltjahr. + \item 2017 ist kein Schaltjahr. + \item 2018 ist kein Schaltjahr. + \item 2019 ist kein Schaltjahr. + \end{itemize} + + \goodbreak + + Hier noch ein Hinweis für Unix-Shell-Experten: + \begin{lstlisting}[style=cmd] + for y in 1 2 3 4 5; do + clear + for x in 1900 1902 1904 1996 1998 2000 2002 2004 2016 2017 2018 2019; do + echo $x | ./loesung-1-$y + done + sleep 2s + done + \end{lstlisting} + + \exercise{Multiplikationstabelle} + + Geben Sie mit Hilfe einer Schleife ein "`Einmaleins"' aus.\\ + Dabei sollen die Faktoren und Ergebnisse rechtsbündig untereinander stehen: + \begin{lstlisting}[style=terminal] + 1 * 7 = 7 + 2 * 7 = 14 + ... + 10 * 7 = 70 + \end{lstlisting} + Hinweis: Verwenden Sie Formatspezifikationen wie z.\,B.\ \lstinline{%3d}\\ + (siehe dazu die Dokumentation zu \lstinline{printf()}, + z.\,B.\ \,\lstinline[style=cmd]{man 3 printf}\,) + + \solution + + Drei verschiedene richtige Lösungen finden Sie in den Dateien + \gitfile{hp}{20191017}{loesung-2-1.c}, \gitfile{hp}{20191017}{loesung-2-2.c} und \gitfile{hp}{20191017}{loesung-2-3.c}. + (Zum Compilieren von \gitfile{hp}{20191017}{loesung-2-2.c} und \gitfile{hp}{20191017}{loesung-2-3.c} + ist mindestens der C99-Standard erforderlich; bitte nötigenfalls + in \file{gcc} die Option \lstinline[style=cmd]{-std=c99} mit angeben.) + + Die Lösung in \gitfile{hp}{20191017}{loesung-2-3.c} ist zwar richtig, + aber unnötig kompliziert und daher nicht empfohlen. + + Eine \textbf{falsche} Lösung finden Sie in der Datei \gitfile{hp}{20191017}{loesung-2-f4.c}: + In der Ausgabe dieses Programms stehen die Faktoren und Ergebnisse + nicht rechtsbündig untereinander. + + \exercise{Fibonacci-Zahlen} + + Die Folge der Fibonacci-Zahlen ist definiert durch: + \begin{quote} + 1.\ Zahl: 0\\ + 2.\ Zahl: 1\\ + nächste Zahl = Summe der beiden vorherigen + \end{quote} + Schreiben Sie ein Programm, das die ersten 50 Fibonacci-Zahlen ausgibt. + + Falls Ihnen dabei irgendwelche Besonderheiten auffallen + und/oder Sie irgendwelche besondere Maßnahmen treffen, + dokumentieren Sie diese. + + (Wem dies zu einfach ist, kann auch gerne + die ersten 100 Fibonacci-Zahlen ausgeben.) + + \solution + + Zwei verschiedene richtige Lösungen finden Sie in den Dateien + \gitfile{hp}{20191017}{loesung-3-1.c} und \gitfile{hp}{20191017}{loesung-3-2.c}. + + Die Lösung in \gitfile{hp}{20191017}{loesung-3-2.c} + speichert alle berechneten Zahlen in einem Array, + die in \gitfile{hp}{20191017}{loesung-3-1.c} hingegen + speichert immer nur maximal drei Zahlen gleichzeitig. + Sofern nicht alle berechneten Zahlen später noch benötigt werden, + ist daher \gitfile{hp}{20191017}{loesung-3-1.c} zu bevorzugen. + + Wichtig in \gitfile{hp}{20191017}{loesung-3-1.c} ist, daß \lstinline{f0 + f1} berechnet wird, + \emph{bevor\/} \lstinline{f0} oder \lstinline{f1} ein neuer Wert zugewiesen wird. + Dies ist nur möglich, weil das Programm + eine zusätzliche Variable (hier: \lstinline{f2}) verwendet. + + \emph{(Fortsetzung folgt.)} + + \exercise{Fehlerhaftes Programm} + + \begin{minipage}[t]{0.65\textwidth} + Wir betrachten das nebenstehende C-Programm + (Datei: \gitfile{hp}{20191017}{aufgabe-4.c}). + \begin{itemize} + \item[(a)] + Was bewirkt dieses Programm? Begründen Sie Ihre Antwort. + + Schreiben Sie Ihre Begründung so auf, + daß man sie auch dann versteht, + wenn man gerade nicht die Möglichkeit hat, + bei Ihnen persönlich nachzufragen + (z.\,B.\ weil man gerade eine Klausur korrigiert). + + Die Schwierigkeit dieser Aufgabe besteht + nicht allein darin, die Problematik zu verstehen, + sondern auch darin, dieses Verständnis für andere aufzuschreiben. + \item[(b)] + Ändern Sie das Programm so um, + daß es einen "`Countdown"' von 10 bis 0 ausgibt. + \end{itemize} + \end{minipage}\hfill + \begin{minipage}[t]{0.3\textwidth} + \begin{lstlisting}[gobble=6] + #include <stdio.h> + + int main (void) + { + for (int i = 10; i = 0; i - 1) + printf ("%d\n", i); + return 0; + } + \end{lstlisting} + \end{minipage} + + \solution + + \begin{itemize} + \item[(a)] + \textbf{Was bewirkt dieses Programm und warum?} + + Dieses Programm bewirkt nichts. + Die \lstinline{for}-Schleife wird nicht ausgeführt. + + Begründung: Die \lstinline{for}-Bedingung ist eine Zuweisung + des Werts \lstinline{0} an die Variable \lstinline{i}. + Neben dem Seiteneffekt der Zuweisung liefert der Ausdruck + einen Wert zurück, nämlich den zugewiesenen Wert + \lstinline{0}. Dieser wird von \lstinline{for} als eine + Bedingung mit dem konstanten Wert "`falsch"' interpretiert. + + (Hinweis: Ohne diese Begründung ist die Aufgabe nur zu einem + kleinen Teil gelöst.) + + Darüberhinaus ist die Zähl-Anwendung unwirksam: Sie berechnet + den Wert \lstinline{i - 1} und vergißt ihn wieder, ohne ihn + einer Variablen (z.\,B.\ \lstinline{i}) zuzuweisen. + + \item[(b)] + \textbf{Ändern Sie das Programm so, daß es einen "`Countdown"' von 10 bis 0 ausgibt.} + + Datei \gitfile{hp}{20191017}{loesung-4.c}: + \begin{lstlisting}[gobble=8] + #include <stdio.h> + + int main (void) + { + for (int i = 10; i >= 0; i--) + printf ("%d\n", i); + return 0; + } + \end{lstlisting} + \end{itemize} + +\end{document} diff --git a/20191017/hp-uebung-20191017.tex b/20191017/hp-uebung-20191017.tex index f8f7aa7dac9c5f3be9ce58056da79fb536e3729e..b12e97398c2c2375420c5512f318e903596b7071 100644 --- a/20191017/hp-uebung-20191017.tex +++ b/20191017/hp-uebung-20191017.tex @@ -26,8 +26,6 @@ \usepackage{pgscript} -\thispagestyle{empty} - \begin{document} \thispagestyle{empty} diff --git a/20191017/loesung-1-1.c b/20191017/loesung-1-1.c new file mode 100644 index 0000000000000000000000000000000000000000..ea41b8ea35bf871389c8be15779a58c293c81049 --- /dev/null +++ b/20191017/loesung-1-1.c @@ -0,0 +1,29 @@ +#include <stdio.h> + +int is_leap_year (int year) +{ + int leap_year = 0; + if (year % 4 == 0) + { + leap_year = 1; + if (year % 100 == 0) + { + leap_year = 0; + if (year % 400 == 0) + leap_year = 1; + } + } + return leap_year; +} + +int main (void) +{ + int year; + printf ("Bitte geben Sie eine Jahreszahl ein: "); + scanf ("%d", &year); + if (is_leap_year (year)) + printf ("Das Jahr %d ist ein Schaltjahr.\n", year); + else + printf ("Das Jahr %d ist kein Schaltjahr.\n", year); + return 0; +} diff --git a/20191017/loesung-1-2.c b/20191017/loesung-1-2.c new file mode 100644 index 0000000000000000000000000000000000000000..d9e4df8a36238875e0b46398b21f93e7f4f98792 --- /dev/null +++ b/20191017/loesung-1-2.c @@ -0,0 +1,31 @@ +#include <stdio.h> + +int is_leap_year (int year) +{ + if (year % 4 == 0) + { + if (year % 100 == 0) + { + if (year % 400 == 0) + return 1; + else + return 0; + } + else + return 1; + } + else + return 0; +} + +int main (void) +{ + int year; + printf ("Bitte geben Sie eine Jahreszahl ein: "); + scanf ("%d", &year); + if (is_leap_year (year)) + printf ("Das Jahr %d ist ein Schaltjahr.\n", year); + else + printf ("Das Jahr %d ist kein Schaltjahr.\n", year); + return 0; +} diff --git a/20191017/loesung-1-3.c b/20191017/loesung-1-3.c new file mode 100644 index 0000000000000000000000000000000000000000..97051b3bb5e6620ff771d6b3f5949687130abea8 --- /dev/null +++ b/20191017/loesung-1-3.c @@ -0,0 +1,21 @@ +#include <stdio.h> + +int is_leap_year (int year) +{ + if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) + return 1; + else + return 0; +} + +int main (void) +{ + int year; + printf ("Bitte geben Sie eine Jahreszahl ein: "); + scanf ("%d", &year); + if (is_leap_year (year)) + printf ("Das Jahr %d ist ein Schaltjahr.\n", year); + else + printf ("Das Jahr %d ist kein Schaltjahr.\n", year); + return 0; +} diff --git a/20191017/loesung-1-4.c b/20191017/loesung-1-4.c new file mode 100644 index 0000000000000000000000000000000000000000..3a0d218e6c03f326ad73bad55ad3e29ea882eb2d --- /dev/null +++ b/20191017/loesung-1-4.c @@ -0,0 +1,23 @@ +#include <stdio.h> + +int main (void) +{ + int year; + printf ("Bitte geben Sie eine Jahreszahl ein: "); + scanf ("%d", &year); + if (year % 4 == 0) + { + if (year % 100 == 0) + { + if (year % 400 == 0) + printf ("Das Jahr %d ist ein Schaltjahr.\n", year); + else + printf ("Das Jahr %d ist kein Schaltjahr.\n", year); + } + else + printf ("Das Jahr %d ist ein Schaltjahr.\n", year); + } + else + printf ("Das Jahr %d ist kein Schaltjahr.\n", year); + return 0; +} diff --git a/20191017/loesung-1-5.c b/20191017/loesung-1-5.c new file mode 100644 index 0000000000000000000000000000000000000000..999d9f2030e29f1c961b12d647d2e82592b637bf --- /dev/null +++ b/20191017/loesung-1-5.c @@ -0,0 +1,13 @@ +#include <stdio.h> + +int main (void) +{ + int year; + printf ("Bitte geben Sie eine Jahreszahl ein: "); + scanf ("%d", &year); + if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) + printf ("Das Jahr %d ist ein Schaltjahr.\n", year); + else + printf ("Das Jahr %d ist kein Schaltjahr.\n", year); + return 0; +} diff --git a/20191017/loesung-2-1.c b/20191017/loesung-2-1.c new file mode 100644 index 0000000000000000000000000000000000000000..5ec9dd3caf6639d22bf770ef4b6bb779a3d7c714 --- /dev/null +++ b/20191017/loesung-2-1.c @@ -0,0 +1,13 @@ +#include <stdio.h> + +int main (void) +{ + int a = 1; + int b = 7; + while (a <= 10) + { + printf ("%2d * %d = %2d\n", a, b, a * b); + a++; + } + return 0; +} diff --git a/20191017/loesung-2-2.c b/20191017/loesung-2-2.c new file mode 100644 index 0000000000000000000000000000000000000000..8f9319ee596a52f38531a2cefb376b54e7ec3ec0 --- /dev/null +++ b/20191017/loesung-2-2.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int main (void) +{ + int x = 7; + for (int i = 1; i <= 10; i++) + printf ("%2d *%2d =%3d\n", i, x, i * x); + return 0; +} diff --git a/20191017/loesung-2-3.c b/20191017/loesung-2-3.c new file mode 100644 index 0000000000000000000000000000000000000000..71fca2538b991397ac5f046a33ff0f9130b2980f --- /dev/null +++ b/20191017/loesung-2-3.c @@ -0,0 +1,21 @@ +#include <stdio.h> + +int main (void) +{ + int x = 7; + for (int i = 1; i <= 10; i++) + { + if (i >= 10) + printf ("%d", i); + else + printf (" %d", i); + printf (" * %d = ", x); + int y = i * x; + if (y >= 10) + printf ("%d", y); + else + printf (" %d", y); + printf ("\n"); + } + return 0; +} diff --git a/20191017/loesung-2-f4.c b/20191017/loesung-2-f4.c new file mode 100644 index 0000000000000000000000000000000000000000..8520d438f654856a74c22ffd01b9c5815741efbc --- /dev/null +++ b/20191017/loesung-2-f4.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int main (void) +{ + int x = 7; + for (int i = 1; i <= 10; i++) + printf ("%d * %d = %d\n", i, x, i * x); + return 0; +} diff --git a/20191017/loesung-3-1.c b/20191017/loesung-3-1.c new file mode 100644 index 0000000000000000000000000000000000000000..ec5f4d9f93985577246eefccdd0f6003403795ab --- /dev/null +++ b/20191017/loesung-3-1.c @@ -0,0 +1,15 @@ +#include <stdio.h> + +int main (void) +{ + int f0 = 0; + int f1 = 1; + for (int i = 0; i < 50; i++) + { + printf ("f[%d] = %d\n", i, f0); + int f2 = f0 + f1; + f0 = f1; + f1 = f2; + } + return 0; +} diff --git a/20191017/loesung-3-2.c b/20191017/loesung-3-2.c new file mode 100644 index 0000000000000000000000000000000000000000..7043f66e6b73894be9547a5562de8cad43cf0e71 --- /dev/null +++ b/20191017/loesung-3-2.c @@ -0,0 +1,13 @@ +#include <stdio.h> + +int main (void) +{ + int f[50]; + f[0] = 0; + f[1] = 1; + for (int i = 2; i < 50; i++) + f[i] = f[i - 2] + f[i - 1]; + for (int i = 0; i < 50; i++) + printf ("f[%d] = %d\n", i, f[i]); + return 0; +} diff --git a/20191017/loesung-4.c b/20191017/loesung-4.c new file mode 100644 index 0000000000000000000000000000000000000000..f8481e994c02ac8e581244713756c9e9be7c7fd6 --- /dev/null +++ b/20191017/loesung-4.c @@ -0,0 +1,8 @@ +#include <stdio.h> + +int main (void) +{ + for (int i = 10; i >= 0; i--) + printf ("%d\n", i); + return 0; +} diff --git a/README.md b/README.md index 67a8fd291d0696a4a42f9ab106ba74bb683f7ec2..b39e399e0ebaf7db92c3b3c2214317ba9b8b21b1 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Vortragsfolien und Beispiele: Musterlösungen: --------------- -(keine) + * [17.10.2019: Schaltjahr ermitteln, Multiplikationstabelle, Fibonacci-Zahlen, fehlerhaftes Programm](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20191017/hp-musterloesung-20191017.pdf) Tafelbilder: ------------