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

Vorbereitung 19.1.2020

parent 69516512
No related branches found
No related tags found
No related merge requests found
Showing
with 1887 additions and 0 deletions
year = ORIGINYEAR; /* = 1980 */
while (days > 365)
{
if (IsLeapYear (year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
}
else
{
days -= 365;
year += 1;
}
}
File added
This diff is collapsed.
File added
% hp-musterloesung-20191024.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: Seltsame Programme, Kalender-Berechnung
\documentclass[a4paper]{article}
\usepackage{pgscript}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- 24.\ Oktober 2019}
\exercise{Seltsame Programme}
Unter \url{https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/20191024}
finden Sie (unter anderem)\\
die Programme \gitfile{hp}{20191024}{test-1.c},
\gitfile{hp}{20191024}{test-2.c} und \gitfile{hp}{20191024}{test-3.c}.
Was bewirken diese Programme, und warum verhalten sie sich so?
\solution
\begin{itemize}
\item
\gitfile{hp}{20191024}{test-1.c}
Hinter \lstinline{return} steht ein Ausdruck mit dem
Komma-Operator. Dieser bewirkt, daß der Wert vor dem Komma
berechnet und ignoriert und danach der Wert nach dem Komma
zurückgegeben wird.
In diesem Fall wird vor dem Komma der Wert des
\lstinline{printf()}-Aufrufs berechnet und ignoriert.
Als Seiteneffekt gibt das Programm die Zeile
\lstinline[style=terminal]{Hello, world!} aus.
Anschließend wird der Wert \lstinline{0} an \lstinline{return}
übergeben und daher \lstinline{return 0} ausgeführt.
\item
\gitfile{hp}{20191024}{test-2.c}
Das Programm gibt die Zeile
\lstinline[style=terminal]{Die Antwort lautet: 42} aus.
Die \lstinline{if}-Bedingung ist eine Zuweisung \lstinline{b = 42},
die den zugewiesenen Wert \lstinline{42} zurückgibt.
Weil dieser Wert ungleich Null ist, interpretiert
\lstinline{if} ihn als Wahrheitswert "`wahr"', führt also den
\lstinline{if}-Zweig aus und überspringt den
\lstinline{else}-Zweig.
\item
\gitfile{hp}{20191024}{test-3.c}
Das Programm stürzt mit einer Fehlermeldung
"`Speicherzugriffsfehler"' oder "`Schutzverletzung"' ab.
Der Funktionsaufruf \lstinline{printf (42)} übergibt den
Zahlenwert \lstinline{42} als String, also als einen Zeiger
auf \lstinline{char}-Variable, an die Funktion
\lstinline{printf()}. Diese versucht, auf den Speicher ab
Adresse 42 zuzugreifen, wofür aber das Programm keine
Zugriffsrechte hat. Das Betriebssystem beendet daraufhin das
Programm mit der o.\,a.\ Fehlermeldung.
Der String \lstinline{"Die Antwort lautet: "} wird nicht
ausgegeben, weil Schreiboperationen aus Effizienzgründen
erst nach einer abgeschlossenen Zeile (\lstinline{"\n"})
durchgeführt werden.
\end{itemize}
\clearpage
\exercise{Kalender-Berechnung}
Am 3.\,1.\,2009 meldete \emph{heise online\/}:
\begin{quote}
Kunden des ersten mobilen Media-Players von Microsoft
erlebten zum Jahresende eine böse Überraschung:
Am 31.\ Dezember 2008 fielen weltweit alle Zune-Geräte der ersten Generation aus.
Ursache war ein interner Fehler bei der Handhabung von Schaltjahren.
\strut\hfill\url{http://heise.de/-193332},
\end{quote}
Der Artikel verweist auf ein Quelltextfragment (Datei: \gitfile{hp}{20191024}{aufgabe-2.c}),
das für einen gegebenen Wert \lstinline{days}
das Jahr und den Tag innerhalb des Jahres
für den \lstinline{days}-ten Tag nach dem 1.\,1.\,1980 berechnen soll:
\begin{lstlisting}
year = ORIGINYEAR; /* = 1980 */
while (days > 365)
{
if (IsLeapYear (year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
}
else
{
days -= 365;
year += 1;
}
}
\end{lstlisting}
Dieses Quelltextfragment enthält schlechten Programmierstil,
nämlich mehrere Code-Verdopplungen:
\begin{itemize}
\item
Die Anweisung \lstinline{year += 1} taucht an zwei Stellen auf.
\item
Es gibt zwei unabhängige Abfragen \lstinline{days > 365} und \lstinline{days > 366}:\\
eine in einer \lstinline{while}- und die andere in einer \lstinline{if}-Bedingung.
\item
Die Länge eines Jahres wird nicht durch eine Funktion berechnet oder in einer Variablen gespeichert;
stattdessen werden an mehreren Stellen die expliziten numerischen Konstanten 365 und 366 verwendet.
\end{itemize}
Diese Probleme führten am 31.\ Dezember 2008 zu einer Endlosschleife.
Gut hingegen ist die Verwendung einer Konstanten \lstinline{ORIGINYEAR}
anstelle der Zahl 1980
sowie die Kapselung der Berechnung der Schaltjahr-Bedingung
in einer Funktion \lstinline{IsLeapYear()}.
\begin{itemize}
\item[(a)]
Erklären Sie das Zustandekommen der Endlosschleife.
\item[(b)]
Schreiben Sie das Quelltextfragment so um, daß es die beschriebenen Probleme
nicht mehr enthält.
\end{itemize}
\textbf{Hinweis 1:} Verwenden Sie Ihre eigene Funktion \lstinline{IsLeapYear()}.
\textbf{Hinweis 2}: Schreiben Sie zusätzlich eine Funktion \lstinline{DaysInYear()}.
\clearpage
\solution
\begin{itemize}
\item[(a)]
\textbf{Erklären Sie das Zustandekommen der Endlosschleife.}
Das Programm startet mit demjenigen Wert für \lstinline{days},
der der Anzahl der Tage vom 1.\,1.\,1980 bis zum
31.\,12.\,2008 entspricht. Die \lstinline{while}-Schleife
läuft zunächst solange korrekt durch, bis \lstinline{year} den
Wert \lstinline{2008} und \lstinline{days} den Wert
\lstinline{366} hat. (Der 31.\,12.\ des Schaltjahres 2008 ist
der 366.\ Tag seines Jahres.)
Die Bedingung der \lstinline{while}-Schleife ist damit
weiterhin erfüllt; das Programm läuft weiter.
Da 2008 ein Schaltjahr ist, ist auch die Bedingung der äußeren
\lstinline{if}-Anweisung erfüllt.
Da \lstinline{days} den Wert 366 hat und dieser nicht größer
als 366 ist, ist die innere \lstinline{if}-Bedingung nicht
erfüllt. Somit wird innerhalb der \lstinline{while}-Schleife
kein weiterer Code ausgeführt, die \lstinline{while}-Bedingung
bleibt erfüllt, und das Programm führt eine Endlosschleife
aus.
\item[(b)]
\textbf{Schreiben Sie das Quelltextfragment so um, daß es die beschriebenen Probleme
nicht mehr enthält.}
Um das Programm zu testen, genügt es, das Datum auf den
31.\,12.\,1980 zu stellen, also \lstinline{days} auf den Wert
366 zu setzen. Darüberhinaus muß man die Funktion
\lstinline{IsLeapYear()} bereitstellen (vgl.\ Aufgabe 1 vom 17.\,10.\,2019).
Der Quelltext \gitfile{hp}{20191024}{loesung-2-f1.c} ist eine lauffähige
Version des Programms, die den Fehler (Endlosschleife)
reproduziert.
\breath
Es liegt nahe, den Fehler in der \lstinline{while}-Bedingung
zu korrigieren, so daß diese Schaltjahre berücksichtigt. Der
Quelltext \gitfile{hp}{20191024}{loesung-2-f2.c} behebt den Fehler auf diese
Weise mit Hilfe von Und- (\lstinline{&&}) und
Oder-Verknüpfungen (\lstinline{||}) in der
\lstinline{while}-Bedingung.
Der Quelltext \gitfile{hp}{20191024}{loesung-2-f3.c} vermeidet die umständliche
Formulierung mit \lstinline{&&} und \lstinline{||} durch
Verwendung des ternären Operators \lstinline{?:}. Dieser
stellt eine "`\lstinline{if}-Anweisung für Ausdrücke"' bereit.
In diesem Fall liefert er für die rechte Seite des Vergleichs
\lstinline{days >} den Wert 366 im Falle eines Schaltjahrs
bzw.\ ansonsten den Wert 365.
Beide Lösungen \gitfile{hp}{20191024}{loesung-2-f2.c} und \gitfile{hp}{20191024}{loesung-2-f3.c}
sind jedoch im Sinne der Aufgabenstellung \textbf{falsch}.
Diese lautet: "`Schreiben Sie das Quelltextfragment so um,
daß es die beschriebenen Probleme nicht mehr enthält."'
Mit den beschriebenen Problemen sind die genannten drei
Code-Verdopplungen gemeint, und diese befinden sich weiterhin
im Quelltext. Damit ist der Fehler zwar "`korrigiert"', aber
das Programm ist eher noch unübersichtlicher geworden, so daß
nicht klar ist, ob es nicht noch weitere Fehler enthält.
\breath
Eine richtige Lösung liefert \gitfile{hp}{20191024}{loesung-2-4.c}. Dieses
Programm speichert den Wert der Tage im Jahr in einer
Variablen \lstinline{DaysInYear}. Damit erübrigen sich die
\lstinline{if}-Anweisungen innerhalb der
\lstinline{while}-Schleife, und die damit verbundenen
Code-Verdopplungen verschwinden.
Etwas unschön ist hierbei die neu hinzugekommene
Code-Verdopplung bei der Berechnung von \lstinline{DaysInYear}.
Diese ist allerdings weniger kritisch als die vorherigen, da
sie nur einmal innerhalb der \lstinline{while}-Schleife
vorkommt und das andere Mal außerhalb derselben.
Um diese Code-Verdopplung loszuwerden, kann man das
\lstinline{if} durch den \lstinline{?:}-Operator ersetzen und
die Zuweisung innerhalb der \lstinline{while}-Bedingung
vornehmen -- siehe \gitfile{hp}{20191024}{loesung-2-5.c}. Dies ist einer der
seltenen Fälle, in denen ein Programm \emph{übersichtlicher\/}
wird, wenn eine Zuweisung innerhalb einer Bedingung
stattfindet.
Alternativ kann \lstinline{DaysInYear()} auch eine Funktion
sein -- siehe \gitfile{hp}{20191024}{loesung-2-6.c}. Diese Version ist
wahrscheinlich die übersichtlichste, hat jedoch den Nachteil,
daß die Berechnung von \lstinline{DaysInYear()} zweimal statt
nur einmal pro Schleifendurchlauf erfolgt, wodurch Rechenzeit
verschwendet wird.
\gitfile{hp}{20191024}{loesung-2-7.c} und \gitfile{hp}{20191024}{loesung-2-8.c} beseitigen
dieses Problem durch eine Zuweisung des Funktionsergebnisses
an eine Variable -- einmal innerhalb der
\lstinline{while}-Bedingung und einmal außerhalb.
Der zweimalige Aufruf der Funktion \lstinline{DaysInYear()} in
\gitfile{hp}{20191024}{loesung-2-8.c} zählt nicht als Code-Verdopplung, denn
der Code ist ja in einer Funktion gekapselt. (Genau dazu sind
Funktionen ja da: daß man sie mehrfach aufrufen kann.)
\breath
Fazit: Wenn Sie sich beim Programmieren bei
Cut-And-Paste-Aktionen erwischen, sollten Sie die Struktur
Ihres Programms noch einmal überdenken.
Wahrscheinlich gibt es dann eine elegantere Lösung, deren
Korrektheit man auf den ersten Blick sieht.
\end{itemize}
\end{document}
File added
% hp-uebung-20201119.pdf - Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020 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: Seltsame Programme, Kalender-Berechnung
\documentclass[a4paper]{article}
\usepackage{pgscript}
\thispagestyle{empty}
\begin{document}
\thispagestyle{empty}
\section*{Hardwarenahe Programmierung\\
Übungsaufgaben -- 19.\ November 2020}
\exercise{Seltsame Programme}
Unter \url{https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/20201119}
finden Sie (unter anderem)\\
die Programme \gitfile{hp}{20201119}{test-1.c},
\gitfile{hp}{20201119}{test-2.c} und \gitfile{hp}{20201119}{test-3.c}.
Was bewirken diese Programme, und warum verhalten sie sich so?
\exercise{Kalender-Berechnung}
Am 3.\,1.\,2009 meldete \emph{heise online\/}:
\begin{quote}
Kunden des ersten mobilen Media-Players von Microsoft
erlebten zum Jahresende eine böse Überraschung:
Am 31.\ Dezember 2008 fielen weltweit alle Zune-Geräte der ersten Generation aus.
Ursache war ein interner Fehler bei der Handhabung von Schaltjahren.
\strut\hfill\url{http://heise.de/-193332},
\end{quote}
Der Artikel verweist auf ein Quelltextfragment (Datei: \gitfile{hp}{20201119}{aufgabe-2.c}),
das für einen gegebenen Wert \lstinline{days}
das Jahr und den Tag innerhalb des Jahres
für den \lstinline{days}-ten Tag nach dem 1.\,1.\,1980 berechnen soll:
\begin{lstlisting}
year = ORIGINYEAR; /* = 1980 */
while (days > 365)
{
if (IsLeapYear (year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
}
else
{
days -= 365;
year += 1;
}
}
\end{lstlisting}
Dieses Quelltextfragment enthält schlechten Programmierstil,
nämlich mehrere Code-Verdopplungen:
\begin{itemize}
\item
Die Anweisung \lstinline{year += 1} taucht an zwei Stellen auf.
\item
Es gibt zwei unabhängige Abfragen \lstinline{days > 365} und \lstinline{days > 366}:\\
eine in einer \lstinline{while}- und die andere in einer \lstinline{if}-Bedingung.
\item
Die Länge eines Jahres wird nicht durch eine Funktion berechnet oder in einer Variablen gespeichert;
stattdessen werden an mehreren Stellen die expliziten numerischen Konstanten 365 und 366 verwendet.
\end{itemize}
Diese Probleme führten am 31.\ Dezember 2008 zu einer Endlosschleife.
Gut hingegen ist die Verwendung einer Konstanten \lstinline{ORIGINYEAR}
anstelle der Zahl 1980
sowie die Kapselung der Berechnung der Schaltjahr-Bedingung
in einer Funktion \lstinline{IsLeapYear()}.
\begin{itemize}
\item[(a)]
Erklären Sie das Zustandekommen der Endlosschleife.
\item[(b)]
Schreiben Sie das Quelltextfragment so um, daß es die beschriebenen Probleme
nicht mehr enthält.
\end{itemize}
\textbf{Hinweis 1:} Verwenden Sie für \lstinline{IsLeapYear()}
Ihre eigene Funktion aus Aufgabe 1 der letzten Übung.
\textbf{Hinweis 2}: Schreiben Sie zusätzlich eine Funktion \lstinline{DaysInYear()}.
\end{document}
#include <stdio.h>
int IsLeapYear (int year)
{
if (year % 4)
return 0;
else if (year % 100)
return 1;
else if (year % 400)
return 0;
else
return 1;
}
int main (void)
{
int ORIGINYEAR = 1980;
int days = 366;
int year;
year = ORIGINYEAR; /* = 1980 */
int DaysInYear;
if (IsLeapYear (year))
DaysInYear = 366;
else
DaysInYear = 365;
while (days > DaysInYear)
{
days -= DaysInYear;
year += 1;
if (IsLeapYear (year))
DaysInYear = 366;
else
DaysInYear = 365;
}
printf ("year = %d\ndays = %d\n", year, days);
return 0;
}
#include <stdio.h>
int IsLeapYear (int year)
{
if (year % 4)
return 0;
else if (year % 100)
return 1;
else if (year % 400)
return 0;
else
return 1;
}
int main (void)
{
int ORIGINYEAR = 1980;
int days = 366;
int year;
year = ORIGINYEAR; /* = 1980 */
int DaysInYear;
while (days > (DaysInYear = IsLeapYear (year) ? 366 : 365))
{
days -= DaysInYear;
year += 1;
}
printf ("year = %d\ndays = %d\n", year, days);
return 0;
}
#include <stdio.h>
int IsLeapYear (int year)
{
if (year % 4)
return 0;
else if (year % 100)
return 1;
else if (year % 400)
return 0;
else
return 1;
}
int DaysInYear (int year)
{
if (IsLeapYear (year))
return 366;
else
return 365;
}
int main (void)
{
int ORIGINYEAR = 1980;
int days = 366;
int year;
year = ORIGINYEAR; /* = 1980 */
while (days > DaysInYear (year))
{
days -= DaysInYear (year);
year += 1;
}
printf ("year = %d\ndays = %d\n", year, days);
return 0;
}
#include <stdio.h>
int IsLeapYear (int year)
{
if (year % 4)
return 0;
else if (year % 100)
return 1;
else if (year % 400)
return 0;
else
return 1;
}
int DaysInYear (int year)
{
if (IsLeapYear (year))
return 366;
else
return 365;
}
int main (void)
{
int ORIGINYEAR = 1980;
int days = 366;
int year;
year = ORIGINYEAR; /* = 1980 */
int d;
while (days > (d = DaysInYear (year)))
{
days -= d;
year += 1;
}
printf ("year = %d\ndays = %d\n", year, days);
return 0;
}
#include <stdio.h>
int IsLeapYear (int year)
{
if (year % 4)
return 0;
else if (year % 100)
return 1;
else if (year % 400)
return 0;
else
return 1;
}
int DaysInYear (int year)
{
if (IsLeapYear (year))
return 366;
else
return 365;
}
int main (void)
{
int ORIGINYEAR = 1980;
int days = 366;
int year;
year = ORIGINYEAR; /* = 1980 */
int d = DaysInYear (year);
while (days > d)
{
days -= d;
year += 1;
d = DaysInYear (year);
}
printf ("year = %d\ndays = %d\n", year, days);
return 0;
}
#include <stdio.h>
int IsLeapYear (int year)
{
if (year % 4)
return 0;
else if (year % 100)
return 1;
else if (year % 400)
return 0;
else
return 1;
}
int main (void)
{
int ORIGINYEAR = 1980;
int days = 366;
int year;
year = ORIGINYEAR; /* = 1980 */
while (days > 365)
{
if (IsLeapYear (year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
}
else
{
days -= 365;
year += 1;
}
}
printf ("year = %d\ndays = %d\n", year, days);
return 0;
}
#include <stdio.h>
int IsLeapYear (int year)
{
if (year % 4)
return 0;
else if (year % 100)
return 1;
else if (year % 400)
return 0;
else
return 1;
}
int main (void)
{
int ORIGINYEAR = 1980;
int days = 366;
int year;
year = ORIGINYEAR; /* = 1980 */
while ((IsLeapYear (year) && days > 366)
|| (!IsLeapYear (year) && days > 365))
{
if (IsLeapYear (year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
}
else
{
days -= 365;
year += 1;
}
}
printf ("year = %d\ndays = %d\n", year, days);
return 0;
}
#include <stdio.h>
int IsLeapYear (int year)
{
if (year % 4)
return 0;
else if (year % 100)
return 1;
else if (year % 400)
return 0;
else
return 1;
}
int main (void)
{
int ORIGINYEAR = 1980;
int days = 366;
int year;
year = ORIGINYEAR; /* = 1980 */
while (days > (IsLeapYear (year) ? 366 : 365))
{
if (IsLeapYear (year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
}
else
{
days -= 365;
year += 1;
}
}
printf ("year = %d\ndays = %d\n", year, days);
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
../common/pgscript.sty
\ No newline at end of file
../common/pgslides.sty
\ No newline at end of file
#include <stdio.h>
int main (void)
{
return
printf ("Hello, world!\n"),
0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment