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

Vorbereitung 26.10.2023

parent 091b9cba
Branches
No related tags found
No related merge requests found
Showing
with 2115 additions and 0 deletions
20231019/gitlab.png

589 B

No preview for this file type
......@@ -1152,6 +1152,8 @@
\end{frame}
\iffalse
\begin{frame}[fragile]
\showsubsection
......@@ -1304,4 +1306,6 @@
\end{frame}
\fi
\end{document}
#include <stdio.h>
void f (int *s0, int *s1)
{
while (*s0 >= 0)
{
int *s = s1;
while (*s >= 0)
if (*s0 == *s++)
printf ("%d ", *s0);
s0++;
}
printf ("\n");
}
int main (void)
{
int a[] = { 10, 4, 3, 7, 12, 0, 1, -1 };
int b[] = { 7, 14, 0, 8, 9, 22, 10, -1 };
f (a, b);
return 0;
}
#include <stdio.h>
void f (int *s0, int *s1)
{
while (*s0 >= 0)
{
int *s = s1;
while (*s >= 0)
if (*s0 == *s++)
printf ("%d ", *s0);
s0++;
}
printf ("\n");
}
int main (void)
{
int a[] = { 10, 4, 3, 7, 12, 0, 1 };
int b[] = { 7, 14, 0, 8, 9, 22, 10 };
f (a, b);
return 0;
}
#include <stdio.h>
int main (void)
{
int n, i, divisors;
for (n = 0; n < 100; n++)
divisors = 0;
for (i = 0; i < n; i++)
if (n % i == 0)
divisors++;
if (divisors = 2)
printf ("%d ist eine Primzahl.\n", n);
return 0;
}
#include <gtk/gtk.h>
static void activate (GtkApplication *app, gpointer user_data)
{
GtkWidget *window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Hello");
gtk_window_present (GTK_WINDOW (window));
}
int main (int argc, char **argv)
{
GtkApplication *app = gtk_application_new ("de.hs-bochum.cvh.hp.hello-gtk", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
int status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
#include <gtk/gtk.h>
static void hello (GtkWidget *this, gpointer user_data)
{
char *world = user_data;
printf ("Hello, %s!\n", world);
}
static void activate (GtkApplication *app, gpointer user_data)
{
GtkWidget *window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Hello");
GtkWidget *button = gtk_button_new_with_label ("Hello, world!");
g_signal_connect (button, "clicked", G_CALLBACK (hello), "world");
gtk_window_set_child (GTK_WINDOW (window), button);
gtk_window_present (GTK_WINDOW (window));
}
int main (int argc, char **argv)
{
GtkApplication *app = gtk_application_new ("de.hs-bochum.cvh.hp.hello-gtk", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
int status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
#include <gtk/gtk.h>
static void close_window (GtkWidget *this, gpointer user_data)
{
GtkWindow *window = user_data;
gtk_window_destroy (window);
}
static void activate (GtkApplication *app, gpointer user_data)
{
GtkWidget *window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Hello");
GtkWidget *button = gtk_button_new_with_label ("Quit");
g_signal_connect (button, "clicked", G_CALLBACK (close_window), window);
gtk_window_set_child (GTK_WINDOW (window), button);
gtk_window_present (GTK_WINDOW (window));
}
int main (int argc, char **argv)
{
GtkApplication *app = gtk_application_new ("de.hs-bochum.cvh.hp.hello-gtk", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
int status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
#include <gtk/gtk.h>
static void activate (GtkApplication *app, gpointer user_data)
{
GtkWidget *window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Hello");
GtkWidget *button = gtk_button_new_with_label ("Quit");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_destroy), window);
gtk_window_set_child (GTK_WINDOW (window), button);
gtk_window_present (GTK_WINDOW (window));
}
int main (int argc, char **argv)
{
GtkApplication *app = gtk_application_new ("de.hs-bochum.cvh.hp.hello-gtk", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
int status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
#include <gtk/gtk.h>
static void hello (GtkWidget *this, gpointer user_data)
{
char *world = user_data;
printf ("Hello, %s!\n", world);
}
static void activate (GtkApplication *app, gpointer user_data)
{
GtkWidget *window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Hello");
GtkWidget *vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_window_set_child (GTK_WINDOW (window), vbox);
GtkWidget *hello_button = gtk_button_new_with_label ("Hello, world!");
g_signal_connect (hello_button, "clicked", G_CALLBACK (hello), "world");
gtk_box_append (GTK_BOX (vbox), hello_button);
GtkWidget *quit_button = gtk_button_new_with_label ("Quit");
g_signal_connect_swapped (quit_button, "clicked", G_CALLBACK (gtk_window_destroy), window);
gtk_box_append (GTK_BOX (vbox), quit_button);
gtk_window_present (GTK_WINDOW (window));
}
int main (int argc, char **argv)
{
GtkApplication *app = gtk_application_new ("de.hs-bochum.cvh.hp.hello-gtk", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
int status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
#include <gtk/gtk.h>
static void draw (GtkDrawingArea *drawing_area, cairo_t *c,
int width, int height, gpointer user_data)
{
GdkRGBA red = { 1.0, 0.0, 0.0, 0.8 };
GdkRGBA yellow = { 1.0, 1.0, 0.0, 0.6 };
GdkRGBA blue = { 0.0, 0.5, 1.0, 0.4 };
gdk_cairo_set_source_rgba (c, &red);
cairo_rectangle (c, 10, 10, 60, 40);
cairo_fill (c);
gdk_cairo_set_source_rgba (c, &yellow);
cairo_arc (c, 65, 50, 30, 0, 2 * G_PI);
cairo_fill (c);
gdk_cairo_set_source_rgba (c, &blue);
cairo_move_to (c, 10, 70);
cairo_line_to (c, 70, 70);
cairo_line_to (c, 40, 18);
cairo_close_path (c);
cairo_fill (c);
}
static void activate (GtkApplication *app, gpointer user_data)
{
GtkWidget *window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Hello");
GtkWidget *vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_window_set_child (GTK_WINDOW (window), vbox);
GtkWidget *drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawing_area, 100, 100);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (drawing_area), draw, NULL, NULL);
gtk_box_append (GTK_BOX (vbox), drawing_area);
GtkWidget *quit_button = gtk_button_new_with_label ("Quit");
g_signal_connect_swapped (quit_button, "clicked", G_CALLBACK (gtk_window_destroy), window);
gtk_box_append (GTK_BOX (vbox), quit_button);
gtk_window_present (GTK_WINDOW (window));
}
int main (int argc, char **argv)
{
GtkApplication *app = gtk_application_new ("de.hs-bochum.cvh.hp.hello-gtk", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
int status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
eine kleine Hexe.
File added
% hp-20231026.pdf - Lecture Slides on Low-Level Programming
% Copyright (C) 2012, 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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: Einführung in C: String-Operationen; Bibliotheken
\documentclass[10pt,t]{beamer}
\usepackage{pgslides}
\usepackage{pdftricks}
\usepackage{tikz}
\begin{psinputs}
\usepackage[utf8]{inputenc}
\usepackage[german]{babel}
\usepackage[T1]{fontenc}
\usepackage{helvet}
\renewcommand*\familydefault{\sfdefault}
\usepackage{pstricks,pst-grad}
\end{psinputs}
\newcommand{\redurl}[1]{\href{#1}{\color{red}\nolinkurl{#1}}}
\title{Hardwarenahe Programmierung}
\author{Prof.\ Dr.\ rer.\ nat.\ Peter Gerwinski}
\date{26.\ Oktober 2023}
\begin{document}
\maketitleframe
%\date{\begin{picture}(0,0)
% \color{red}
% \put(0.65,1.05){\makebox(0,0)[t]{$\underbrace{\rule{1.45cm}{0pt}}_{%
% \mbox{\emph{rerum naturalium\/} = der natürlichen Dinge (lat.)}}$}}
% \put(1.65,-3){\makebox(0,0)[bl]{\redurl{https://www.peter.gerwinski.de/physik/}}}
% \end{picture}%
% 12.\ Oktober 2023}
%
%\maketitleframe
\title{Hardwarenahe Programmierung}
\nosectionnonumber{\inserttitle}
\begin{frame}
\shownosectionnonumber
\begin{itemize}
\item[\textbf{1}] \textbf{Einführung}
\hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}}
\item[\textbf{2}] \textbf{Einführung in C}
\begin{itemize}
\vspace{-1.5\smallskipamount}
\item[\dots]
\item[2.7] Strukturierte Programmierung
\item[2.8] Seiteneffekte
\item[2.9] Funktionen
\item[2.10] Zeiger
\color{medgreen}
\item[2.11] Arrays und Strings
\item[2.12] Strukturen
\item[2.13] Dateien und Fehlerbehandlung
\item[2.14] Parameter des Hauptprogramms
\color{orange}
\item[2.15] String-Operationen
\end{itemize}
\item[\textbf{3}] \textbf{Bibliotheken}
\vspace*{-\smallskipamount}
\item[\textbf{\dots}]
% \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
% \item[\textbf{5}] \textbf{Algorithmen}
% \item[\textbf{6}] \textbf{Ergänzungen und Ausblicke}
\end{itemize}
\end{frame}
\section{Einführung}
\section{Einführung in C}
\setcounter{subsection}{10}
\subsection{Arrays und Strings}
\begin{frame}[fragile]
\showsubsection
Ein Zeiger zeigt auf eine Variable\only<2->{ und deren Nachbarn}.
\bigskip
\pause
\pause
\begin{onlyenv}<1-8>
\begin{lstlisting}[gobble=6]
#include <stdio.h>
int main (void)
{
int prime[5] = { 2, 3, 5, 7, 11 };
int *p = prime;
for (int i = 0; i < 5; i++)
printf ("%d\n", *(p + i));
return 0;
}
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<9>
\begin{lstlisting}[gobble=6]
#include <stdio.h>
int main (void)
{
int prime[5] = { 2, 3, 5, 7, 11 };
int *p = prime;
for (int i = 0; i < 5; i++)
printf ("%d\n", p[i]);
return 0;
}
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<10>
\begin{lstlisting}[gobble=6]
#include <stdio.h>
int main (void)
{
int prime[5] = { 2, 3, 5, 7, 11 };
for (int i = 0; i < 5; i++)
printf ("%d\n", prime[i]);
return 0;
}
¡ ¿
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<11>
\begin{lstlisting}[gobble=6]
#include <stdio.h>
int main (void)
{
int prime[5] = { 2, 3, 5, 7, 11 };
for (int *p = prime;
p < prime + 5; p++)
printf ("%d\n", *p);
return 0;
}
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<12>
\begin{lstlisting}[gobble=6]
#include <stdio.h>
int main (void)
{
int prime[6] = { 2, 3, 5, 7, 11, 0 };
for (int *p = prime; *p; p++)
printf ("%d\n", *p);
return 0;
}
¡ ¿
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<13->
\begin{lstlisting}[gobble=6]
#include <stdio.h>
int main (void)
{
int prime[] = { 2, 3, 5, 7, 11, 0 };
for (int *p = prime; *p; p++)
printf ("%d\n", *p);
return 0;
}
¡ ¿
\end{lstlisting}
\end{onlyenv}
\pause
\vspace{-3.05cm}\hspace{5.5cm}%
\begin{minipage}{6.5cm}
\begin{itemize}
\item
\lstinline{prime} ist \alt<5->{ein Array}{eine Ansammlung} von\\fünf ganzen Zahlen.
\pause
\pause
\item
\only<6-9>{\begin{picture}(0,0)
\color{red}
\put(-1.6,0.1){\tikz{\draw[-latex](0.0,0.0)--(-1,0);}}
\end{picture}}%
\lstinline{prime} ist ein Zeiger auf eine \lstinline{int}.
\pause
\item
\lstinline{p + i} ist ein Zeiger\\
auf den \lstinline{i}-ten Nachbarn von \lstinline{*p}.
\pause
\item
\lstinline{*(p + i)} ist der \lstinline{i}-te Nachbar von \lstinline{*p}.
\pause
\item
Andere Schreibweise:\\
\lstinline{p[i]} statt \lstinline{*(p + i)}
\pause
\pause
\item
Zeiger-Arithmetik:\\
\lstinline{p++} rückt den Zeiger \lstinline{p}\\
um eine \lstinline{int} weiter.
\pause
\pause
\item
Array ohne \only<14->{explizite }Längenangabe:\\
Compiler zählt selbst
\vspace*{-1cm}
\pause
\begin{picture}(0,0)
\put(-5.2,1.0){\makebox(0,0)[br]{\color{red}\bf\shortstack{Die Länge des Arrays\\ist \emph{nicht\/} veränderlich!}}}
\end{picture}
\end{itemize}
\end{minipage}
\end{frame}
\nosectionnonumber{\inserttitle}
\begin{frame}
\shownosectionnonumber
\begin{itemize}
\item[\textbf{1}] \textbf{Einführung}
\hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}}
\item[\textbf{2}] \textbf{Einführung in C}
\begin{itemize}
\vspace{-1.5\smallskipamount}
\item[\dots]
\item[2.5] Verzweigungen
\item[2.6] Schleifen
\color{medgreen}
\item[2.7] Strukturierte Programmierung
\item[2.8] Seiteneffekte
\item[2.9] Funktionen
\item[2.10] Zeiger
\color{orange}
\item[2.11] Arrays und Strings
\color{red}
\item[2.12] Strukturen
\item[2.13] Dateien und Fehlerbehandlung
\item[2.14] Parameter des Hauptprogramms
\item[2.15] String-Operationen
\end{itemize}
\color{gray}
\item[\textbf{3}] \textbf{Bibliotheken}
\vspace*{-\smallskipamount}
\item[\textbf{\dots}]
% \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
% \item[\textbf{5}] \textbf{Algorithmen}
% \item[\textbf{6}] \textbf{Ergänzungen und Ausblicke}
\end{itemize}
\vspace*{-1cm}
\end{frame}
% \begin{frame}[fragile]
% \showsubsection
%
% \begin{lstlisting}
% #include <stdio.h>
%
% int main (void)
% {
% char hello_world[] = "Hello, world!\n";
% int i = 0;
% while (hello_world[i] != 0)
% printf ("%d", hello_world[i++]);
% return 0;
% }
% \end{lstlisting}
% \end{frame}
% \begin{frame}[fragile]
% \showsubsection
%
% \begin{lstlisting}
% #include <stdio.h>
%
% int main (void)
% {
% char hello_world[] = "Hello, world!\n";
% int i = 0;
% while (hello_world[i])
% printf ("%d", hello_world[i++]);
% return 0;
% }
% \end{lstlisting}
% \end{frame}
% \begin{frame}[fragile]
% \showsubsection
%
% \begin{lstlisting}
% #include <stdio.h>
%
% int main (void)
% {
% char hello_world[] = "Hello, world!\n";
% char *p = hello_world;
% while (*p)
% printf ("%c", *p++);
% return 0;
% }
% \end{lstlisting}
% \end{frame}
\begin{frame}[fragile]
\showsubsection
\begin{onlyenv}<1-6>
\begin{lstlisting}[gobble=6]
#include <stdio.h>
int main (void)
{
char hello[] = "Hello, world!\n";
for (char *p = hello; *p; p++)
printf ("%d", *p);
return 0;
}
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<7>
\begin{lstlisting}[gobble=6]
#include <stdio.h>
int main (void)
{
char hello[] = "Hello, world!\n";
for (char *p = hello; *p; p++)
printf ("%c", *p);
return 0;
}
\end{lstlisting}
\end{onlyenv}
% \begin{onlyenv}<8>
% \begin{lstlisting}[gobble=6]
% #include <stdio.h>
%
% int main (void)
% {
% char hello[] = "Hello, world!\n";
% printf ("%s", hello);
% return 0;
% }
% ¡ ¿
% \end{lstlisting}
% \end{onlyenv}
% \begin{onlyenv}<9>
% \begin{lstlisting}[gobble=6]
% #include <stdio.h>
%
% int main (void)
% {
% char *hello = "Hello, world!\n";
% printf ("%s", hello);
% return 0;
% }
% ¡ ¿
% \end{lstlisting}
% \end{onlyenv}
% \begin{onlyenv}<10>
% \begin{lstlisting}[gobble=6]
% #include <stdio.h>
%
% int main (void)
% {
% char *hello = "Hello, world!\n";
% while (*hello)
% printf ("%c", *hello++);
% return 0;
% }
% \end{lstlisting}
% \end{onlyenv}
\vspace{-1.7cm}\hfill
\begin{minipage}{6.8cm}
\begin{itemize}
\pause[2]
\item
Ein \lstinline{char} ist eine kleinere \lstinline{int}.
\pause
\item
Ein "`String"' in C ist ein Array von \lstinline{char}s\only<4->{,\\
also ein Zeiger auf \lstinline{char}s}\only<5->{\\
also ein Zeiger auf (kleinere) Integer}.
\pause
\pause
\pause
\item
Der letzte \lstinline{char} muß 0 sein.\\
Er kennzeichnet das Ende des Strings.
\pause
\item
Die Formatspezifikation\\
entscheidet über die Ausgabe:\\[\smallskipamount]
\begin{tabular}{ll}
\lstinline|%d|\hspace*{0.5em}dezimal
& \lstinline|%c|\hspace*{0.5em}Zeichen\\
\lstinline|%x|\hspace*{0.5em}hexadezimal
% \pause
% & \lstinline|%s|\hspace*{0.5em}String
\end{tabular}
\vspace*{-1cm}
\end{itemize}
\end{minipage}
\end{frame}
\addtocounter{subsection}{-1}
\subsection{Arrays und Strings \protect\color{gray}und Zeichen}
\begin{frame}[fragile]
\showsubsection
\emph{"`Alles ist Zahl."'\/} -- Schule der Pythagoreer, 6.\ Jh.\ v.\,Chr.
\medskip
\begin{center}
\renewcommand{\arraystretch}{1.5}
\begin{tabular}{r}
\lstinline|"Hello"|\\
\lstinline|'H'|\\
\lstinline|'a' + 4|
\end{tabular}
\renewcommand{\arraystretch}{1.0}
\begin{tabular}{c}
ist nur eine andere\\
Schreibweise für
\end{tabular}
\renewcommand{\arraystretch}{1.5}
\begin{tabular}{l}
\lstinline|{ 72, 101, 108, 108, 111, 0 }|\\
\lstinline|72|\\
\lstinline|'e'|
\end{tabular}
\renewcommand{\arraystretch}{1.0}
\end{center}
\begin{itemize}
\item
Welchen Zahlenwert hat \lstinline{'*'} im Zeichensatz?
\smallskip
\begin{lstlisting}[gobble=8]
printf ("%d\n", '*');
\end{lstlisting}
\smallskip
(normalerweise: ASCII)
\medskip
\item
Ist \lstinline{char ch} ein Großbuchstabe?
\smallskip
\begin{lstlisting}[gobble=8]
if (ch >= 'A' && ch <= 'Z')
...
\end{lstlisting}
\medskip
\item
Groß- in Kleinbuchstaben umwandeln
\smallskip
\begin{lstlisting}[gobble=8]
ch += 'a' - 'A';
\end{lstlisting}
\end{itemize}
\end{frame}
\subsection{Strukturen}
\begin{frame}[fragile]
\showsubsection
\begin{lstlisting}
#include <stdio.h>
typedef struct
{
char day, month;
int year;
}
date;
int main (void)
{
date today = { 17, 10, 2022 };
printf ("%d.%d.%d\n", today.day, today.month, today.year);
return 0;
}
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]
\showsubsection
\vspace*{0.9mm}
\begin{minipage}[b]{6cm}
\begin{lstlisting}[gobble=6]
¡#include <stdio.h>
typedef struct
{
char day, month;
int year;
}
date;
void set_date (date *d)
{
(*d).day = 17;
(*d).month = 10;
(*d).year = 2022;
}¿
\end{lstlisting}
\end{minipage}%
\begin{minipage}[b]{6cm}
\begin{lstlisting}[gobble=6]
¡int main (void)
{
date today;
set_date (&today);
printf ("%d.%d.%d\n", today.day,
today.month, today.year);
return 0;
}¿
\end{lstlisting}
\end{minipage}
\end{frame}
\begin{frame}[fragile]
\showsubsection
\vspace*{0.9mm}
\begin{minipage}[b]{6cm}
\begin{lstlisting}[gobble=6]
¡#include <stdio.h>
typedef struct
{
char day, month;
int year;
}
date;
void set_date (date *d)
{
d->day = 17;
d->month = 10;
d->year = 2022;
}¿
\end{lstlisting}
\end{minipage}%
\begin{minipage}[b]{6cm}
\hspace*{-1cm}%
\lstinline{foo->bar}
ist Abkürzung für
\lstinline{(*foo).bar}
\bigskip
\visible<2->{%
\hspace*{-1cm}%
Eine Funktion, die mit einem \lstinline{struct} arbeitet,\\
\hspace*{-1cm}%
kann man eine \newterm{Methode\/} des \lstinline{struct} nennen.}
\bigskip
\bigskip
\begin{lstlisting}[gobble=6]
¡int main (void)
{
date today;
set_date (&today);
printf ("%d.%d.%d\n", today.day,
today.month, today.year);
return 0;
}¿
\end{lstlisting}
\end{minipage}
\end{frame}
\subsection{Dateien und Fehlerbehandlung}
\begin{frame}[fragile]
\showsubsection
\vspace*{-0.2925cm}
\begin{minipage}[t]{6cm}
\begin{onlyenv}<1>
\begin{lstlisting}[gobble=8]
¡#include <stdio.h>
int main (void)
{
FILE *f = fopen ("fhello.txt", "w");
fprintf (f, "Hello, world!\n");
fclose (f);
return 0;
}¿
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<2>
\begin{lstlisting}[gobble=8]
¡#include <stdio.h>
int main (void)
{
FILE *f = fopen ("fhello.txt", "w");
if (f)
{
fprintf (f, "Hello, world!\n");
fclose (f);
}
return 0;
}¿
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<3>
\begin{lstlisting}[gobble=8]
¡#include <stdio.h>
#include <errno.h>
int main (void)
{
FILE *f = fopen ("fhello.txt", "w");
if (f)
{
fprintf (f, "Hello, world!\n");
fclose (f);
}
else
fprintf (stderr, "error #%d\n", errno);
return 0;
}¿
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<4>
\begin{lstlisting}[gobble=8]
¡#include <stdio.h>
#include <errno.h>
#include <string.h>
int main (void)
{
FILE *f = fopen ("fhello.txt", "w");
if (f)
{
fprintf (f, "Hello, world!\n");
fclose (f);
}
else
{
char *msg = strerror (errno);
fprintf (stderr, "%s\n", msg);
}
return 0;
}¿
\end{lstlisting}
\vspace*{-1cm}
\end{onlyenv}
\begin{onlyenv}<5->
\begin{lstlisting}[gobble=8]
¡#include <stdio.h>
#include <errno.h>
#include <er¡ror.h>
int main (void)
{
FILE *f = fopen ("fhello.txt", "w");
if (!f)
error (errno, errno, "cannot open file");
fprintf (f, "Hello, world!\n");
fclose (f);
return 0;
}
\end{lstlisting}
\end{onlyenv}
\end{minipage}\pause\hspace*{-1.5cm}%
\begin{minipage}[t]{8.5cm}
\bigskip
\only<3->{\bigskip}
\begin{itemize}
\item
Wenn die Datei nicht geöffnet werden kann,\\
gibt \lstinline{fopen()} den Wert \lstinline{NULL} zurück.
\pause
\medskip
\item
\addtolength{\leftskip}{1cm}
Die globale Variable \lstinline{int errno}\\
enthält dann die Nummer des Fehlers.\\
Benötigt: \lstinline{#include <errno.h>}
\pause
\medskip
\only<5->{\bigskip}
\item
Die Funktion \lstinline{strerror()} wandelt \lstinline{errno}\\
in einen Fehlermeldungstext um.\\
Benötigt: \lstinline{#include <string.h>}
\pause
\medskip
\item
\addtolength{\leftskip}{-1.5cm}
Die Funktion \lstinline{error()} gibt eine Fehlermeldung aus\\
und beendet das Programm.\\
Benötigt: \lstinline{#include <er¡¿ror.h>}
\pause
\medskip
\item
\textbf{Niemals Fehler einfach ignorieren!}
\end{itemize}
\addtolength{\leftskip}{0.5cm}
\end{minipage}
\end{frame}
\subsection{Parameter des Hauptprogramms}
\begin{frame}[fragile]
\showsubsection
\begin{lstlisting}
#include <stdio.h>
int main (int argc, char **argv)
{
printf ("argc = %d\n", argc);
for (int i = 0; i < argc; i++)
printf ("argv[%d] = \"%s\"\n", i, argv[i]);
return 0;
}
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]
\showsubsection
\begin{lstlisting}
#include <stdio.h>
int main (int argc, char **argv)
{
printf ("argc = %d\n", argc);
for (int i = 0; *argv; i++, argv++)
printf ("argv[%d] = \"%s\"\n", i, *argv);
return 0;
}
\end{lstlisting}
\end{frame}
\subsection{String-Operationen}
\begin{frame}[fragile]
\showsubsection
% \vspace*{-0.4cm}
\begin{lstlisting}
#include <stdio.h>
#include <string.h>
int main (void)
{
char hello[] = "Hello, world!\n";
printf ("%s\n", hello);
printf ("%zd\n", strlen (hello));
printf ("%s\n", hello + 7);
printf ("%zd\n", strlen (hello + 7));
hello[5] = 0;
printf ("%s\n", hello);
printf ("%zd\n", strlen (hello));
return 0;
}
\end{lstlisting}
\vspace*{-1cm}
\end{frame}
\begin{frame}[fragile]
\showsubsection
% \vspace*{-0.4cm}
\begin{lstlisting}
#include <stdio.h>
#include <string.h>
int main (void)
{
char *anton = "Anton";
char *zacharias = "Zacharias";
printf ("%d\n", strcmp (anton, zacharias));
printf ("%d\n", strcmp (zacharias, anton));
printf ("%d\n", strcmp (anton, anton));
char buffer[100] = "Huber ";
strcat (buffer, anton);
printf ("%s\n", buffer);
return 0;
}
\end{lstlisting}
\vspace*{-1cm}
\end{frame}
\begin{frame}[fragile]
\showsubsection
% \vspace*{-0.4cm}
\begin{lstlisting}
#include <stdio.h>
#include <string.h>
int main (void)
{
char buffer[100] = "";
sprintf (buffer, "Die Antwort lautet: %d", 42);
printf ("%s\n", buffer);
char *answer = strstr (buffer, "Antwort");
printf ("%s\n", answer);
printf ("found at: %zd\n", answer - buffer);
return 0;
}
\end{lstlisting}
\vspace*{-1cm}
\end{frame}
\begin{frame}[fragile]
\showsubsection
% \vspace*{-0.4cm}
\begin{lstlisting}
#include <stdio.h>
#include <string.h>
int main (void)
{
char buffer[100] = "";
snprintf (buffer, 100, "Die Antwort lautet: %d", 42);
printf ("%s\n", buffer);
char *answer = strstr (buffer, "Antwort");
printf ("%s\n", answer);
printf ("found at: %zd\n", answer - buffer);
return 0;
}
\end{lstlisting}
\end{frame}
\begin{frame}
\showsection
Sprachelemente weitgehend komplett
\bigskip
Es fehlen:
\begin{itemize}
\item
Ergänzungen (z.\,B.\ ternärer Operator, \lstinline{union}, \lstinline{unsigned}, \lstinline{volatile})
\item
Bibliotheksfunktionen (z.\,B.\ \lstinline{malloc()})
\arrowitem
werden eingeführt, wenn wir sie brauchen
\bigskip
\item
Konzepte (z.\,B.\ rekursive Datenstrukturen, Klassen selbst bauen)
\arrowitem
werden eingeführt, wenn wir sie brauchen, oder:
\arrowitem
Literatur\\[\smallskipamount]
(z.\,B.\ Wikibooks: C-Programmierung,\\
Dokumentation zu Compiler und Bibliotheken)
\bigskip
\item
Praxiserfahrung
\arrowitem
Übung und Praktikum: nur Einstieg
\arrowitem
selbständig arbeiten
\end{itemize}
\end{frame}
\nosectionnonumber{\inserttitle}
\begin{frame}
\shownosectionnonumber
\begin{itemize}
\item[\textbf{1}] \textbf{Einführung}
\hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}}
\item[\textbf{2}] \textbf{Einführung in C}
\begin{itemize}
\vspace{-1.5\smallskipamount}
\item[\dots]
\item[2.7] Strukturierte Programmierung
\item[2.8] Seiteneffekte
\item[2.9] Funktionen
\item[2.10] Zeiger
\item[2.11] Arrays und Strings
\item[2.12] Strukturen
\item[2.13] Dateien und Fehlerbehandlung
\item[2.14] Parameter des Hauptprogramms
\color{medgreen}
\item[2.15] String-Operationen
\end{itemize}
\item[\textbf{3}] \textbf{Bibliotheken}
\vspace*{-\smallskipamount}
\item[\textbf{\dots}]
% \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
% \item[\textbf{5}] \textbf{Algorithmen}
% \item[\textbf{6}] \textbf{Ergänzungen und Ausblicke}
\end{itemize}
\vspace*{-1cm}
\end{frame}
\section{Bibliotheken}
\subsection{Der Präprozessor}
\begin{frame}[fragile]
\showsection
\showsubsection
\lstinline{#include}: %\pause:
Text einbinden
\begin{itemize}
\pause
\item
\lstinline{#include <stdio.h>}: Standard-Verzeichnisse -- Standard-Header
\pause
\item
\lstinline{#include "answer.h"}: auch aktuelles Verzeichnis -- eigene Header
\end{itemize}
\pause
\bigskip
\lstinline{#define SIX 6}: Text ersetzen lassen -- Konstante definieren
\begin{itemize}
\pause
\item
Kein Semikolon!
\pause
\item
Berechnungen in Klammern setzen:\\
\lstinline{#define SIX (1 + 5)}
\pause
\item
Konvention: Großbuchstaben
\end{itemize}
\end{frame}
\subsection{Bibliotheken einbinden}
\begin{frame}[fragile]
\showsection
\showsubsection
Inhalt der Header-Datei: externe Deklarationen
\pause
\smallskip
\lstinline{extern int answer (void);}
\pause
\smallskip
\lstinline{extern int printf (__const char *__restrict __format, ...);}
\pause
\bigskip
Funktion wird "`anderswo"' definiert
\begin{itemize}
\pause
\item
separater C-Quelltext: mit an \lstinline[style=terminal]{gcc} übergeben
\pause
\item
Zusammenfügen zu ausführbarem Programm durch den \newterm{Linker}
\pause
\item
vorcompilierte Bibliothek: \lstinline[style=terminal]{-lfoo}\\
\pause
= Datei \file{libfoo.a} in Standard-Verzeichnis
\end{itemize}
\end{frame}
\subsection{Bibliothek verwenden (Beispiel: GTK)}
\begin{frame}[fragile]
\showsubsection
\begin{itemize}
\item
\lstinline{#include <gtk/gtk.h>}
\pause
\smallskip
\item
Mit \lstinline[style=cmd]{pkg-config --cflags --libs} erfährt man,\\
welche Optionen und Bibliotheken man an \lstinline[style=cmd]{gcc}
übergeben muß\alt<4->{.}{:}
\pause
\begin{onlyenv}<3>
\begin{lstlisting}[style=terminal,gobble=10]
$ ¡pkg-config --cflags --libs gtk4¿
-I/usr/include/gtk-4.0 -I/usr/include/pango-1.0 -I/usr/
include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/i
nclude -I/usr/include/harfbuzz -I/usr/include/freetype2
-I/usr/include/libpng16 -I/usr/include/libmount -I/usr/
include/blkid -I/usr/include/fribidi -I/usr/include/cai
ro -I/usr/include/pixman-1 -I/usr/include/gdk-pixbuf-2.
0 -I/usr/include/x86_64-linux-gnu -I/usr/include/graphe
ne-1.0 -I/usr/lib/x86_64-linux-gnu/graphene-1.0/include
-mfpmath=sse -msse -msse2 -pthread -lgtk-4 -lpangocairo
-1.0 -lpango-1.0 -lharfbuzz -lgdk_pixbuf-2.0 -lcairo-go
bject -lcairo -lgraphene-1.0 -lgio-2.0 -lgobject-2.0 -l
glib-2.0
\end{lstlisting}
\vspace*{-3cm}
\end{onlyenv}
\pause
\arrowitem
Compiler-Aufruf:
\begin{onlyenv}<4>
\begin{lstlisting}[style=terminal,gobble=10]
$ ¡gcc -Wall -O hello-gtk.c -I/usr/include/gtk-4.0 -I/u
sr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib
/x86_64-linux-gnu/glib-2.0/include -I/usr/include/harfb
uzz -I/usr/include/freetype2 -I/usr/include/libpng16 -I
/usr/include/libmount -I/usr/include/blkid -I/usr/inclu
de/fribidi -I/usr/include/cairo -I/usr/include/pixman-1
-I/usr/include/gdk-pixbuf-2.0 -I/usr/include/x86_64-lin
ux-gnu -I/usr/include/graphene-1.0 -I/usr/lib/x86_64-li
nux-gnu/graphene-1.0/include -mfpmath=sse -msse -msse2
-pthread -lgtk-4 -lpangocairo -1.0 -lpango-1.0 -lharfbu
zz -lgdk_pixbuf-2.0 -lcairo-gobject -lcairo -lgraphene-
1.0 -lgio-2.0 -lgobject-2.0 -l glib-2.0 -o hello-gtk¿
\end{lstlisting}
\vspace*{-2cm}
\end{onlyenv}
\begin{onlyenv}<5->
\begin{lstlisting}[style=terminal,gobble=10]
$ ¡gcc -Wall -O hello-gtk.c $(pkg-config --cflags --libs
gtk4) -o hello-gtk¿
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<5>
\begin{picture}(0,0)(0.3,0.3)
\color{red}
\put(6.6,-0.6){\makebox(0,0)[bl]{\tikz{\draw[-latex](0,0)--(3,1.5);}}}
\put(6.3,-0.7){\makebox(0,0)[t]{\shortstack{\strut Optionen:\\
\strut u.\,a.\ viele Include-Verzeichnisse:\\
\lstinline[style=cmd]{-I/usr/include/gtk-4.0}}}}
\put(10.0,-2.1){\makebox(0,0)[bl]{\tikz{\draw[-latex](0,0)--(1.5,3);}}}
\put(10.3,-2.2){\makebox(0,0)[t]{\shortstack{\strut Bibliotheken:\\
\strut u.\,a.\ \lstinline[style=cmd]{-lgtk-4}}}}
\end{picture}
\end{onlyenv}
\pause
\pause
\item
Auf manchen Plattformen kommt es auf die Reihenfolge an:
\begin{lstlisting}[style=terminal,gobble=8]
$ ¡gcc -Wall -O $(pkg-config --cflags gtk4) \
hello-gtk.c $(pkg-config --libs gtk4) \
-o hello-gtk¿
\end{lstlisting}
(Backslash = "`Es geht in der nächsten Zeile weiter."')
\end{itemize}
\end{frame}
\subsection{Callbacks}
\begin{frame}[fragile]
\showsubsection
Selbst geschriebene Funktion übergeben: \newterm{Callback}
\bigskip
\begin{lstlisting}[xleftmargin=1em]
static void hello (GtkWidget *this, gpointer user_data)
{
char *world = user_data;
printf ("Hello, %s!\n", world);
}
...
g_signal_connect (button, "clicked", G_CALLBACK (hello), "world");
\end{lstlisting}
\medskip
\begin{itemize}
\arrowitem
GTK ruft immer dann, wenn der Button betätigt wurde,\\
die Funktion \lstinline{hello} auf.
\end{itemize}
\pause
\begin{picture}(0,0)(1.1,0.8)
\color{red}
\put(9.7,5.1){\makebox(0,0)[br]{\tikz{\draw[-latex](0,0)--(-0.3,0.5);}}}
\put(10.0,5.0){\makebox(0,0)[t]{\shortstack{\strut optionale Zusatzinformationen\\
\strut für hello(), hier ein String\\
\strut oft ein Zeiger auf ein struct}}}
\put(10.5,3.5){\makebox(0,0)[tl]{\tikz{\draw[-latex](0,0)--(0.3,-0.5);}}}
\end{picture}
\end{frame}
\begin{frame}[fragile]
\showsubsection
Selbst geschriebene Funktion übergeben: \newterm{Callback}
\bigskip
\begin{lstlisting}[xleftmargin=1em]
static void draw (GtkDrawingArea *drawing_area, cairo_t *c,
int width, int height, gpointer user_data)
{
/* Zeichenbefehle */
...
}
...
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (drawing_area),
draw, NULL, NULL);
\end{lstlisting}
\medskip
\begin{itemize}
\arrowitem
GTK ruft immer dann, wenn es etwas zu zeichnen gibt,\\
die Funktion \lstinline{draw} auf.
\end{itemize}
\pause
\begin{picture}(0,0)
\color{red}
\put(10.0,4.9){\makebox(0,0)[br]{\tikz{\draw[-latex](0,0)--(-0.3,0.9);}}}
\put(10.0,4.8){\makebox(0,0)[t]{\shortstack{\strut repräsentiert den\\
\strut Bildschirm, auf den\\
\strut gezeichnet werden soll}}}
\end{picture}
\end{frame}
\iffalse
\begin{frame}[fragile]
\showsubsection
Selbst geschriebene Funktion übergeben: \newterm{Callback}
\bigskip
\begin{lstlisting}[xleftmargin=1em]
gboolean timer (GtkWidget *widget)
{
/* Rechenbefehle */
...
gtk_widget_queue_draw_area (widget, 0, 0, WIDTH, HEIGHT);
g_timeout_add (50, (GSourceFunc) timer, widget);
return FALSE;
}
...
g_timeout_add (50, (GSourceFunc) timer, drawing_area);
\end{lstlisting}
\medskip
\begin{itemize}
\arrowitem
GTK+ ruft nach 50 Millisekunden
die Funktion \lstinline{timer} auf.
\end{itemize}
\pause
\begin{picture}(0,0)(-0.07,0.2)
\color{red}
\put(9.7,6.7){\makebox(0,0)[t]{\shortstack{\strut Dieser Bereich soll\\
\strut neu gezeichnet werden.}}}
\put(9.7,5.7){\makebox(0,0)[tr]{\tikz{\draw[-latex](0,0)--(-0.6,-0.8);}}}
\pause
\put(4.3,3.2){\makebox(0,0)[br]{\tikz{\draw[-latex](0,0)--(-0.7,0.6);}}}
\put(4.3,3.1){\makebox(0,0)[t]{\shortstack{\strut In weiteren 50 Millisekunden soll\\
\strut die Funktion erneut aufgerufen werden.}}}
\pause
\put(9.3,2.9){\makebox(0,0)[br]{\tikz{\draw[-latex](0,0)--(-3.3,0.9);}}}
\put(9.8,2.8){\makebox(0,0)[t]{\shortstack{\strut Explizite Typumwandlung\\
\strut eines Zeigers (später)}}}
\end{picture}
\end{frame}
\fi
\nosectionnonumber{\inserttitle}
\begin{frame}
\shownosectionnonumber
\begin{itemize}
\item[\textbf{1}] \textbf{Einführung}
\hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}}
\item[\textbf{2}] \textbf{Einführung in C}
\begin{itemize}
\vspace{-1.5\smallskipamount}
\item[\dots]
\item[2.11] Arrays und Strings
\item[2.12] Strukturen
\item[2.13] Dateien und Fehlerbehandlung
\item[2.14] Parameter des Hauptprogramms
\color{medgreen}
\item[2.15] String-Operationen
\end{itemize}
\item[\textbf{3}] \textbf{Bibliotheken}
\begin{itemize}
\color{medgreen}
\item[3.1] Der Präprozessor
\item[3.2] Bibliotheken einbinden
\item[3.3] Bibliotheken verwenden
\color{orange}
\item[3.4] Callbacks
\color{red}
\item[3.5] Projekt organisieren: make
\end{itemize}
\item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
\vspace*{-\smallskipamount}
\item[\textbf{\dots}]
% \item[\textbf{5}] \textbf{Algorithmen}
% \item[\textbf{6}] \textbf{Ergänzungen und Ausblicke}
\end{itemize}
\end{frame}
\end{document}
File added
% hp-musterloesung-20231026.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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, Strings, Programm analysieren
\documentclass[a4paper]{article}
\usepackage{pgscript}
\renewcommand{\breath}{\bigskip}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- 26.\ Oktober 2023}
\exercise{Arrays mit Zahlen}
\begin{minipage}[t]{0.4\textwidth}
Wir betrachten das folgende Programm\\
(Datei: \gitfile{hp}{2023ws/20231026}{aufgabe-1.c}):
\begin{lstlisting}[gobble=6]
#include <stdio.h>
void f (int *s0, int *s1)
{
while (*s0 >= 0)
{
int *s = s1;
while (*s >= 0)
if (*s0 == *s++)
printf ("%d ", *s0);
s0++;
}
printf ("\n");
}
int main (void)
{
int a[] = { 10, 4, 3, 7, 12, 0, 1, -1 };
int b[] = { 7, 14, 0, 8, 9, 22, 10, -1 };
f (a, b);
return 0;
}
\end{lstlisting}
\end{minipage}\hfill
\begin{minipage}[t]{0.55\textwidth}
\vspace*{-\bigskipamount}
\begin{enumerate}[\quad(a)]
\item
Was bewirkt die Funktion \lstinline{f},\\
und wie funktioniert sie?
\points{4}
% \item
% Von welcher Ordnung (Landau-Symbol) ist die Funktion?
% Begründen Sie Ihre Antwort.
%
% Wir beziehen uns hierbei auf die Anzahl der Vergleiche
% in Abhängigkeit von der Länge der Eingabedaten \lstinline{s0} und \lstinline{s1}.
% Für die Rechnung dürfen Sie beide Längen mit $n$ gleichsetzen,
% obwohl sie normalerweise nicht gleich sind.
% \points{2}
\item
Was passiert, wenn Sie beim Aufruf der Funktion für einen der
Parameter den Wert \lstinline{NULL} übergeben?
Begründen Sie Ihre Antwort.
\points{2}
\item
Was kann passieren, wenn Sie das Hauptprogramm wie folgt abändern
(\gitfile{hp}{2023ws/20231026}{aufgabe-1c.c})?
Begründen Sie Ihre Antwort.
\begin{lstlisting}[gobble=8]
int main (void)
{
int a[] = { 10, 4, 3, 7, 12, 0, 1 };
int b[] = { 7, 14, 0, 8, 9, 22, 10 };
f (a, b);
return 0;
}
\end{lstlisting}
\points{2}
% \item
% Beschreiben Sie -- in Worten und/oder als C-Quelltext --, wie
% sich die Funktion \lstinline{f} effizienter gestalten läßt,
% wenn man die ihr übergebenen Arrays \lstinline{s0} und
% \lstinline{s1} als sortiert voraussetzt.
% \points{5}
%
% Hinweis: Wie würden Sie als Mensch die Aufgabe erledigen?
% \item
% Von welcher
% Ordnung (Landau-Symbol) ist Ihre effizientere Version der Funktion und warum?
% \points{2}
\end{enumerate}
\end{minipage}
\solution
\begin{enumerate}[\quad(a)]
\item
\textbf{Was bewirkt die Funktion \lstinline{f}, und wie funktioniert sie?}
Die Funktion gibt alle Zahlen aus, die sowohl im Array \lstinline{s0}
als auch im Array \lstinline{s1} vorkommen (Schnittmenge).
Dies geschieht, indem der Zeiger \lstinline{s0} das gesamte Array durchläuft
(äußere Schleife).
Für jedes Element des ersten Arrays durchläuft der Zeiger \lstinline{s}
das gesamte zweite Array (innere Schleife).
Auf diese Weise wird jedes Element von \lstinline{s0}
mit jedem von \lstinline{s1} verglichen und bei Gleichheit ausgegeben.
Um die Schleifen abbrechen zu können, enthalten beide Arrays
als Ende-Markierung eine negative Zahl (\lstinline{-1}).
\item
\textbf{Was passiert, wenn Sie beim Aufruf der Funktion für einen der
Parameter den Wert \lstinline{NULL} übergeben?
Begründen Sie Ihre Antwort.}
In dem Moment, wo auf den jeweiligen Parameter-Zeiger zugegriffen wird
(\lstinline{while (*s0 >= 0)} für \lstinline{s0} bzw.\
\lstinline{int *s = s1; while (*s >= 0)} für \lstinline{s1}),
kommt es zu einem Absturz (Speicherzugriffsfehler).
Die Dereferenzierung eines Zeigers mit dem Wert \lstinline{NULL}
ist nicht zulässig.
\item
\textbf{Was kann passieren, wenn Sie das Hauptprogramm wie folgt abändern
(\gitfile{hp}{2023ws/20231026}{aufgabe-1c.c})?
Begründen Sie Ihre Antwort.}
\begin{minipage}{0.35\textwidth}
\begin{lstlisting}[gobble=10]
int main (void)
{
int a[] = { 10, 4, 3, 7, 12, 0, 1 };
int b[] = { 7, 14, 0, 8, 9, 22, 10 };
f (a, b);
return 0;
}
\end{lstlisting}
\end{minipage}\hfill
\begin{minipage}{0.575\textwidth}
Durch die fehlenden Ende-Markierungen der Arrays
laufen die Schleifen immer weiter,
bis sie irgendwann zufällig auf Speicherzellen stoßen,
die sich als Ende-Markierungen interpretieren lassen (negative Zahlen).
Dadurch kann es zu einem Lesezugriff auf Speicher kommen,
für den das Programm kein Lesezugriffsrecht hat,
also zu einem Absturz (Speicherzugriffsfehler).
\end{minipage}
\end{enumerate}
\exercise{Datum-Bibliothek}
Schreiben Sie eine Bibliothek (\file{.c}-Datei und \file{.h}-Datei)
zur Behandlung von Datumsangaben.
Diese soll enthalten:
\begin{itemize}
\item
einen \lstinline{struct}-Datentyp \lstinline{date},
der eine Datumsangabe speichert,
\item
eine Funktion \lstinline{void date_print (date *d)}, die ein Datum ausgibt,
\item
eine Funktion \lstinline{int date_set (date *d, int day, int month, int year)},
die ein Datum auf einen gegebenen Tag setzt
und zurückgibt, ob es sich um ein gültiges Datum handelt (0 = nein, 1 = ja),
\item
eine Funktion \lstinline{void date_next (date *d)},
die ein Datum auf den nächsten Tag vorrückt.
\end{itemize}
Schreiben Sie auch ein Programm, das die o.\,a.\ Funktionen testet.
\solution
Die Dateien \gitfile{hp}{2023ws/20231026}{loesung-2.c},
\gitfile{hp}{2023ws/20231026}{loesung-2.h}
und \gitfile{hp}{2023ws/20231026}{loesung-2-test.c}
enthalten die Bibliothek und das Test-Programm.
Eine detaillierte Anleitung,
wie man auf die Funktion \lstinline{date_next()} kommt,
finden Sie im Skript zur Lehrveranstaltung,
Datei \gitfile{hp}{2023ws/script/hp-2023ws.pdf}{hp-2023ws.pdf},
ab Seite 29.
\exercise{Fehlerhaftes Primzahl-Programm}
\begin{minipage}[t]{5.5cm}
Das nebenstehende Primzahlsuchprogramm (Datei: \gitfile{hp}{2023ws/20231026}{aufgabe-3.c})
soll Zahlen ausgeben, die genau zwei Teiler haben, ist aber fehlerhaft.
\smallskip
Korrigieren Sie das Programm derart, daß ein Programm entsteht,
welches alle Primzahlen kleiner 100 ausgibt.% \points 5
\end{minipage}\hfill
\begin{minipage}[t]{9cm}
\vspace*{-0.5cm}
\begin{lstlisting}[gobble=6]
#include <stdio.h>
int main (void)
{
int n, i, divisors;
for (n = 0; n < 100; n++)
divisors = 0;
for (i = 0; i < n; i++)
if (n % i == 0)
divisors++;
if (divisors = 2)
printf ("%d ist eine Primzahl.\n", n);
return 0;
}
\end{lstlisting}
\end{minipage}
\solution
Beim Compilieren des Beispiel-Programms mit
\lstinline[style=cmd]{gcc -Wall} erhalten wir die folgende Warnung:
\begin{lstlisting}[style=terminal]
aufgabe-2.c:11:5: warning: suggest parentheses around assignment
used as truth value [-Wparentheses]
\end{lstlisting}
Beim Ausführen gibt das Programm die folgende (falsche) Behauptung aus:
\begin{lstlisting}[style=terminal]
100 ist eine Primzahl.
\end{lstlisting}
Einen ersten Hinweis auf den Fehler im Programm liefert die Warnung.
Die Bedingung \lstinline{if (divisors = 2)} in Zeile 11
steht \emph{nicht\/} für einen Vergleich
der Variablen \lstinline{divisors} mit der Zahl 2,
sondern für eine Zuweisung der Zahl 2 an die Variable \lstinline{divisors}.
Neben dem \emph{Seiteneffekt\/} der Zuweisung gibt \lstinline{divisors = 2}
den Wert \lstinline{2} zurück.
Als Bedingung interpretiert, hat \lstinline{2} den Wahrheitswert "`wahr"' ("`true"');
die \lstinline{printf()}-Anweisung wird daher in jedem Fall ausgeführt.
Korrektur dieses Fehlers: \lstinline{if (divisors == 2)}
-- siehe die Datei \gitfile{hp}{2023ws/20231026}{loesung-2-1.c}.
\bigskip
Nach der Korrektur dieses Fehlers compiliert das Programm ohne Warnung,
gibt aber beim Ausführen die folgende Fehlermeldung aus:
\begin{lstlisting}[style=terminal]
Gleitkomma-Ausnahme
\end{lstlisting}
(Bemerkung: Bei ausgeschalteter Optimierung
-- \lstinline[style=cmd]{gcc} ohne \lstinline[style=cmd]{-O} --
kommt diese Fehlermeldung bereits beim ersten Versuch, das Programm auszuführen.
Der Grund für dieses Verhalten ist, daß bei eingeschalteter Optimierung
irrelevante Teile des Programms entfernt und gar nicht ausgeführt werden,
so daß der Fehler nicht zum Tragen kommt.
In diesem Fall wurde die Berechnung von \lstinline{divisors} komplett wegoptimiert,
da der Wert dieser Variablen nirgendwo abgefragt,
sondern durch die Zuweisung \lstinline{if (divisors = 2)}
sofort wieder überschrieben wurde.)
Die Fehlermeldung "`\lstinline[style=terminal]{Gleitkomma-Ausnahme}"'
ist insofern irreführend, als daß hier gar keine Gleitkommazahlen im Spiel sind;
andererseits deutet sie auf einen Rechenfehler hin, was auch tatsächlich zutrifft.
Durch Untersuchen aller Rechenoperationen
-- z.\,B.\ durch das Einfügen zusätzlicher \lstinline{printf()} --
finden wir den Fehler in Zeile 9:
Die Modulo-Operation \lstinline{n % i} ist eine Division,
die dann fehlschlägt, wenn der Divisor \lstinline{i} den Wert 0 hat.
Die Fehlerursache ist die bei 0 beginnende \lstinline{for}-Schleife in Zeile 8:
\lstinline{for (i = 0; i < n; i++)}.
Korrektur dieses Fehlers: Beginn der Schleife mit \lstinline{i = 1}
statt \lstinline{i = 0} -- siehe die Datei \gitfile{hp}{2023ws/20231026}{loesung-2-2.c}.
\bigskip
Nach der Korrektur dieses Fehlers gibt das Programm überhaupt nichts mehr aus.
Durch Untersuchen des Verhaltens des Programms
-- z.\,B.\ durch das Einfügen zusätzlicher \lstinline{printf()} --
stellen wir fest, daß die Zeilen 8 bis 12 des Programms nur einmal ausgeführt werden
und nicht, wie die \lstinline{for}-Schleife in Zeile 6 vermuten ließe, 100mal.
Der Grund dafür ist, daß sich die \lstinline{for}-Schleife
nur auf die unmittelbar folgende Anweisung \lstinline{divisors = 0} bezieht.
Nur diese Zuweisung wird 100mal ausgeführt;
alles andere befindet sich außerhalb der \lstinline{for}-Schleife.
(Die Einrückung hat in C keine inhaltliche Bedeutung,
sondern dient nur zur Verdeutlichung der Struktur des Programms.
In diesem Fall entsprach die tatsächliche Struktur nicht der beabsichtigten.)
Korrektur dieses Fehlers:
geschweifte Klammern um den Inhalt der äußeren \lstinline{for}-Schleife
-- siehe die Datei \gitfile{hp}{2023ws/20231026}{loesung-2-3.c}.
\bigskip
Nach der Korrektur dieses Fehlers gibt das Programm folgendes aus:
\begin{lstlisting}[style=terminal]
4 ist eine Primzahl.
9 ist eine Primzahl.
25 ist eine Primzahl.
49 ist eine Primzahl.
\end{lstlisting}
Diese Zahlen sind keine Primzahlen (mit zwei Teilern),
sondern sie haben drei Teiler.
Demnach findet das Programm einen Teiler zu wenig.
(Um diesen Fehler zu finden, kann man sich zu jeder Zahl
die gefundene Anzahl der Teiler \lstinline{divisors} ausgeben lassen.)
Der nicht gefundene Teiler ist jeweils die Zahl selbst.
Dies kommt daher, daß die Schleife
\lstinline{for (i = 1; i < n; i++)} nur bis \lstinline{n - 1} geht,
also keine Division durch \lstinline{n} stattfindet.
Korrektur dieses Fehlers: Schleifenbedingung \lstinline{i <= n}
statt \lstinline{i < n}
-- siehe die Datei \gitfile{hp}{2023ws/20231026}{loesung-2-4.c}.
\bigskip
Nach der Korrektur dieses Fehlers verhält sich das Programm korrekt.
Die Datei \gitfile{hp}{2023ws/20231026}{loesung-2-4.c} enthält somit das korrigierte Programm.
\end{document}
File added
% hp-uebung-20231026.pdf - Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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: Arrays mit Zahlen, Datum-Bibliothek, fehlerhaftes Primzahl-Programm
\documentclass[a4paper]{article}
\usepackage{pgscript}
\begin{document}
\thispagestyle{empty}
\section*{Hardwarenahe Programmierung\\
Übungsaufgaben -- 26.\ Oktober 2023}
Diese Übung enthält Punkteangaben wie in einer Klausur.
Um zu "`bestehen"', müssen Sie innerhalb von 60 Minuten
unter Verwendung ausschließlich zugelassener Hilfsmittel
10 Punkte (von insgesamt \totalpoints) erreichen.
\exercise{Arrays mit Zahlen}
\begin{minipage}[t]{0.4\textwidth}
Wir betrachten das folgende Programm\\
(Datei: \gitfile{hp}{2023ws/20231026}{aufgabe-1.c}):
\begin{lstlisting}[gobble=6]
#include <stdio.h>
void f (int *s0, int *s1)
{
while (*s0 >= 0)
{
int *s = s1;
while (*s >= 0)
if (*s0 == *s++)
printf ("%d ", *s0);
s0++;
}
printf ("\n");
}
int main (void)
{
int a[] = { 10, 4, 3, 7, 12, 0, 1, -1 };
int b[] = { 7, 14, 0, 8, 9, 22, 10, -1 };
f (a, b);
return 0;
}
\end{lstlisting}
\end{minipage}\hfill
\begin{minipage}[t]{0.55\textwidth}
\vspace*{-\bigskipamount}
\begin{enumerate}[\quad(a)]
\item
Was bewirkt die Funktion \lstinline{f},\\
und wie funktioniert sie?
\points{4}
% \item
% Von welcher Ordnung (Landau-Symbol) ist die Funktion?
% Begründen Sie Ihre Antwort.
%
% Wir beziehen uns hierbei auf die Anzahl der Vergleiche
% in Abhängigkeit von der Länge der Eingabedaten \lstinline{s0} und \lstinline{s1}.
% Für die Rechnung dürfen Sie beide Längen mit $n$ gleichsetzen,
% obwohl sie normalerweise nicht gleich sind.
% \points{2}
\item
Was passiert, wenn Sie beim Aufruf der Funktion für einen der
Parameter den Wert \lstinline{NULL} übergeben?
Begründen Sie Ihre Antwort.
\points{2}
\item
Was kann passieren, wenn Sie das Hauptprogramm wie folgt abändern
(\gitfile{hp}{2023ws/20231026}{aufgabe-1c.c})?
Begründen Sie Ihre Antwort.
\begin{lstlisting}[gobble=8]
int main (void)
{
int a[] = { 10, 4, 3, 7, 12, 0, 1 };
int b[] = { 7, 14, 0, 8, 9, 22, 10 };
f (a, b);
return 0;
}
\end{lstlisting}
\points{2}
% \item
% Beschreiben Sie -- in Worten und/oder als C-Quelltext --, wie
% sich die Funktion \lstinline{f} effizienter gestalten läßt,
% wenn man die ihr übergebenen Arrays \lstinline{s0} und
% \lstinline{s1} als sortiert voraussetzt.
% \points{5}
%
% Hinweis: Wie würden Sie als Mensch die Aufgabe erledigen?
% \item
% Von welcher
% Ordnung (Landau-Symbol) ist Ihre effizientere Version der Funktion und warum?
% \points{2}
\end{enumerate}
\end{minipage}
\exercise{Datum-Bibliothek}
Schreiben Sie eine Bibliothek (\file{.c}-Datei und \file{.h}-Datei)
zur Behandlung von Datumsangaben.
Diese soll enthalten:
\begin{itemize}
\item
einen \lstinline{struct}-Datentyp \lstinline{date},
der eine Datumsangabe speichert,
\item
eine Funktion \lstinline{void date_print (date *d)}, die ein Datum ausgibt,
\item
eine Funktion \lstinline{int date_set (date *d, int day, int month, int year)},
die ein Datum auf einen gegebenen Tag setzt
und zurückgibt, ob es sich um ein gültiges Datum handelt (0 = nein, 1 = ja),
\item
eine Funktion \lstinline{void date_next (date *d)},
die ein Datum auf den nächsten Tag vorrückt.
\end{itemize}
Schreiben Sie auch ein Programm, das die o.\,a.\ Funktionen testet.
\points{8}
\exercise{Fehlerhaftes Primzahl-Programm}
\begin{minipage}[t]{5.5cm}
Das nebenstehende Primzahlsuchprogramm (Datei: \gitfile{hp}{2023ws/20231026}{aufgabe-3.c})
soll Zahlen ausgeben, die genau zwei Teiler haben, ist aber fehlerhaft.
\smallskip
Korrigieren Sie das Programm derart, daß ein Programm entsteht,
welches alle Primzahlen kleiner 100 ausgibt. \points 5
\end{minipage}\hfill
\begin{minipage}[t]{9cm}
\vspace*{-0.5cm}
\begin{lstlisting}[gobble=6]
#include <stdio.h>
int main (void)
{
int n, i, divisors;
for (n = 0; n < 100; n++)
divisors = 0;
for (i = 0; i < n; i++)
if (n % i == 0)
divisors++;
if (divisors = 2)
printf ("%d ist eine Primzahl.\n", n);
return 0;
}
\end{lstlisting}
\end{minipage}
\makeatletter
\immediate\write\@mainaux{\string\gdef\string\totalpoints{\arabic{points}}}
\makeatother
\end{document}
#include <stdio.h>
#include "loesung-2.h"
void check (char day, char month, int year)
{
date d;
if (date_set (&d, day, month, year))
{
date_print (&d);
printf (" --> ");
date_next (&d);
date_print (&d);
printf ("\n");
}
else
printf ("%02d.%02d.%04d: invalid date\n", day, month, year);
}
int main (void)
{
check (6, 11, 2018);
check (29, 11, 2018);
check (30, 11, 2018);
check (31, 11, 2018);
check (29, 12, 2018);
check (30, 12, 2018);
check (31, 12, 2018);
check (28, 2, 2016);
check (29, 2, 2016);
check (30, 2, 2016);
check (28, 2, 2015);
check (29, 2, 2015);
check (30, 2, 2015);
check (31, 12, 2008);
check (28, 2, 2000);
check (29, 2, 2000);
check (30, 2, 2000);
check (28, 2, 1900);
check (29, 2, 1900);
check (30, 2, 1900);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment