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

Musterlösungen 5.12.2019

parent 783b0e9c
No related branches found
No related tags found
No related merge requests found
File added
% hp-musterloesung-20191205.pdf - Solutions to the Exercises on Low-Level Programming
% 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: Löschen aus Strings, Hexdumps
\documentclass[a4paper]{article}
\usepackage{pgscript}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- 5.\ Dezember 2019}
\exercise{Löschen aus Strings}
Wir betrachten das folgende Programm (\gitfile{hp}{20191205}{aufgabe-1.c}):
\begin{lstlisting}[style=numbered]
#include <stdio.h>
#include <string.h>
void delete_char_from_string (char *s, int pos)
{
for (int i = strlen (s) - 1; i > pos; i--)
s[i - 1] = s[i];
}
int main (void)
{
char test[] = "Hochschule Boochum";
delete_char_from_string (test, 12);
printf ("%s\n", test);
return 0;
}
\end{lstlisting}
Die Ausgabe des Programms lautet:
\lstinline[style=terminal]{Hochschule Bmmmmmm}
\begin{enumerate}[\quad(a)]
\item
Erklären Sie, wie die Ausgabe zustandekommt.
\points{3}
% \workspace{12}
\item
Schreiben Sie die Funktion \lstinline{delete_char_from_string()} so um,
daß sie aus dem String \lstinline{s} das Zeichen an der Stelle \lstinline{pos}
löscht.\par
Die Ausgabe des Programms müßte dann
\lstinline[style=terminal]{Hochschule Bochum} lauten.
\points{4}
% \workspace{15}
\item
Was kann passieren, wenn Sie
\lstinline{char test[] = "Hochschule Boochum";} \\
durch
\lstinline{char *test = "Hochschule Boochum";}
ersetzen? Begründen Sie Ihre Antwort.
\points{2}
% \workspace{9}
\item
Schreiben Sie eine Funktion
\lstinline{void delete_from_string (char *s, int pos, int length)},
die \lstinline{length} Zeichen ab der Stelle \lstinline{pos}
aus dem String \lstinline{s} löscht,
\emph{indem sie die in Aufgabenteil (b) korrigierte Funktion\/}
\lstinline{void delete_char_from_string (char *s, int pos)}
\emph{wiederholt aufruft}. \par
% Wie schnell (Landau-Symbol in Abhängigkeit von der Länge $n$ des Strings)
% arbeitet diese Funktion
% \lstinline{delete_from_string()}?
% Begründen Sie Ihre Antwort.
% \points{3}
\points{2}
% \workspace{15}
\item
Schreiben Sie eine \emph{optimierte\/} Funktion
\lstinline{void quick_delete_from_string (char *s, int pos, int length)},
die ebenfalls \lstinline{length} Zeichen ab der Stelle \lstinline{pos}
aus dem String \lstinline{s} löscht,
% dafür aber höchstens $\mathcal{O}(n)$ an Rechenzeit benötigt.
aber mit einer einzigen Schleife auskommt.
\points{4}
% \workspace{15}
\end{enumerate}
\solution
\begin{enumerate}[\quad(a)]
\item
\textbf{Erklären Sie, wie die Ausgabe zustandekommt.}
Die Zuweisung innerhalb der Schleife (Zeile 7)
kopiert ein Zeichen des Strings von rechts nach links.
Die Schleife läuft ebenfalls von rechts nach links
(\lstinline{i--} in Zeile 6).
Beides zusammen bewirkt, daß das Zeichen ganz rechts im String
(\lstinline{'m'}) immer weiter nach links kopiert wird
bis einschließlich zu Stelle \lstinline{pos}.
(Die Schleife endet zwar bereits vor \lstinline{pos} (\lstinline{i > pos}),
aber die Zuweisung erfolgt an die Stelle \lstinline{i - 1}).
Da das Stringendesymbol nicht verschoben wird,
ändert sich die Länge des Strings nicht.
\item
\textbf{Schreiben Sie die Funktion \lstinline{delete_char_from_string()} so um,
daß sie aus dem String \lstinline{s} das Zeichen an der Stelle \lstinline{pos}
löscht.}\par
\textbf{Die Ausgabe des Programms müßte dann
\lstinline[style=terminal]{Hochschule Bochum} lauten.}
Siehe \gitfile{hp}{20191205}{loesung-1b-1.c}.
Geändert wurden die Zeilen 6 und 7.
Die Schleife muß von links nach rechts gehen anstatt von rechts nach links,
und sie muß das Stringendesymbol mit erfassen.
Alternativ kann man auch nur Zeile 6 ändern,
siehe \gitfile{hp}{20191205}{loesung-1b-2.c}.
\item
\textbf{Was kann passieren, wenn Sie
\lstinline{char test[] = "Hochschule Boochum";} \\
durch
\lstinline{char *test = "Hochschule Boochum";}
ersetzen? Begründen Sie Ihre Antwort.}
Das Array \lstinline{test[]} ist eine für das Programm schreibbare Variable.
Dies ist notwendig, um aus dem String ein Zeichen entfernen zu können.
Bei \lstinline{*test} ist nur der Zeiger selbst eine schreibbare Variable.
Die String-Konstante, auf die der Zeiger zeigt, ist typischerweise nur lesbar.
Der Versuch, aus diesem String ein Zeichen zu entfernen,
endet daher typischerweise in einem Speicherzugriffsfehler.
\item
\textbf{Schreiben Sie eine Funktion
\lstinline{void delete_from_string (char *s, int pos, int length)},
die \lstinline{length} Zeichen ab der Stelle \lstinline{pos}
aus dem String \lstinline{s} löscht,
\emph{indem sie die in Aufgabenteil (b) korrigierte Funktion\/}
\lstinline{void delete_char_from_string (char *s, int pos)}
\emph{wiederholt aufruft}.}
Siehe \gitfile{hp}{20191205}{loesung-1d.c}.
\item
\textbf{Schreiben Sie eine \emph{optimierte\/} Funktion
\lstinline{void quick_delete_from_string (char *s, int pos, int}\break
\lstinline{length)},
die ebenfalls \lstinline{length} Zeichen ab der Stelle \lstinline{pos}
aus dem String \lstinline{s} löscht,
aber mit einer einzigen Schleife auskommt.}
Die Funktion \lstinline{strlen()} ermittelt die Länge eines Strings,
indem sie den String von seinem Anfang bis zum Stringendesymbol durchgeht.
Der Aufruf von \lstinline{strlen()} innerhalb der Schleifenbedingung
(Zeile 6) enthält daher implizit eine weitere Schleife.
Wesentlich effizienter ist es,
wenn wir während des Durchlaufs unserer eigenen Schleife
selbst auf das Stringendesymbol achten und es als Abbruchkriterium verwenden
-- siehe \gitfile{hp}{20191205}{loesung-1e.c}.
\end{enumerate}
\exercise{Hexdumps}
Das folgende Programm (\gitfile{hp}{20191205}{aufgabe-2.c}) liest
einen String ein und gibt die ASCII-Werte der Buchstaben hexadezimal aus.
(Anders als z.\,B.\ \lstinline{scanf()}
akzeptiert die Funktion \lstinline{fgets()} zum Lesen von Strings auch Leerzeichen,
und sie vermeidet Pufferüberläufe.)
\begin{lstlisting}[style=numbered]
#include <stdio.h>
int main (void)
{
char buffer[100];
fgets (buffer, 100, stdin);
for (char *p = buffer; *p; p++)
printf ("%02x", *p);
printf ("\n");
}
\end{lstlisting}
Beispiel: Bei der Eingabe von \lstinline[style=cmd]{Dies ist ein Test.}
erscheint die Ausgabe\\
\lstinline[style=terminal]{44696573206973742065696e20546573742e0a}.
Schreiben Sie ein Programm, das diese Umwandlung in umgekehrter Richtung vornimmt,
also z.\,B.\ bei Eingabe von \lstinline[style=cmd]{44696573206973742065696e20546573742e0a}
wieder \lstinline[style=terminal]{Dies ist ein Test.} ausgibt.
\points{6}
Hinweis für die Klausur:
Abgabe in digitaler Form ist erwünscht, aber nicht zwingend.
\solution
Siehe \gitfile{hp}{20191205}{loesung-2.c}.
Das Programm macht mehrfach davon Gebrauch,
daß in C Zeichen und Zahlen äquivalent sind.
Wenn z.\,B.\ die \lstinline{char}-Variable \lstinline{c}
den Wert \lstinline{'3'} (Ziffer 3) enthält,
dann hat der Ausdruck \lstinline{c - '0'} den Wert \lstinline{3} (Zahlenwert 3).
Hierfür ist es insbesondere nicht nötig, vorauszusetzen,
daß wir den ASCII-Zeichensatz verwenden und \lstinline{'0'}
den Wert \lstinline{48} hat.
Bei Eingabe von \lstinline[style=cmd]{44696573206973742065696e20546573742e0a}
gibt das Programm zusätzlich eine Leerzeile aus.
Die liegt daran, daß das \lstinline[style=cmd]{0a} am Ende
bereits eine Zeilenschaltung enthält und das Programm mit
\lstinline{printf ("\n")} eine zusätzliche Zeilenschaltung ausgibt.
\end{document}
#include <stdio.h>
#include <string.h>
void delete_char_from_string (char *s, int pos)
{
for (int i = pos; i < strlen (s); i++)
s[i] = s[i + 1];
}
int main (void)
{
char test[] = "Hochschule Boochum";
delete_char_from_string (test, 12);
printf ("%s\n", test);
return 0;
}
#include <stdio.h>
#include <string.h>
void delete_char_from_string (char *s, int pos)
{
for (int i = pos + 1; i <= strlen (s); i++)
s[i - 1] = s[i];
}
int main (void)
{
char test[] = "Hochschule Boochum";
delete_char_from_string (test, 12);
printf ("%s\n", test);
return 0;
}
#include <stdio.h>
#include <string.h>
void delete_char_from_string (char *s, int pos)
{
for (int i = pos; i < strlen (s); i++)
s[i] = s[i + 1];
}
void delete_from_string (char *s, int pos, int length)
{
for (int i = 0; i < length; i++)
delete_char_from_string (s, pos);
}
int main (void)
{
char test[] = "Hochschule Boochum";
delete_from_string (test, 12, 3);
printf ("%s\n", test);
return 0;
}
#include <stdio.h>
#include <string.h>
void quick_delete_char_from_string (char *s, int pos)
{
for (int i = pos; s[i]; i++)
s[i] = s[i + 1];
}
int main (void)
{
char test[] = "Hochschule Boochum";
quick_delete_char_from_string (test, 12);
printf ("%s\n", test);
return 0;
}
#include <stdio.h>
int read_hex (char c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else
{
fprintf (stderr, "invalid hex digit '%c'\n", c);
return 0;
}
}
int main (void)
{
char buffer[100];
fgets (buffer, 100, stdin);
for (char *p = buffer; p[0] && p[1]; p += 2)
{
char c = 16 * read_hex (p[0]) + read_hex (p[1]);
printf ("%c", c);
}
printf ("\n");
}
......@@ -60,6 +60,7 @@ Musterlösungen:
* [14.11.2019: Ausgabe von Hexadezimalzahlen, Einfügen in Strings, Länge von Strings](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20191114/hp-musterloesung-20191114.pdf)
* [21.11.2019: Zahlensysteme, Mikrocontroller](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20191121/hp-musterloesung-20191121.pdf)
* [28.11.2019: Datum-Bibliothek, Text-Grafik-Bibliothek, LED-Blinkmuster](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20191128/hp-musterloesung-20191128.pdf)
* [05.12.2019: Löschen aus Strings, Hexdumps](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20191205/hp-musterloesung-20191205.pdf)
* [12.12.2019: Kondensator, hüpfender Ball](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20191212/hp-musterloesung-20191212.pdf)
* [19.12.2019: Trickprogrammierung, Thermometer-Baustein an I²C-Bus](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20191219/hp-musterloesung-20191219.pdf)
* [09.01.2020: Speicherformate von Zahlen, Zeigerarithmetik, Personen-Datenbank](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20200109/hp-musterloesung-20200109.pdf)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment