diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..1a99cc2c297e318fc1260cba78223c1a3399b812
--- /dev/null
+++ b/README.md
@@ -0,0 +1,75 @@
+Hardwarenahe Programmierung
+===========================
+
+Lehrveranstaltung im Wintersemester 2020/21  
+Hochschule Bochum, Campus Velbert/Heiligenhaus  
+Prof. Dr. rer. nat. Peter Gerwinski
+
+Copyright © 2012–2020  Peter Gerwinski
+
+**Diese Lehrmaterialien sind freie Software.**  
+Sie dürfen diese gemäß den jeweils angegebenen Lizenzen  
+([CC-BY-SA 3.0](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/CC-BY-SA-3.0),
+[GNU GPL 3+](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/GNU-GPL-3),
+[modified BSD License](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/BSD-MODIFIED))  
+studieren, kopieren, modifizieren und/oder weitergeben.  
+Für Details siehe [common/README](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/README).
+
+Vortragsfolien und Beispiele:
+-----------------------------
+ * [05.11.2020: Einführung, Einführung in C (bis Schleifen)](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20201105/hp-20201105.pdf) [**(Beispiele)**](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/20201105/)
+ * [alle in 1 Datei](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/hp-slides-2020ws.pdf)
+
+Übungsaufgaben:
+---------------
+ * [05.11.2020: Hello-World-Programme, Schaltjahr ermitteln, Maximum berechnen](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20201105/hp-uebung-20201105.pdf)
+
+Musterlösungen:
+---------------
+(keine)
+
+Tafelbilder:
+------------
+(keine)
+
+Praktikumsunterlagen:
+---------------------
+(keine)
+
+Alte Klausuren:
+---------------
+
+Skript:
+-------
+ * [Hardwarenahe Programmierung](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/script/hp-2020ws.pdf)
+
+Original-Materialien einschließlich Beispiel-Programme und LaTeX-Quelltexte:
+----------------------------------------------------------------------------
+ * [common – gemeinsame Dateien für Skript und Vortragsfolien](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/common)
+ * [script – Skript zur Lehrveranstaltung](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/script)
+ * [201????? – Vortragsfolien und Beispiele](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master)
+ * [branch 2018ws – vollständige Lehrmaterialien vom Wintersemester 2018/19](https://gitlab.cvh-server.de/pgerwinski/hp/tree/2018ws)
+
+
+Low-Level Programming
+=====================
+
+Course in winter semester 2020-21
+Bochum University of Applied Sciences, Campus Velbert/Heiligenhaus  
+Prof. Dr. rer. nat. Peter Gerwinski
+
+Copyright © 2012–2020  Peter Gerwinski
+
+**These teaching materials are Free Software.**  
+You may study, copy, modify, and/or distribute them  
+according to their respective licences  
+([CC-BY-SA 3.0](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/CC-BY-SA-3.0),
+[GNU GPL 3+](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/GNU-GPL-3),
+[modified BSD License](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/BSD-MODIFIED)).  
+See the file [common/README](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/README) for details.
+
+ * [common – common files for lecture notes and slides](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/common)
+ * [script – lecture notes](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/script)
+ * [201????? – slides and examples](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master)
+ * [hp-slides-2020ws.pdf – all slides in 1 file](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/hp-slides-2020ws.pdf)
+ * [branch 2018ws – complete teaching materials from winter semester 2018–19](https://gitlab.cvh-server.de/pgerwinski/hp/tree/2018ws)
diff --git a/hp-slides-2020ws.pdf b/hp-slides-2020ws.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..96d24eaefd6e4c6e1bd8cf2f4fa9e0ccdcc0be5d
Binary files /dev/null and b/hp-slides-2020ws.pdf differ
diff --git a/hp-slides-2020ws.tex b/hp-slides-2020ws.tex
new file mode 100644
index 0000000000000000000000000000000000000000..509b56d9361c36cd915ea4bfd337236c2f3b5f0f
--- /dev/null
+++ b/hp-slides-2020ws.tex
@@ -0,0 +1,15 @@
+\documentclass{article}
+
+\usepackage[final]{pdfpages}
+\usepackage[paperwidth=363pt,paperheight=272pt]{geometry}
+\usepackage{hyperref}
+
+\pagestyle{empty}
+
+\begin{document}
+  \includepdf[pages=1]{script/hp-slides-title-2020ws.pdf}
+  \pdfbookmark[1]{Wichtiger Hinweis}{Hinweis}
+  \includepdf[pages=2-]{script/hp-slides-title-2020ws.pdf}
+  \pdfbookmark[1]{05.11.2020: Einführung, Einführung in C (bis Schleifen)}{20201105}
+  \includepdf[pages=-]{20201105/hp-20201105.pdf}
+\end{document}
diff --git a/script/Tower_of_Hanoi.jpeg b/script/Tower_of_Hanoi.jpeg
new file mode 120000
index 0000000000000000000000000000000000000000..a1a794afda08596ffa2f46f278db53455de25b6c
--- /dev/null
+++ b/script/Tower_of_Hanoi.jpeg
@@ -0,0 +1 @@
+../common/Tower_of_Hanoi.jpeg
\ No newline at end of file
diff --git a/script/Zeichen_101_-_Gefahrstelle,_StVO_1970.pdf b/script/Zeichen_101_-_Gefahrstelle,_StVO_1970.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..8f90a0d169c4b94a85845ccc3dad9b2877799c9b
Binary files /dev/null and b/script/Zeichen_101_-_Gefahrstelle,_StVO_1970.pdf differ
diff --git a/script/Zeichen_101_-_Gefahrstelle,_StVO_1970.svg b/script/Zeichen_101_-_Gefahrstelle,_StVO_1970.svg
new file mode 100644
index 0000000000000000000000000000000000000000..d399442a10e479bbb92058b13e1aafa2fbcd3503
--- /dev/null
+++ b/script/Zeichen_101_-_Gefahrstelle,_StVO_1970.svg
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   viewBox="0 0 847.15857 743.62268"
+   height="743.62268"
+   width="847.15857"
+   xml:space="preserve"
+   version="1.1"
+   id="svg5488"><metadata
+     id="metadata5494"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+     id="defs5492" /><g
+     transform="matrix(1.25,0,0,-1.25,0,743.62267)"
+     id="g5496"><g
+       id="g5498"><path
+         id="path5500"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 338.867,594.5 c -7.512,0 -15.027,-2.867 -20.758,-8.598 -1.879,-1.879 -3.445,-3.953 -4.707,-6.152 l -15.246,-26.157 -0.07,0 L 4.984,45.554 C 4.93,45.457 4.887,45.359 4.832,45.261 3.344,42.867 2.176,40.218 1.406,37.351 -2.789,21.695 6.504,5.597 22.164,1.402 c 2.586,-0.695 5.184,-1.012 7.738,-1 l 618.067,0 c 16.215,0 29.355,13.141 29.355,29.356 0,5.304 -1.414,10.281 -3.879,14.578 -0.019,0.031 -0.035,0.062 -0.05,0.097 l -304.368,528.41 c -3.863,6.665 -5.652,9.305 -9.406,13.059 -5.73,5.731 -13.242,8.598 -20.754,8.598 z" /><path
+         id="path5502"
+         style="fill:#c1121c;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 338.867,587.144 c -7.125,0.051 -14.949,-3.59 -18.781,-10.406 L 10.793,40.847 C 9.008,37.199 8.258,34.027 8.234,30.398 c 0,-6.496 2.875,-12.66 7.848,-16.84 4.383,-3.394 8.535,-5.16 14.121,-5.16 l 617.906,0 c 3.77,-0.035 7.547,0.871 10.977,3.133 6.453,3.898 10.402,10.883 10.41,18.426 -0.184,3.894 -1.144,8 -2.879,10.89 L 357.504,576.828 c -0.027,0.047 -0.059,0.094 -0.09,0.14 -0.031,0.047 -0.062,0.094 -0.094,0.145 -1.097,1.754 -2.472,3.305 -4.039,4.633 -3.59,3.109 -8.086,4.976 -12.824,5.316 -0.531,0.047 -1.062,0.078 -1.59,0.082 z M 30.203,8.398 l -1.523,0 1.554,0 -0.031,0 z M 338.547,480.933 574.25,72.398 l -471.738,0 236.035,408.535 z" /><path
+         id="path5504"
+         style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 338.867,594.898 c -7.617,0 -15.23,-2.906 -21.039,-8.715 -1.906,-1.902 -3.492,-4.008 -4.773,-6.234 l -15.129,-25.957 -0.071,0 L 4.641,45.754 C 4.574,45.636 4.527,45.535 4.48,45.453 2.977,43.031 1.797,40.351 1.02,37.457 -3.23,21.586 6.191,5.269 22.059,1.015 24.68,0.312 27.316,-0.008 29.902,0 l 618.067,0 c 16.429,0 29.758,13.328 29.758,29.758 0,5.375 -1.438,10.417 -3.934,14.773 -0.012,0.019 -0.027,0.051 -0.051,0.098 L 369.379,573.043 c -3.871,6.668 -5.695,9.363 -9.469,13.14 -5.808,5.809 -13.426,8.715 -21.039,8.715 l -0.004,0 z m 0,-0.398 c 7.512,0 15.024,-2.867 20.754,-8.598 3.754,-3.754 5.543,-6.394 9.406,-13.059 L 673.391,44.433 c 0.019,-0.035 0.035,-0.066 0.054,-0.097 2.465,-4.297 3.879,-9.274 3.879,-14.578 0,-16.215 -13.14,-29.356 -29.355,-29.356 l -618.067,0 C 27.348,0.39 24.75,0.707 22.164,1.402 6.504,5.597 -2.789,21.695 1.406,37.351 c 0.766,2.867 1.938,5.516 3.426,7.91 0.055,0.098 0.098,0.196 0.152,0.293 l 293.102,508.039 0.07,0 15.246,26.157 c 1.262,2.199 2.828,4.273 4.707,6.152 5.731,5.731 13.243,8.598 20.758,8.598 z" /><path
+         id="path5506"
+         style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 338.867,408.414 c -17.676,0 -32.004,-14.328 -32.004,-32 l 16,-188.016 c 0,-8.836 6.371,-16.015 16.004,-16 9.629,0.016 15.996,7.82 15.996,16.012 l 16,188.004 c 0,17.672 -14.324,32 -31.996,32 z" /><path
+         id="path5508"
+         style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="m 370.863,124.398 c 0,-17.683 -14.316,-31.996 -31.996,-31.996 -17.676,0 -32.004,14.309 -32.004,31.996 0,17.672 14.328,32.004 32.004,32.004 17.68,0 31.996,-14.332 31.996,-32.004" /></g></g></svg>
\ No newline at end of file
diff --git a/script/Zeichen_123.pdf b/script/Zeichen_123.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..fdbc897227df059cfda790a16555e6e417682116
--- /dev/null
+++ b/script/Zeichen_123.pdf
@@ -0,0 +1 @@
+../common/Zeichen_123.pdf
\ No newline at end of file
diff --git a/script/answer.c b/script/answer.c
new file mode 100644
index 0000000000000000000000000000000000000000..65a1dc248becb3157f2a226fc7b30df2ffb82e00
--- /dev/null
+++ b/script/answer.c
@@ -0,0 +1,6 @@
+#include "answer.h"
+
+int answer (void)
+{
+  return 23;
+}
diff --git a/script/answer.h b/script/answer.h
new file mode 100644
index 0000000000000000000000000000000000000000..b6777e8210983d315b3ac3424a61bd9c9f0437b1
--- /dev/null
+++ b/script/answer.h
@@ -0,0 +1 @@
+extern int answer (void);
diff --git a/script/arrays-1.c b/script/arrays-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..2582e4953f11963bc5a71bb055829c9b95fc2f68
--- /dev/null
+++ b/script/arrays-1.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int prime[5] = { 2, 3, 5, 7, 11 };
+  int *p = prime;
+  int i;
+  for (i = 0; i < 5; i++)
+    printf ("%d\n", *(p + i));
+  return 0;
+}
diff --git a/script/arrays-2.c b/script/arrays-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..8affefa7b74afcbe0effbbe0ff32a577c696f21e
--- /dev/null
+++ b/script/arrays-2.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int prime[5] = { 2, 3, 5, 7, 11 };
+  int *p = prime;
+  int i;
+  for (i = 0; i < 5; i++)
+    printf ("%d\n", p[i]);
+  return 0;
+}
diff --git a/script/bsort-1.c b/script/bsort-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c02adc72e6a7e702e2c7c68c838fc94cc8ef547
--- /dev/null
+++ b/script/bsort-1.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, int left, int right)
+{
+  int result = strcmp (name[left], name[right]);
+  comparisons++;
+  display (name, left, right);
+  usleep (200000);
+  return result;
+}
+
+void sort (char **name)
+{
+  for (int i = 1; name[i]; i++)
+    if (compare (name, i - 1, i) > 0)
+      {
+        char *temp = name[i - 1];
+        name[i - 1] = name[i];
+        name[i] = temp;
+      }
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  sort (name);
+  display (name, -1, -1);
+  return 0;
+}
diff --git a/script/bsort-1a.c b/script/bsort-1a.c
new file mode 100644
index 0000000000000000000000000000000000000000..348b638843002926f57cdcf1d4fbc9bd88d2a10c
--- /dev/null
+++ b/script/bsort-1a.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, int left, int right)
+{
+  int result = strcmp (name[left], name[right]);
+  comparisons++;
+  display (name, left, right);
+  usleep (200000);
+  return result;
+}
+
+void sort (char **name)
+{
+  for (int i = 1; name[i]; i++)
+    if (compare (name, i - 1, i) > 0)
+      {
+        char *temp = name[i - 1];
+        name[i - 1] = name[i];
+        name[i] = temp;
+      }
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Zacharias", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", NULL };
+  sort (name);
+  display (name, -1, -1);
+  return 0;
+}
diff --git a/script/bsort-2.c b/script/bsort-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..d277be0182a40ecd0c66eaeef94d7aebac6aa542
--- /dev/null
+++ b/script/bsort-2.c
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, int left, int right)
+{
+  int result = strcmp (name[left], name[right]);
+  comparisons++;
+  display (name, left, right);
+  usleep (200000);
+  return result;
+}
+
+void sort (char **name)
+{
+  int sorted = 0;
+  while (name[sorted])
+    sorted++;
+  while (sorted > 0)
+    {
+      for (int i = 1; i < sorted; i++)
+        if (compare (name, i - 1, i) > 0)
+          {
+            char *temp = name[i - 1];
+            name[i - 1] = name[i];
+            name[i] = temp;
+          }
+      sorted--;
+    }
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  sort (name);
+  display (name, -1, -1);
+  return 0;
+}
diff --git a/script/bsort-3.c b/script/bsort-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..67d0097b913171b4523f4f04b6b6ff494046dabd
--- /dev/null
+++ b/script/bsort-3.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, int left, int right)
+{
+  int result = strcmp (name[left], name[right]);
+  comparisons++;
+  display (name, left, right);
+  usleep (200000);
+  return result;
+}
+
+void sort (char **name)
+{
+  int done = 0;
+  int sorted = 0;
+  while (name[sorted])
+    sorted++;
+  while (sorted > 0 && !done)
+    {
+      done = 1;
+      for (int i = 1; i < sorted; i++)
+        if (compare (name, i - 1, i) > 0)
+          {
+            done = 0;
+            char *temp = name[i - 1];
+            name[i - 1] = name[i];
+            name[i] = temp;
+          }
+      sorted--;
+    }
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  sort (name);
+  display (name, -1, -1);
+  return 0;
+}
diff --git a/script/bsort-4.c b/script/bsort-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..241270a46f4ffa005d252207d769c3c4059ed7e2
--- /dev/null
+++ b/script/bsort-4.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, int left, int right)
+{
+  int result = strcmp (name[left], name[right]);
+  comparisons++;
+  display (name, left, right);
+  usleep (200000);
+  return result;
+}
+
+void sort (char **name)
+{
+  int sorted = 0;
+  while (name[sorted])
+    sorted++;
+  while (sorted > 0)
+    {
+      int new_sorted = 0;
+      for (int i = 1; i < sorted; i++)
+        if (compare (name, i - 1, i) > 0)
+          {
+            new_sorted = i;
+            char *temp = name[i - 1];
+            name[i - 1] = name[i];
+            name[i] = temp;
+          }
+      sorted = new_sorted;
+    }
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  sort (name);
+  display (name, -1, -1);
+  return 0;
+}
diff --git a/script/cube-1.c b/script/cube-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..2f9328f07a9e6f35bb50535911fd0a327a5b6669
--- /dev/null
+++ b/script/cube-1.c
@@ -0,0 +1,21 @@
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#include "opengl-magic.h"
+
+void draw (void)
+{
+  glClear (GL_COLOR_BUFFER_BIT + GL_DEPTH_BUFFER_BIT);
+  set_material_color (1.0, 0.7, 0.0);
+  glutSolidCube (0.75);
+  glFlush ();
+  glutSwapBuffers ();
+}
+
+int main (int argc, char **argv)
+{
+  init_opengl (&argc, argv, "Cube");
+  glutDisplayFunc (draw);
+  glutMainLoop ();
+  return 0;
+}
diff --git a/script/cube-2.c b/script/cube-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..0df28c7e4901f3653611c3803bc7df4d68a84121
--- /dev/null
+++ b/script/cube-2.c
@@ -0,0 +1,22 @@
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#include "opengl-magic.h"
+
+void draw (void)
+{
+  glClear (GL_COLOR_BUFFER_BIT + GL_DEPTH_BUFFER_BIT);
+  set_material_color (1.0, 0.7, 0.0);
+  glRotatef (-30.0, 0.5, 1.0, 0.0);
+  glutSolidCube (0.75);
+  glFlush ();
+  glutSwapBuffers ();
+}
+
+int main (int argc, char **argv)
+{
+  init_opengl (&argc, argv, "Cube");
+  glutDisplayFunc (draw);
+  glutMainLoop ();
+  return 0;
+}
diff --git a/script/cube-3.c b/script/cube-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..ef326a1f58b7e5396fc2102907a3ba6a671b1bbf
--- /dev/null
+++ b/script/cube-3.c
@@ -0,0 +1,32 @@
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#include "opengl-magic.h"
+
+float t = 0.0;
+
+void draw (void)
+{
+  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  set_material_color (1.0, 0.7, 0.0);
+  glRotatef (t, 0.5, 1.0, 0.0);
+  glutSolidCube (0.5);
+  glFlush ();
+  glutSwapBuffers ();
+}
+
+void timer_handler (int value)
+{
+  t += 0.05;
+  glutPostRedisplay ();
+  glutTimerFunc (50, timer_handler, 0);
+}
+
+int main (int argc, char **argv)
+{
+  init_opengl (&argc, argv, "Cube");
+  glutDisplayFunc (draw);
+  glutTimerFunc (50, timer_handler, 0);
+  glutMainLoop ();
+  return 0;
+}
diff --git a/script/cube-4.c b/script/cube-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..9dfb48d59fbbc5221a6f5599089aa2f1a694209a
--- /dev/null
+++ b/script/cube-4.c
@@ -0,0 +1,34 @@
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#include "opengl-magic.h"
+
+float t = 0.0;
+
+void draw (void)
+{
+  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  set_material_color (1.0, 0.7, 0.0);
+  glPushMatrix ();
+  glRotatef (t, 0.5, 1.0, 0.0);
+  glutSolidCube (0.5);
+  glPopMatrix ();
+  glFlush ();
+  glutSwapBuffers ();
+}
+
+void timer_handler (int value)
+{
+  t += 0.05;
+  glutPostRedisplay ();
+  glutTimerFunc (50, timer_handler, 0);
+}
+
+int main (int argc, char **argv)
+{
+  init_opengl (&argc, argv, "Cube");
+  glutDisplayFunc (draw);
+  glutTimerFunc (50, timer_handler, 0);
+  glutMainLoop ();
+  return 0;
+}
diff --git a/script/cube-5.c b/script/cube-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..5cbb7d0065fa2c51fc5a268e964b418306034234
--- /dev/null
+++ b/script/cube-5.c
@@ -0,0 +1,34 @@
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#include "opengl-magic.h"
+
+float t = 0.0;
+
+void draw (void)
+{
+  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  set_material_color (1.0, 0.7, 0.0);
+  glPushMatrix ();
+  glRotatef (20.0 * t, 0.5, 1.0, 0.0);
+  glutSolidCube (0.5);
+  glPopMatrix ();
+  glFlush ();
+  glutSwapBuffers ();
+}
+
+void timer_handler (int value)
+{
+  t += 0.05;
+  glutPostRedisplay ();
+  glutTimerFunc (50, timer_handler, 0);
+}
+
+int main (int argc, char **argv)
+{
+  init_opengl (&argc, argv, "Cube");
+  glutDisplayFunc (draw);
+  glutTimerFunc (50, timer_handler, 0);
+  glutMainLoop ();
+  return 0;
+}
diff --git a/script/cube-6.c b/script/cube-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..b82eb81195fd03c68073807e800759e9a6e55e4a
--- /dev/null
+++ b/script/cube-6.c
@@ -0,0 +1,35 @@
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#include "opengl-magic.h"
+
+float t = 0.0;
+
+void draw (void)
+{
+  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  set_material_color (1.0, 0.7, 0.0);
+  glPushMatrix ();
+  glTranslatef (0.9, 0.0, 0.0);
+  glRotatef (20.0 * t, 0.5, 1.0, 0.0);
+  glutSolidCube (0.5);
+  glPopMatrix ();
+  glFlush ();
+  glutSwapBuffers ();
+}
+
+void timer_handler (int value)
+{
+  t += 0.05;
+  glutPostRedisplay ();
+  glutTimerFunc (50, timer_handler, 0);
+}
+
+int main (int argc, char **argv)
+{
+  init_opengl (&argc, argv, "Cube");
+  glutDisplayFunc (draw);
+  glutTimerFunc (50, timer_handler, 0);
+  glutMainLoop ();
+  return 0;
+}
diff --git a/script/cube-7.c b/script/cube-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..b177ba0d9351d4c299503266b0f6df733ac8721d
--- /dev/null
+++ b/script/cube-7.c
@@ -0,0 +1,35 @@
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#include "opengl-magic.h"
+
+float t = 0.0;
+
+void draw (void)
+{
+  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  set_material_color (1.0, 0.7, 0.0);
+  glPushMatrix ();
+  glRotatef (20.0 * t, 0.5, 1.0, 0.0);
+  glTranslatef (0.9, 0.0, 0.0);
+  glutSolidCube (0.5);
+  glPopMatrix ();
+  glFlush ();
+  glutSwapBuffers ();
+}
+
+void timer_handler (int value)
+{
+  t += 0.05;
+  glutPostRedisplay ();
+  glutTimerFunc (50, timer_handler, 0);
+}
+
+int main (int argc, char **argv)
+{
+  init_opengl (&argc, argv, "Cube");
+  glutDisplayFunc (draw);
+  glutTimerFunc (50, timer_handler, 0);
+  glutMainLoop ();
+  return 0;
+}
diff --git a/script/earth-texture.png b/script/earth-texture.png
new file mode 120000
index 0000000000000000000000000000000000000000..c55876c24a42b6e0bb353e9e4789127e5b33e470
--- /dev/null
+++ b/script/earth-texture.png
@@ -0,0 +1 @@
+../common/earth-texture.png
\ No newline at end of file
diff --git a/script/fhello-1.c b/script/fhello-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..6548d9c81c73a7f3da8b1b2e62290bc8029d11f0
--- /dev/null
+++ b/script/fhello-1.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main (void)
+{
+  FILE *f = fopen ("fhello.txt", "w");
+  fprintf (f, "Hello, world!\n");
+  fclose (f);
+  return 0;
+}
diff --git a/script/fhello-2.c b/script/fhello-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..6bd3fc97506fab7643dfe4d59a957cfa1a600750
--- /dev/null
+++ b/script/fhello-2.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+int main (void)
+{
+  FILE *f = fopen ("fhello.txt", "w");
+  if (f)
+    {
+      fprintf (f, "Hello, world!\n");
+      fclose (f);
+    }
+  return 0;
+}
diff --git a/script/fhello-3.c b/script/fhello-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..529ddffd80d4a17c9fc89bf07f9da2368f412ea3
--- /dev/null
+++ b/script/fhello-3.c
@@ -0,0 +1,15 @@
+#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;
+}
diff --git a/script/fhello-4.c b/script/fhello-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..2719776d312c79509d2863c5eabce09236db255c
--- /dev/null
+++ b/script/fhello-4.c
@@ -0,0 +1,19 @@
+#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;
+}
diff --git a/script/fhello-5.c b/script/fhello-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..038e0a3693708ca63281fce8e6d8f977d75ca8f4
--- /dev/null
+++ b/script/fhello-5.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+
+int main (void)
+{
+  FILE *f = fopen ("fhello.txt", "w");
+  if (!f)
+     error (1, errno, "cannot open file");
+  fprintf (f, "Hello, world!\n");
+  fclose (f);
+  return 0;
+}
diff --git a/script/fhello-6.c b/script/fhello-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..8572d98de1fa9eef81ec260592bc5c2fa3399a02
--- /dev/null
+++ b/script/fhello-6.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <errno.h>
+#include <error.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;
+}
diff --git a/script/functions-1.c b/script/functions-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..10f26249461a77f1db7691b0bedd754d8ade5e0a
--- /dev/null
+++ b/script/functions-1.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+void foo (int a, int b)
+{
+  printf ("foo(): a = %d, b = %d\n", a, b);
+}
+
+int main (void)
+{
+  foo (3, 7);
+  return 0;
+}
diff --git a/script/functions-2.c b/script/functions-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..23ea1d20a629fcb69f88d44dc010da45572791ba
--- /dev/null
+++ b/script/functions-2.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+
+int a, b = 3;
+
+void foo (void)
+{
+  b++;
+  static int a = 5;
+  int b = 7;
+  printf ("foo(): a = %d, b = %d\n", a, b);
+  a++;
+  b++;
+}
+
+int main (void)
+{
+  printf ("main(): a = %d, b = %d\n", a, b);
+  foo ();
+  printf ("main(): a = %d, b = %d\n", a, b);
+  a = b = 12;
+  printf ("main(): a = %d, b = %d\n", a, b);
+  foo ();
+  printf ("main(): a = %d, b = %d\n", a, b);
+  return 0;
+}
diff --git a/script/hello-1.c b/script/hello-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..b19d80e9bd0bd7c5ed8f54b20c6a50d9166f03ac
--- /dev/null
+++ b/script/hello-1.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Hello, world!\n");
+  return 0;
+}
diff --git a/script/hello-2.c b/script/hello-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..15d0bc8e9b71c25fcd70d60b5f188d930ffa04b4
--- /dev/null
+++ b/script/hello-2.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Hello, world!\n");
+  "\n";
+  return 0;
+}
diff --git a/script/hexe.h b/script/hexe.h
new file mode 100644
index 0000000000000000000000000000000000000000..2b98e2bb0231a5114084d64430290fea93281edc
--- /dev/null
+++ b/script/hexe.h
@@ -0,0 +1 @@
+eine kleine Hexe.
diff --git a/script/higher-math-1.c b/script/higher-math-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d1a61a7f3f115e878707bf9ab97d8536e46e9bb
--- /dev/null
+++ b/script/higher-math-1.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#define VIER 4
+
+int main (void)
+{
+  printf ("2 + 2 = %d\n", VIER);
+  return 0;
+}
diff --git a/script/higher-math-2.c b/script/higher-math-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..4f8bfec89f2f1d3a82ee0911dadee9d3955bed50
--- /dev/null
+++ b/script/higher-math-2.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+#define wuppdich printf
+#define holla main
+#define pruzzel return
+#define VIER 4
+
+int holla (void)
+{
+  wuppdich ("2 + 2 = %d\n", VIER);
+  pruzzel 0;
+}
diff --git a/script/higher-math-3.c b/script/higher-math-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..0774461371a771e36ef4682648194a3161f4e1b6
--- /dev/null
+++ b/script/higher-math-3.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#define VIER 2 + 2
+
+int main (void)
+{
+  printf ("2 + 3 * 4 = %d\n", 2 + 3 * VIER);
+  return 0;
+}
diff --git a/script/higher-math-4.c b/script/higher-math-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..66907e2c7865f7e345f31376748ebfd62134fa43
--- /dev/null
+++ b/script/higher-math-4.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#define VIER (2 + 2)
+
+int main (void)
+{
+  printf ("2 + 3 * 4 = %d\n", 2 + 3 * VIER);
+  return 0;
+}
diff --git a/script/higher-math-5.c b/script/higher-math-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..77a4e4ccc520044f3be85c473f440f313ac9f0fa
--- /dev/null
+++ b/script/higher-math-5.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#define VIER (2 + 2));
+
+int main (void)
+{
+  printf ("2 + 3 * 4 = %d\n", 2 + 3 * VIER
+  return 0;
+}
diff --git a/script/hp-2019ws.pdf b/script/hp-2019ws.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..eab13eeb248cdd96d7ae143e812fffbbffde1e07
Binary files /dev/null and b/script/hp-2019ws.pdf differ
diff --git a/script/hp-2019ws.tex b/script/hp-2019ws.tex
new file mode 100644
index 0000000000000000000000000000000000000000..9f44ecd7250c6a89ec08983eb70536f20ac14948
--- /dev/null
+++ b/script/hp-2019ws.tex
@@ -0,0 +1,5876 @@
+% hp-2018ws.pdf - Lecture Notes on Applied Computer Sciences
+% Copyright (C) 2012, 2013, 2015, 2016, 2018  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/>.
+
+\documentclass[a4paper]{article}
+
+\usepackage{pgscript}
+\usepackage{pdftricks}
+\usepackage{rotating}
+\usepackage{amsfonts}
+\usepackage[helvet]{sfmath}
+\usepackage{tikz}
+
+\newcommand{\name}[1]{\textsc{#1}}
+\newcommand{\ccbysanp}{CC-by-sa (Version 3.0, nicht portiert)}
+\newcommand{\fdl}{GNU FDL (Version 1.2 oder höher)}
+\newcommand{\mylicense}{CC-by-sa (Version 3.0) oder GNU GPL (Version 3 oder höher)}
+\newcommand{\pd}{gemeinfrei -- \emph{public domain}}
+
+\newcommand{\underconstruction}{%
+  \begin{minipage}{6cm}
+    \begin{center}
+      \includegraphics[width=2cm]{Zeichen_123.pdf}
+
+      Dieser Abschnitt ist\\
+      noch nicht fertig.
+    \end{center}
+  \end{minipage}}
+
+\makeatletter
+  \newcommand{\figurecaptionraw}[2]{%
+    \def\n{\hfill\break}
+    \refstepcounter{figure}%
+    \addcontentsline{lof}{figure}%
+      {\protect\numberline{\hspace{-1.5em}Abb.~\thefigure}{\ignorespaces #1}}%
+    \begingroup
+      \def\n{\break}
+      \@makecaption{\csname fnum@figure\endcsname}{\ignorespaces #1}\par
+    \endgroup
+    \addtocontents{lof}{\begingroup\leftskip3.8em #2\par\endgroup}
+  }
+\makeatother
+\newcommand{\figurecaptionurl}[5]{%
+  \figurecaptionraw{#1}{Quelle: \protect\url{#2},\protect\\abgerufen am #3\protect\\Autor: #4\protect\\Lizenz: #5}}
+\newcommand{\figurecaptionurlurl}[5]{%
+  \figurecaptionraw{#1}{Quelle: \protect\url{#2},\protect\\abgerufen am #3\protect\\Autor: \protect\url{#4}\protect\\Lizenz: #5}}
+\newcommand{\figurecaptionself}[1]{\figurecaptionraw{#1}{Quelle/Autor: selbst erstellt\protect\\Lizenz: \mylicense}}
+
+\begin{psinputs}
+  \usepackage{pgscript}
+  \usepackage{pstricks,pst-grad,pst-node,pst-plot}
+  \psset{unit=1cm}
+\end{psinputs}
+
+\begin{document}
+  \thispagestyle{empty}
+  \makebox(0,0.0105)[tl]{\includegraphics[scale=1.008]{logo-hochschule-bochum-cvh-text-v2.pdf}}\hfill
+  \makebox(0,0)[tr]{\includegraphics[scale=0.7]{logo-hochschule-bochum.pdf}}%
+  \vfill
+  \begin{center}
+    {\Huge\textbf{Hardwarenahe Programmierung}\par}
+    \vspace{2cm}
+    {\large Wintersemester 2019/20\\[\medskipamount]
+    Prof.~Dr.~rer.~nat.~Peter Gerwinski}
+  \end{center}
+  \vfill
+
+  \clearpage
+
+  \begingroup
+
+    \setlength{\leftskip}{3cm}
+
+    \strut\vfill
+
+    Stand: 11.\ Januar 2020
+
+    Soweit nicht anders angegeben:\\
+    Text und Bilder: Copyright \copyright\ 2012, 2013, 2015, 2016, 2018, 2020\quad Peter Gerwinski\\
+    Lizenz: \mylicense
+
+    Sie können dieses Skript
+    einschließlich Vortragsfolien, Beispielprogramme und sonstiger Lehrmaterialien
+    unter \url{https://gitlab.cvh-server.de/pgerwinski/hp} herunterladen.
+
+  \endgroup
+
+  \clearpage
+
+  \tableofcontents
+
+  \clearpage
+
+  \section{Einführung}
+
+  \subsection{Was ist hardwarenahe Programmierung?}
+
+%  Die angewandte Informatik befaßt sich mit der Praxis der Programmierung von Computern.
+%  Sie vermittelt zwischen den Fachgebieten der Rechnertechnik
+%  ("`Wie funktioniert ein Computer?"') und der Softwaretechnik (Theorie des Programmierens).
+
+  In der Programmierung steht "`hardwarenah"'
+  für maximale Kontrolle des Programmierers über das genaue Verhalten der Hardware.
+  Im Gegensatz zur abstrakten Programmierung,
+  in der man als Programmierer in einer für Menschen möglichst komfortablen Weise
+  das gewünschte Verhalten des Computers beschreibt
+  und des den Programmierwerkzeugen überläßt,
+  auf welche Weise genau der Computer dies umsetzt,
+  geht es in der hardwarenahen Programmierung darum,
+  das Verhalten des Prozessors und jeder einzelnen Speicherzelle genau zu kennen.
+  
+  \begin{center}
+    \begin{pdfpic}
+      \begin{pspicture}(-5,0)(12,12)
+        \small
+        \psset{unit=0.5cm}
+        \psline[arrows=<->](-1,0)(-1,22)
+        \rput(-1.3,0){\makebox(0,0)[br]{\textbf{gegenständlich}}}
+        \rput(-1.3,22){\makebox(0,0)[tr]{\textbf{abstrakt}}}
+        \rput(-1.3,2){\makebox(0,0)[r]{Elektromagnetismus, Halbleiter}}
+        \rput(-1.3,4){\makebox(0,0)[r]{Elektronische Bauelemente}}
+        \rput(-1.3,6){\makebox(0,0)[r]{Logik-Schaltkreise}}
+        \rput(-1.3,8){\makebox(0,0)[r]{Prozessoren}}
+        \rput(-1.3,9){\makebox(0,0)[r]{Maschinensprache}}
+        \rput(-1.3,10){\makebox(0,0)[r]{Assembler}}
+        \rput(-1.3,11){\makebox(0,0)[r]{Ein-/Ausgabe}}
+        \rput(-1.3,12.35){\makebox(0,0)[r]{\textbf{hardwarenahe Programmierung} (z.\,B.\ in C)}}
+        \rput(-1.3,14){\makebox(0,0)[r]{\shortstack[r]{abstrahierende Programmierung\\(z.\,B.\ in C++, Java)}}}
+%          \rput(-1.3,15){\makebox(0,0)[r]{Programmierung}}
+        \rput(-1.3,16){\makebox(0,0)[r]{Algorithmen, Datenstrukturen, Software-Entwurf}}
+        \rput(-1.3,17){\makebox(0,0)[r]{Requirements Engineering}}
+        \rput(-1.3,18){\makebox(0,0)[r]{formale Sprachen, Berechenbarkeit}}
+        \rput(-1.3,19){\makebox(0,0)[r]{mathematische Strukturen}}
+        \rput(-1.3,20){\makebox(0,0)[r]{mathematische Beweise}}
+        \rput(2.1,0.5){\makebox(0,0)[l]{Physik}}
+        \rput(4.1,4){\makebox(0,0)[l]{Elektrotechnik}}
+        \rput(6.1,8){\makebox(0,0)[l]{Rechnertechnik}}
+        \rput(8.1,12.35){\makebox(0,0)[l]{angewandte Informatik}}
+        \rput(10.1,16){\makebox(0,0)[l]{\shortstack[l]{Softwaretechnik und\\theoretische Informatik}}}
+        \rput(12.1,21){\makebox(0,0)[l]{Mathematik}}
+        \psset{linewidth=0.001,linestyle=none,fillstyle=gradient,gradmidpoint=1.0,gradlines=1000}
+        \definecolor{RGBwhite}{rgb}{1.0,1.0,1.0}
+        \definecolor{RGBblue}{rgb}{0.0,0.0,1.0}
+        \definecolor{RGBred}{rgb}{1.0,0.0,0.0}
+        \definecolor{RGBgreen}{rgb}{0.0,1.0,0.0}
+        \definecolor{RGByellow}{rgb}{1.0,1.0,0.0}
+        \definecolor{RGBorange}{rgb}{1.0,0.7,0.0}
+        \definecolor{RGBgrey}{rgb}{0.7,0.7,0.7}
+        \rput(0,2){\psframe[gradbegin=RGBwhite,gradend=RGBblue](2,2)}
+        \rput(0,0){\psframe[fillstyle=solid,fillcolor=RGBblue](2,2.01)}
+        \rput(2,6){\psframe[gradbegin=RGBwhite,gradend=RGBred](2,2)}
+        \rput(2,2){\psframe[gradbegin=RGBred,gradend=RGBwhite](2,2)}
+        \rput(2,3.99){\psframe[fillstyle=solid,fillcolor=RGBred](2,2.02)}
+        \rput(4,10){\psframe[gradbegin=RGBwhite,gradend=RGBgreen](2,2)}
+        \rput(4,6){\psframe[gradbegin=RGBgreen,gradend=RGBwhite](2,2)}
+        \rput(4,7.99){\psframe[fillstyle=solid,fillcolor=RGBgreen](2,2.02)}
+        \rput(6,14){\psframe[gradbegin=RGBwhite,gradend=RGByellow](2,2)}
+        \rput(6,10){\psframe[gradbegin=RGByellow,gradend=RGBwhite](2,2)}
+        \rput(6,11.99){\psframe[fillstyle=solid,fillcolor=RGByellow](2,2.02)}
+        \rput(8,18){\psframe[gradbegin=RGBwhite,gradend=RGBorange](2,2)}
+        \rput(8,14){\psframe[gradbegin=RGBorange,gradend=RGBwhite](2,2)}
+        \rput(8,15.99){\psframe[fillstyle=solid,fillcolor=RGBorange](2,2.02)}
+        \rput(10,18){\psframe[gradbegin=RGBgrey,gradend=RGBwhite](2,2)}
+        \rput(10,19.99){\psframe[fillstyle=solid,fillcolor=RGBgrey](2,2.01)}
+      \end{pspicture}
+    \end{pdfpic}
+    \vspace{-\bigskipamount}
+    \figurecaptionself{Wissenschaftliche Disziplinen mit Bezug zur Informatik,\n
+                       angeordnet nach Abstraktionsgrad ihres jeweiligen Gegenstandes
+                       \label{Disziplinen}}
+  \end{center}
+
+  Im Gegensatz zu z.\,B.\ Lebewesen
+  werden Computer von Menschen entwickelt und gebaut.
+  Daher ist es grundsätzlich möglich, sie durch hardwarenahe Programmierung
+  vollständig zu verstehen und zu beherrschen.
+
+  \subsection{Programmierung in C}
+
+  Ein großer Teil dieser Vorlesung wird der Programmierung in der Programmiersprache C gewidmet sein.
+
+  Warum C?
+
+  C hat sich als Kompromiß zwischen einer Hochsprache und maximaler Nähe zur Hardware
+  sehr weit etabliert.
+  Es läuft auf nahezu jeder Plattform (= Kombination aus Hardware und Betriebssystem)
+  und stellt somit einen "`kleinsten gemeinsamen Nenner der Programmierung"' dar.
+  C orientiert sich sehr eng an der Funktionsweise der Computer-Hardware
+  und wird daher auch als "`High-Level-Assembler"' bezeichnet.
+
+  Wie die Assembler-Sprache, die Sie in \emph{Grundlagen Rechnertechnik\/} kennenlernen werden,
+  ist C ein Profi-Werkzeug und als solches "`leistungsfähig, aber gefährlich"'.
+  Programme können in C sehr kompakt geschrieben werden.
+  C kommt mit verhältnismäßig wenigen Sprach"-elementen aus,
+  die je nach Kombination etwas anderes bewirken.
+  Dies hat zur Folge, daß einfache Schreibfehler,
+  die in anderen Programmiersprachen als Fehler bemängelt würden,
+  in C häufig ein ebenfalls gültiges Programm ergeben,
+  das sich aber völlig anders als beabsichtigt verhält.
+
+  \breath
+
+  C wurde gemeinsam mit dem Betriebssystem Unix entwickelt
+  und hat mit diesem wichtige Eigenschaften gemeinsam:
+  \begin{itemize}
+    \item
+      \textbf{Kompakte Schreibweise:}
+      Häufig verwendete Konstrukte werden möglichst platzsparend notiert.
+      Wie in C, kann auch unter Unix ein falsch geschriebenes Kommando
+      ein ebenfalls gültiges Kommando mit anderer Wirkung bedeuten.
+    \item
+      \textbf{Baukastenprinzip:}
+      In C wie in Unix bemüht man sich darum, den unveränderlichen Kern möglichst klein zu halten.
+      Das meiste, was man in C tatsächlich benutzt, ist in Form von Bibliotheken modularisiert;
+      das meiste, was man unter Unix tatsächlich benutzt, ist in Form von Programmen modularisiert.
+    \item
+      \textbf{Konsequente Regeln:}
+      In C wie in Unix bemüht man sich darum,
+      feste Regeln -- mathematisch betrachtet -- möglichst einfach zu halten
+      und Ausnahmen zu vermeiden.
+      (Beispiel: Unter MS-DOS und seinen Nachfolgern wird eine ausführbare Datei gefunden,
+      wenn sie sich \emph{entweder} im aktuellen Verzeichnis \emph{oder} im Suchpfad befindet.
+      Unter Unix wird sie gefunden, wenn sie sich im Suchpfad befindet.
+      Es ist unter Unix möglich, das aktuelle Verzeichnis in den Suchpfad aufzunehmen;
+      aus Sicherheitserwägungen heraus geschieht dies jedoch üblicherweise nicht.)
+    \item
+      \textbf{Kein "`Fallschirm"':}
+      C und Unix führen Befehle ohne Nachfrage aus.
+      (Beispiel: Ein eingegebener Unix-Befehl zum Formatieren einer Festplatte
+      wird ohne Rückfrage ausgeführt.)
+  \end{itemize}
+
+  Trotz dieser Warnungen besteht bei Programmierübungen in C
+  normalerweise \emph{keine\/} Gefahr für den Rechner.
+  Moderne PC-Betriebssysteme überwachen die aufgerufenen Programme
+  und beenden sie notfalls mit einer Fehlermeldung ("`Schutzverletzung"').
+  Experimente mit Mikrocontrollern, die im Rahmen dieser Lehrveranstaltung stattfinden werden,
+  erfolgen ebenfalls in einer Testumgebung, in der kein Schaden entstehen kann.
+
+  Bitte nutzen Sie die Gelegenheit, in diesem Rahmen Ihre Programmierkenntnisse zu trainieren,
+  damit Sie später in Ihrer beruflichen Praxis,
+  wenn durch ein fehlerhaftes Programm ernsthafter Schaden entstehen kann,
+  wissen, was Sie tun.
+
+  \section{Einführung in C}
+
+  \subsection{Hello, world!}
+
+  Das folgende Beispiel-Programm (Datei: \gitfile{hp}{script}{hello-1.c})
+  gibt den Text "`Hello, world!"' auf dem Bildschirm aus:
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      printf ("Hello, world!\n");
+      return 0;
+    }
+  \end{lstlisting}
+  Dieses traditionell erste -- "`einfachste"' -- Beispiel enthält in C bereits viele Elemente,
+  die erst zu einem späteren Zeitpunkt zufriedenstellend erklärt werden können:
+  \begin{itemize}
+    \item
+      \lstinline{#include <stdio.h>}
+
+      Wir deuten diese Zeile im Moment so, daß uns damit gewisse Standardfunktionen
+      (darunter \lstinline{printf()} -- siehe unten) zur Verfügung gestellt werden.
+
+      Diese Betrachtungsweise ist nicht wirklich korrekt
+      und wird in Abschnitt \ref{Praeprozessor} genauer erklärt.
+
+    \item
+      \lstinline|int main (void) { ... }|
+
+      Dies ist das C-Hauptprogramm.
+      Das, was zwischen den geschweiften Klammern steht, wird ausgeführt.
+
+      Auch hier wird zu einem späteren Zeitpunkt (Abschnitt \ref{Funktionen})
+      genauer erklärt werden, was die einzelnen Elemente bedeuten und welchen Sinn sie haben.
+  \end{itemize}
+  \goodbreak
+  Im folgenden soll nun der eigentliche Inhalt des Programms erklärt werden:
+  \begin{lstlisting}
+    printf ("Hello, world!\n");
+    return 0;
+  \end{lstlisting}
+  \vspace{-\bigskipamount}
+  \begin{itemize}
+    \item
+      Bei beiden Zeilen handelt es sich um sogenannte \newterm{Anweisungen}.
+    \item
+      Jede Anweisung wird mit einem Semikolon abgeschlossen.
+    \item
+      Bei \lstinline{printf()} handelt es sich um einen \newterm{Funktionsaufruf},
+      dessen Wirkung darin besteht, daß der zwischen den Klammern angegebene \newterm{Parameter\/}
+      (oder: das \newterm{Argument\/}) der Funktion
+      auf dem Standardausgabegerät ausgegeben wird.
+      (In unserem Fall handelt es sich dabei um einen Bildschirm.)
+      Der Name "`\lstinline{printf}"' der Funktion steht für "`print formatted"' -- formatierte Ausgabe.
+    \item
+      \lstinline{"Hello, world!\n"} ist eine \newterm{Konstante\/}
+      vom Typ \newterm{String\/} (= Zeichenkette).
+    \item
+      \lstinline{\n} ist eine \newterm{Escape-Sequenz}.
+      Sie steht für ein einzelnes, normalerweise unsichtbares Zeichen
+      mit der Bedeutung "`neue Zeile"'.
+    \item
+      Die Anweisung \lstinline{return 0} bedeutet:
+      Beende die laufende Funktion (hier: \lstinline{main()}, also das Hauptprogramm)
+      mit dem Rückgabewert 0.
+      (Bedeutung: "`Programm erfolgreich ausgeführt."' --  siehe Abschnitt \ref{Funktionen}.)
+  \end{itemize}
+
+  \subsection{Programme compilieren und ausführen}
+
+  Der Programmtext wird mit Hilfe eines Eingabeprogramms, des \newterm{Texteditors},
+  in den Computer eingegeben und als Datei gespeichert.
+  Als Dateiname sei hier \gitfile{hp}{script}{hello-1.c} angenommen.
+  Die Dateiendung \file{.c} soll anzeigen,
+  daß es sich um einen Programmquelltext in der Programmiersprache C handelt.
+
+  Die \file{.c}-Datei ist für den Computer nicht direkt ausführbar.
+  Um eine ausführbare Datei zu erhalten,
+  muß das Programm zuerst in die Maschinensprache des verwendeten Computers übersetzt werden.
+  Diesen Vorgang nennt man \newterm{Compilieren}.
+
+  In einer Unix-Shell mit installierter GNU-Compiler-Collection
+  (GCC; frühere Bedeutung der Abkürzung: GNU-C-Compiler)
+  geschieht das Compilieren durch Eingabe der folgenden Zeile, der \newterm{Kommandozeile\/}:
+
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc hello-1.c -o hello-1¿
+  \end{lstlisting}
+
+  Das Zeichen \lstinline[style=terminal]{$} steht für die \newterm{Eingabeaufforderung\/}
+  (oder das \newterm{Prompt\/}) der Unix-Shell. Es kann auch anders aussehen, z.\,B.\
+  \lstinline[style=terminal]{pc42:~$} oder auch
+  \lstinline[style=terminal]{cassini/home/peter/bo/2018ws/hp/script>}.
+  Die Eingabe"-aufforderung wird vom Computer ausgegeben;
+  die Kommandozeile rechts daneben müssen wir eingeben und mit der Eingabetaste (Enter) bestätigen.
+
+  \lstinline[style=cmd]{gcc} ist ein Befehl an den Computer,
+  nämlich der Name eines Programms, das wir aufrufen wollen (hier: der Compiler).
+  Die darauf folgenden Teile der Kommandozeile heißen die \newterm{Parameter\/}
+  oder \newterm{Argumente\/} des Befehls.
+
+  Der Parameter \lstinline[style=cmd]{hello-1.c} ist der Name der Datei, die compiliert werden soll.
+
+  \lstinline[style=cmd]{-o} ist eine \newterm{Option\/} an den Compiler,
+  mit der man ihm mitteilt, daß der nächste Parameter \lstinline[style=cmd]{hello-1}
+  der Name der ausführbaren Datei ist, die erzeugt werden soll.
+
+  Unter Unix ist es üblich, ausführbaren Dateien \emph{keine\/} Endung zu geben.
+  Unter Microsoft Windows wäre es stattdessen üblich,
+  die ausführbare Datei \lstinline[style=cmd]{hello-1.exe} zu nennen.
+
+  \breath
+
+  Um von einer Unix-Shell aus ein Programm aufzurufen,
+  gibt man dessen vollständigen Namen
+  -- einschließlich Verzeichnispfad und eventueller Endung -- als Kommando ein:
+  \begin{lstlisting}[style=terminal]
+    $ ¡./hello-1¿
+  \end{lstlisting}
+  Der Punkt steht für das aktuelle Verzeichnis;
+  der Schrägstrich trennt das Verzeichnis vom eigentlichen Dateinamen.
+
+  Wenn sich ein Programm im Suchpfad befindet (z.\,B.: \lstinline[style=cmd]{gcc}),
+  darf die Angabe des Verzeichnisses entfallen.
+  (Den Suchpfad kann man sich mit dem Kommando
+  \lstinline[style=cmd]{echo $PATH} anzeigen lassen.)
+  Aus Sicherheitsgründen steht das aktuelle Verzeichnis
+  unter Unix üblicherweise \emph{nicht\/} im Suchpfad.
+
+  \breath
+
+  \begin{experts}
+    Dateiendungen dienen unter Unix nur der Übersicht,
+    haben aber keine technischen Konsequenzen:
+    \begin{itemize}
+      \item
+        Ob eine Datei als ausführbar betrachtet wird oder nicht,
+        wird nicht anhand einer Endung, sondern über ein \newterm{Dateiattribut\/} entschieden.
+        Die Dateiattribute werden beim Listen des Verzeichnisinhalts angezeigt:
+        \begin{lstlisting}[style=terminal,gobble=10]
+          $ ¡ls -l¿
+          -rwxr-x--- 1 peter ainf 6294  4. Okt 14:34 hello-1
+          -rw-r--r-- 1 peter ainf   82  4. Okt 15:11 hello-1.c
+        \end{lstlisting}
+        Jedes \lstinline[style=terminal]{r} steht für "`read"' (Datei lesbar),
+        jedes \lstinline[style=terminal]{w} für "`write"' (Datei schreibbar)
+        und jedes \lstinline[style=terminal]{x} für "`execute"' (Datei ausführbar).
+        Von links nach rechts stehen die \lstinline[style=terminal]{rwx}-Gruppen für
+        den Besitzer der Datei (hier: \lstinline[style=terminal]{peter})
+        eine Benutzergruppe (hier: \lstinline[style=terminal]{ainf})
+        und für alle anderen Benutzer des Computers.
+        
+        Im o.\,a.\ Beispiel ist die Datei \gitfile{hp}{script}{hello-1.c}
+        für den Benutzer \lstinline[style=terminal]{peter} les- und schreibbar,
+        für alle Angehörigen der Gruppe \lstinline[style=terminal]{ainf} nur lesbar
+        und für alle anderen Benutzer des Computers ebenfalls nur lesbar.
+        Die Datei \file{hello-1} (ohne Endung) ist hingegen
+        für den Benutzer \lstinline[style=terminal]{peter} les-, schreib- und ausführbar,
+        für alle Angehörigen der Gruppe \lstinline[style=terminal]{ainf} les- und ausführbar,
+        aber nicht schreibbar. Alle anderen Benutzer des Computer haben für die Datei
+        \file{hello-1} überhaupt keine Zugriffsrechte.
+      \item
+        Welcher Art der Inhalt der Datei ist,
+        entnimmt Unix dem Inhalt selbst.
+        Man kann sich dies mit Hilfe des Befehls \lstinline[style=cmd]{file} anzeigen lassen:
+        \begin{lstlisting}[style=terminal,gobble=10]
+          $ ¡file hello-1¿
+          hello-1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
+          dynamically linked (uses shared libs), for GNU/Linux 2.6.18,
+          not stripped
+          $ ¡file hello-1.c¿
+          hello-1.c: ASCII C program text
+        \end{lstlisting}
+      \item
+        Eine ausführbare Datei, die Text enthält, ist ein sogenanntes \newterm{Shell-Skript}.
+        Der Aufruf eines Shell-Skripts bewirkt i.\,w.\ dasselbe,
+        als wenn man den darin enthaltenen Text als Kommandos eingeben würde.
+      \item
+        Ein C-Quelltext enthält i.\,d.\,R.\ \emph{keine\/} gültigen Unix-Kommandos
+        und kann daher \emph{nicht\/} "`einfach so"' ausgeführt werden.
+      \item
+        Es ist zulässig, aber normalerweise nicht sinnvoll,
+        einer ausführbaren Datei die Endung \file{.c} zu geben.
+    \end{itemize}
+  \end{experts}
+
+  \subsection{Elementare Aus- und Eingabe}
+
+  Da es möglich ist, mittels der Funktion \lstinline{printf()}
+  eine String-Konstante wie z.\,B.\ \lstinline{"Hello, world!\n"} "`einfach so"' auszugeben,
+  liegt die Vermutung nahe, Integer-Konstanten auf gleiche Weise ausgeben zu können.
+
+  Datei \gitfile{hp}{script}{output-1.c}:
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      printf (42);
+      return 0;
+    }
+  \end{lstlisting}
+  Beim Compilieren dieses Programms erhalten wir eine Warnung:
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc output-1.c -o output-1¿
+    output-12.c: In function 'main':
+    output-12.c:5: warning: passing argument 1 of 'printf'
+    makes pointer from integer without a cast
+    /usr/include/stdio.h:339: note: expected
+    'const char * __restrict__' but argument is of type 'int'
+  \end{lstlisting}
+  \goodbreak
+  Es entsteht trotzdem eine ausführbare Datei \file{output-1}.
+  Wenn wir diese jedoch ausführen, erhalten wir eine Fehlermeldung:
+  \begin{lstlisting}[style=terminal]
+    $ ¡./output-12¿
+    Segmentation fault
+  \end{lstlisting}
+  Tatsächlich ist die direkte Übergabe einer Integer-Konstanten an \lstinline{printf()}
+  ein grober Fehler: \lstinline{printf()} akzeptiert als ersten Parameter nur Ausdrücke vom Typ String.
+  Der C-Compiler nimmt eine implizite Umwandlung der Integer-Konstanten in einen String vor:
+  Die Zahl wird als eine Speicheradresse interpretiert, an der sich der Text befindet.
+  Dies ist nicht besonders sinnvoll (daher die Warnung), aber in C zulässig.
+
+  Wenn nun das Programm ausgeführt wird, versucht es, auf die Speicheradresse Nr.\ 42 zuzugreifen.
+  Diese befindet sich normalerweise außerhalb des Programms.
+  Das Betriebssystem bemerkt den illegalen Zugriffsversuch
+  und bricht das Programm mit einer Fehlermeldung
+  ("`Speicherzugriffsfehler"', "`Schutzverletzung"' o.\,ä.) ab.
+
+  Auf einer Plattform ohne derartige Schutzmechanismen (z.\,B.\ einem Mikrocontroller)
+  wird das fehlerhafte Programm hingegen klaglos ausgeführt.
+  Es werden dann sinnlose Texte, die sich zufällig an Speicheradresse Nr.\ 42 befinden,
+  auf dem Standardausgabegerät ausgegeben.
+
+  \breath
+
+  Dieses fehlerhafte Programm illustriert, wie leicht es in der Programmiersprache C ist,
+  einen Absturz zu programmieren.
+  Die meisten anderen Programmiersprachen würden das fehlerhafte Programm nicht akzeptieren;
+  anstelle der o.\,a.\ Warnung bekäme man eine ähnlichlautende Fehlermeldung.
+
+  \begin{hint}
+    Nehmen Sie nicht nur die Fehlermeldungen,\\
+    sondern auch die Warnungen des Compilers ernst!
+  \end{hint}
+
+  Gerade in graphischen Entwicklungsentwicklungen
+  werden Warnungen oft in einem winzigen Fenster angezeigt
+  und gehen zwischen anderen Meldungen unter.
+  Auch sind die Compiler-Optionen,
+  mit denen Sie Warnungen ein- oder ausschalten können,
+  oft in tiefen Menü-Strukturen versteckt,
+  so daß man als Programmierer den Aufwand scheut,
+  diese sinnvoll zu setzen.
+
+  Fehlermeldungen \emph{müssen\/} Sie ernstnehmen,
+  da Sie sonst kein ausführbares Programm erhalten.
+  Warnungen \emph{sollten\/} Sie ebenfalls ernstnehmen,
+  \emph{obwohl\/} Sie ein ausführbares Programm erhalten,
+  da dieses mit hoher Wahrscheinlichkeit
+  in einer nicht-offensichtlichen Weise \emph{fehlerhaft\/} ist.
+  Ein derartiges Programm produktiv einzusetzen,
+  kann je nach Einsatzgebiet Vermögens-, Sach- oder sogar Personenschäden
+  zur Folge haben.
+
+  \breath
+
+  Wie man nun tatsächlich in C Zahlenwerte ausgibt,
+  illustriert das Beispielprogramm \gitfile{hp}{script}{output-2.c}:
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      printf ("Die Antwort lautet: %d\n", 42);
+      return 0;
+    }
+  \end{lstlisting}
+  Der erste Parameter von \lstinline{printf()}, der sog.\ \newterm{Format-String},
+  enthält das Symbol \lstinline{%d}.
+  Diese sog.\ \newterm{Formatspezifikation\/} wird in der Ausgabe
+  durch den Zahlenwert des zweiten Parameters von \lstinline{printf()} ersetzt.
+  Das \lstinline{d} steht hierbei für "`dezimal"'.
+
+  \breath
+
+  \begin{experts}
+%    Wenn man anstelle von \lstinline{%d} die Formatspezifikation \lstinline{%x} verwendet,
+%    wird die Zahl in hexadezimaler anstatt in dezimaler Schreibweise ausgegeben.
+    Wenn man zwischen das Prozentzeichen un das \lstinline{d} eine Zahl schreibt (z.\,B.\ \lstinline{%3d}),
+    gibt man damit die Breite eines Feldes an, in die die auszugebende Zahl rechtsbündig geschrieben wird.
+    Wenn man die Feldbreite mit einer Null beginnen läßt (z.\,B.\ \lstinline{%03d})
+    wird die auszugebende Zahl von links mit Nullen bis zur Feldbreite aufgefüllt.
+
+    Eine vollständige Liste der in \lstinline{printf()} zulässigen Formatspezifikationen
+    finden Sie in der Dokumentation des Compiler-Herstellers zu \lstinline{printf()}.
+    Von der Unix-Shell aus können Sie diese
+    mit dem Befehl \lstinline[style=cmd]{man 3 printf} abrufen.
+%
+%    Umgekehrt können Sie in C Integer-Konstanten
+%    durch Voranstellen von \lstinline{0x} in hexadezimaler anstatt dezimaler Schreibweise eingeben.
+%    Die Hexadezimalzahl \lstinline{0x2a} steht in C für genau dieselbe Konstante
+%    wie die Dezimalzahl \lstinline{42}.
+  \end{experts}
+
+  \breath
+
+  Bemerkungen:
+  \begin{itemize}
+    \item
+      Ein Text darf auch Ziffern enthalten.
+      Anhand der Ausgabe sind \lstinline{printf ("42\n");} 
+      und \lstinline{printf ("%d\n", 42);} nicht voneinander unterscheidbar.
+    \item
+      Die Position des \lstinline{\n} ist relevant,
+      z.\,B.\ geht \lstinline{printf ("\n42");} zuerst in eine neue Zeile
+      und gibt danach den Text aus.
+      Auch mehrere \lstinline{\n} in derselben String-Konstanten sind zulässig.
+    \item
+      C akzeptiert auch sehr seltsame Konstrukte.
+      Das folgende Beispiel (Datei: \gitfile{hp}{script}{hello-2.c})
+      \begin{lstlisting}[gobble=8]
+        #include <stdio.h>
+
+        int main (void)
+        {
+          printf ("Hello, world!\n");
+          "\n";
+          return 0;
+        }
+      \end{lstlisting}
+      wird vom Compiler akzeptiert.
+      (Warum das so ist, wird in Abschnitt \ref{Seiteneffekte} behandelt.)
+
+      Bei Verwendung der zusätzlichen Option \lstinline[style=cmd]{-Wall}
+      erhalten wir zumindest eine Warnung über eine "`Anweisung ohne Effekt"':
+      \begin{lstlisting}[style=terminal,gobble=8]
+        $ ¡gcc -Wall hello-2.c -o hello-2¿
+        hello-2.c: In function 'main':
+        hello-2.c:6: warning: statement with no effect
+      \end{lstlisting}
+      Es empfiehlt sich, die Option \lstinline[style=cmd]{-Wall} grundsätzlich zu verwenden
+      und die Warnungen ernstzunehmen.
+  \end{itemize}
+
+  \breath
+
+  Wenn mehrere Werte ausgegeben werden sollen,
+  verwendet man in \lstinline{printf()} mehrere Formatspezifikationen
+  und gibt mehrere Werte als Parameter an (Datei: \gitfile{hp}{script}{output-3.c}):
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      printf ("Richtige Antworten wären %d oder %d oder sonstige.\n", 1, 2);
+      return 0;
+    }
+  \end{lstlisting}
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc output-3.c -o output-3¿
+    $ ¡./output-3¿
+    Richtige Antworten wären 1 oder 2 oder sonstige.
+    $
+  \end{lstlisting}
+  Achtung: Zu viele oder zu wenige Werte in der Parameterliste
+  ergeben trotzdem ein gültiges, wenn auch fehlerhaftes C-Programm
+  (Datei: \gitfile{hp}{script}{output-4.c}):
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      printf ("Richtige Antworten wären %d", 1, " oder %d", 2, " oder sonstige.\n");
+      return 0;
+    }
+  \end{lstlisting}
+  Wenn man dieses Programm laufen läßt,
+  wird nicht etwa das zweite \lstinline{%d} durch den Zahlenwert 2 ersetzt.
+  Vielmehr endet das, was ausgegeben wird, mit dem ersten \lstinline{%d},
+  für das der Zahlenwert 1 eingesetzt wird,
+  und alles, was nach der 1 kommt, wird schlichtweg ignoriert.
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc output-4.c -o output-4¿
+    $ ¡./output-4¿
+    Richtige Antworten wären 1
+    $
+  \end{lstlisting}
+  Bei Verwendung der Option \lstinline[style=cmd]{-Wall}
+  erhalten wir auch hier eine Warnung:
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall output-4.c -o output-4¿
+    output-4.c: In function 'main':
+    output-4.c:5: warning: too many arguments for format
+  \end{lstlisting}
+
+  Das Einlesen von Werten erfolgt in C mit der Funktion \lstinline{scanf()}.
+
+  Das folgende Beispielprogramm (Datei: \gitfile{hp}{script}{input-1.c})
+  liest einen Wert vom Standardeingabegerät (hier: Tastatur) ein
+  und gibt ihn wieder aus:
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int a;
+      printf ("Bitte eine Zahl eingeben: ");
+      scanf ("%d", &a);
+      printf ("Sie haben eingegeben: %d\n", a);
+      return 0;
+    }
+  \end{lstlisting}
+
+  Damit \lstinline{scanf()} in die Variable \lstinline{a} einen Wert schreiben kann,
+  ist es erforderlich, nicht den aktuellen Wert von \lstinline{a},
+  sondern die Variable selbst an \lstinline{scanf()} zu übergeben.
+  Dies geschieht durch Voranstellen eines Und-Symbols \lstinline{&}.
+  (Genaugenommen handelt es sich um die Übergabe einer Speicheradresse.
+  Dies wird in Abschnitt \ref{Zeiger} genauer behandelt.)
+
+  Wenn wir das \lstinline{&} vergessen (Beispielprogramm: \gitfile{hp}{script}{input-2.c}),
+  kann das C-Programm weiterhin compiliert werden.
+  Bei Verwendung der Option \lstinline[style=cmd]{-Wall} erhalten wir eine Warnung.
+  Wenn wir das Programm ausführen und versuchen, einen Wert einzugeben, stürzt das Programm ab.
+  (Hintergrund: Es betrachtet den aktuellen -- zufälligen -- Wert der Variablen \lstinline{a}
+  als Adresse einer Speicherzelle, an der der eingelesene Wert gespeichert werden soll.
+  Das Programm greift also schreibend auf eine Speicherzelle außerhalb des ihm zugeteilten Bereichs zu.)
+
+  \breath
+
+  \begin{experts}
+    Die Funktion \lstinline{scanf()} kann, analog zu \lstinline{printf()},
+    gleichzeitig mehrere Werte abfragen.
+    Hierzu müssen wir im Format-String mehrere Formatspezifikationen angeben
+    und die Adressen mehrerer Variabler als Parameter übergeben.
+
+    Genau wie bei \lstinline{printf()} werden überzählige Parameter ignoriert,
+    und fehlende Parameter führen zu einem Absturz des Programms.
+
+    Zeichen zwischen den Formatspezifikationen fungieren als Trennzeichen.
+    Damit die Zahlen angenommen werden, muß die Eingabe die Trennzeichen enthalten.
+
+    Für doppelt genaue Fließkommazahlen (\lstinline{double})
+    lautet die Formatspezifikation \lstinline{%lf};
+    für einfach genaue Fließkommazahlen (\lstinline{float})
+    lautet sie \lstinline{%f}.
+
+    Weitere Informationen zu den Formatspezifikationen von \lstinline{scanf()}
+    finden Sie in der Dokumentation zu \lstinline{scanf()}.
+    (In der Unix-Shell können Sie diese mit dem Befehl \lstinline[style=cmd]{man 3 scanf} abrufen.)
+
+    Für das Einlesen von Strings ist \lstinline{scanf()} eher ungeeignet.
+    Hier empfiehlt es sich, stattdessen \lstinline{fgets()} zu benutzen
+    (siehe \lstinline[style=cmd]{man 3 fgets}).
+  \end{experts}
+
+  \subsection{Elementares Rechnen}
+
+  Der \newterm{binäre Operator} \lstinline{+} kann in C (und den meisten Programmiersprachen)
+  dazu verwendet werden, zwei Integer-Ausdrücke, die sogenannten \newterm{Operanden},
+  durch Addition zu einem neuen Integer-Ausdruck zu verknüpfen.
+
+  Beispiel: \gitfile{hp}{script}{mathe-1.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      printf ("%d\n", 23 + 19);
+      return 0;
+    }
+  \end{lstlisting}
+  \begin{experts}
+    (Tatsächlich führt bereits die erste Stufe des Compilers eine Optimierung durch,
+    die bewirkt, daß die ausführbare Datei keine Additionsbefehle,
+    sondern direkt das Ergebnis der Addition enthält.)
+  \end{experts}
+
+  Die Operatoren für die Grundrechenarten lauten in C:
+  \begin{center}
+    \begin{tabular}{cl}
+      \lstinline|+| & Addition \\
+      \lstinline|-| & Subtraktion \\
+      \lstinline|*| & Multiplikation \\
+      \lstinline|/| & Division: Bei ganzen Zahlen wird grundsätzlich abgerundet. \\
+      \lstinline|%| & Modulo-Operation: Rest bei Division (\lstinline|39 % 4| ergibt \lstinline|3|.)
+    \end{tabular}
+  \end{center}
+
+  Die Verwendung von \newterm{Variablen} erfordert in C eine vorherige Deklaration.
+  \begin{lstlisting}[belowskip=0pt]
+    int a;
+  \end{lstlisting}
+  deklariert eine Variable vom Typ Integer,
+  \begin{lstlisting}[belowskip=0pt]
+    int a, b;
+  \end{lstlisting}
+  deklariert zwei Variable vom Typ Integer, und
+  \begin{lstlisting}[belowskip=0pt]
+    int a, b = 3;
+  \end{lstlisting}
+  deklariert zwei Variable vom Typ Integer und initialisiert \emph{die zweite\/} mit dem Wert 3.
+  (Im letzten Beispiel wird insbesondere die erste Variable \lstinline{a} \emph{nicht\/} initialisiert.)
+  
+  Nicht initialisierte Variable erhalten einen \emph{zufälligen\/} Wert.
+  Wenn beim Compilieren mit \lstinline[style=cmd]{gcc}
+  zusätzlich zu den Warnungen (Option \lstinline[style=cmd]{-Wall})
+  auch die Optimierung (Option \lstinline[style=cmd]{-O}, \lstinline[style=cmd]{-O2} oder \lstinline[style=cmd]{O3})
+  aktiviert ist, erkennt \lstinline[style=cmd]{gcc}
+  die Verwendung derartiger zufälliger Werte und gibt eine Warnung aus.
+
+  \begin{experts}
+    Nicht explizit initialisierte \newterm{globale Variable},
+    also solche, die außerhalb einer Funktion deklariert werden,
+    werden implizit auf Null initialisiert
+    (\lstinline{0} für Zahlen, \lstinline{NULL} für Zeiger usw.).
+    Es ist trotzdem in Hinblick auf selbstdokumentierenden Quelltext sinnvoll,
+    diese ggf.\ explizit auf \lstinline{0} zu initialisieren.
+  \end{experts}
+
+  \breath
+
+  Für Fließkommazahlen verwendet man meistens den Datentyp \lstinline{double}:
+  \begin{lstlisting}[belowskip=0pt]
+    double x = 3.141592653589793;
+  \end{lstlisting}
+
+  \bigskip
+
+  \begin{experts}
+    Die Bezeichnung \lstinline{double} steht für "`doppelt genau"'.
+    Daneben gibt es noch einen Datentyp \lstinline{float} für "`einfach genaue"' Fließkommazahlen
+    sowie einen Datentyp \lstinline{long double} für noch höhere Genauigkeit.
+    Typischerweise folgen Fließkommazahlen in C dem Standard IEEE 754.
+    In diesem Fall hat \lstinline{float} eine Genauigkeit von ca.\ 6
+    und \lstinline{double} eine Genauigkeit von ca.\ 15 Nachkommastellen.
+  \end{experts}
+
+  \breath
+
+  Zuweisungen an Variable erfolgen in C mit Hilfe des binären Operators \lstinline{=}.
+  Es ist ausdrücklich erlaubt, den "`alten"' Wert einer Variablen in Berechnungen zu verwenden,
+  deren Ergebnis man dann derselben Variablen zuweist.
+
+  Eine Anweisung wie z.\,B.\ \lstinline{a = 2 * a}
+  ist insbesondere keine mathematische Gleichung
+  (mit der Lösung 0 für die Unbekannte \lstinline{a}),
+  sondern die Berechnung des Doppelten des aktuellen Wertes der Variablen \lstinline{a},
+  welches dann wiederum in der Variablen \lstinline{a} gespeichert wird.
+
+  \subsection{Verzweigungen}
+
+  Das Beispielprogramm \gitfile{hp}{script}{if-0.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int a, b;
+      printf ("Bitte a eingeben: ");
+      scanf ("%d", &a);
+      printf ("Bitte b eingeben: ");
+      scanf ("%d", &b);
+      printf ("a geteilt durch b ist: %d\n", a / b);
+      return 0;
+    }
+  \end{lstlisting}
+  hat den Nachteil, daß bei Eingabe von 0 für die zweite Zahl das Programm abstürzt:
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall if-0.c -o if-0¿
+    $ ¡./if-0¿
+    Bitte a eingeben: ¡13¿
+    Bitte b eingeben: ¡0¿
+    Floating point exception
+  \end{lstlisting}
+  Die Fehlermeldung stammt nicht vom Programm selbst, sondern vom Betriebssystem,
+  das auf einen vom Prozessor signalisierten Fehlerzustand reagiert.
+  ("`Floating point exception"' ist die Bezeichnung dieses Fehlerzustands.
+  In diesem Fall ist die Bezeichnung leicht irreführend,
+  da konkret dieser Fehler durch eine Division ganzer Zahlen,
+  also insbesondere nicht durch eine Fließkommaoperation, ausgelöst wird.)
+
+  Für Programme wie dieses ist es notwendig,
+  in Abhängigkeit von den Benutzereingaben unterschiedliche Anweisungen auszuführen.
+  Diese sog.\ \newterm{Verzweigung\/} geschieht mittels einer \lstinline{if}-Anweisung.
+
+  \goodbreak
+  Beispielprogramm: \gitfile{hp}{script}{if-1.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int a, b;
+      printf ("Bitte a eingeben: ");
+      scanf ("%d", &a);
+      printf ("Bitte b eingeben: ");
+      scanf ("%d", &b);
+      if (b != 0)
+        printf ("a geteilt durch b ist: %d\n", a / b);
+      return 0;
+    }
+  \end{lstlisting}
+
+  In den Klammern hinter dem \lstinline{if} steht ein Ausdruck, die sog.\ \newterm{Bedingung}.
+  Die auf das \lstinline{if} folgende Anweisung wird nur dann ausgeführt,
+  wenn die Bedingung \emph{ungleich Null\/} ist.
+  (C kennt keinen eigenen "`Booleschen"' Datentyp.
+  Stattdessen steht \lstinline{0} für den Wahrheitswert "`falsch"'
+  und alles andere für den Wahrheitswert "`wahr"'.)
+
+  Der binäre Operator \lstinline{!=} prüft zwei Ausdrücke auf Ungleichheit.
+  Er liefert \lstinline{0} zurück, wenn beide Operanden gleich sind,
+  und \lstinline{1}, wenn sie ungleich sind.
+
+  \breath
+
+  Die \lstinline{if}-Anweisung kennt einen optionalen \lstinline{else}-Zweig.
+  Dieser wird dann ausgeführt, wenn die Bedingung \emph{nicht\/} erfüllt ist.
+
+  Beispielprogramm: \gitfile{hp}{script}{if-2.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int a, b;
+      printf ("Bitte a eingeben: ");
+      scanf ("%d", &a);
+      printf ("Bitte b eingeben: ");
+      scanf ("%d", &b);
+      if (b != 0)
+        printf ("a geteilt durch b ist: %d\n", a / b);
+      else
+        printf ("Bitte nicht durch 0 teilen!\n");
+      return 0;
+    }
+  \end{lstlisting}
+
+  \breath
+
+  Sowohl auf das \lstinline{if} als auch auf das \lstinline{else}
+  folgt nur jeweils \emph{eine\/} Anweisung, die von der Bedingung abhängt.
+
+  In dem folgenden Beispielprogramm (Datei: \gitfile{hp}{script}{if-3.c})
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int a, b;
+      printf ("Bitte a eingeben: ");
+      scanf ("%d", &a);
+      printf ("Bitte b eingeben: ");
+      scanf ("%d", &b);
+      if (b != 0)
+        printf ("a geteilt durch b ist: %d\n", a / b);
+      else
+        printf ("Bitte nicht durch 0 teilen!\n");
+        printf ("Das tut man nicht.\n");
+      return 0;
+    }
+  \end{lstlisting}
+  wird die Zeile \lstinline{printf ("Das tut man nicht.\n");} auch dann ausgeführt,
+  wenn die Variable \lstinline{b} ungleich 0 ist.
+
+  \breath
+
+  In C ist die Einrückung der Zeilen im Programmquelltext "`nur"' eine optische Hilfe für Programmierer.
+  Welche Anweisung von welcher Bedingung abhängt,
+  entscheidet der Compiler allein anhand der Regeln der Programmiersprache,
+  und diese besagen eindeutig:
+  "`Sowohl auf das \lstinline{if} als auch auf das \lstinline{else}
+  folgt nur jeweils \emph{eine\/} Anweisung, die von der Bedingung abhängt."'
+
+  Wenn wir möchten, daß mehrere Anweisungen von der Bedingung abhängen,
+  müssen wir diese mittels geschweifter Klammern
+  zu einem sog.\ \newterm{Anweisungsblock\/} zusammenfassen.
+
+  \goodbreak
+  Beispielprogramm: \gitfile{hp}{script}{if-4.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int a, b;
+      printf ("Bitte a eingeben: ");
+      scanf ("%d", &a);
+      printf ("Bitte b eingeben: ");
+      scanf ("%d", &b);
+      if (b != 0)
+        printf ("a geteilt durch b ist: %d\n", a / b);
+      else
+        {
+          printf ("Bitte nicht durch 0 teilen!\n");
+          printf ("Das tut man nicht.\n");
+        }
+      return 0;
+    }
+  \end{lstlisting}
+
+  Aus Sicht des Computers ist die Einrückung
+  -- und überhaupt die Anordnung von Leerzeichen und Zeilenschaltungen -- belanglos.
+  Die folgende Schreibweise (Datei: \gitfile{hp}{script}{if-5.c}) ist für ihn
+  vollkommen gleichwertig zu \gitfile{hp}{script}{if-4.c}:
+  \begin{lstlisting}
+    #include<stdio.h>
+    int main(void){int a,b;printf("Bitte a eingeben: ");scanf("%d",&a);
+    printf("Bitte b eingeben: ");scanf("%d",&b);if(b!=0)printf(
+    "a geteilt durch b ist: %d\n",a/b);else{printf("Bitte nicht durch 0 teilen!\n");
+    printf("Das tut man nicht.\n");}return 0;}
+  \end{lstlisting}
+  Aus Sicht eines Menschen hingegen kann eine \emph{korrekte\/} Einrückung des Quelltextes
+  \emph{sehr\/} hilfreich dabei sein, in einem Programm die Übersicht zu behalten.
+
+  \goodbreak
+  Daher hier der dringende Rat:
+  \begin{hint}
+    Achten Sie in Ihren Programmen auf korrekte und übersichtliche Einrückung!
+  \end{hint}
+
+  \breath
+
+  Um zwei Ausdrücke auf Gleichheit zu prüfen,
+  verwendet man in C den binären Operator \lstinline{==}.
+
+  Die Anweisungen
+  \begin{lstlisting}[belowskip=0pt]
+    if (b != 0)
+      {
+        printf ("Die erste Zahl geteilt durch die zweite ergibt: ");
+        printf ("%d, Rest %d \n", a / b, a % b);
+      }
+    else
+      printf ("Bitte nicht durch 0 teilen!\n");
+  \end{lstlisting}
+  sind also äquivalent zu:
+  \begin{lstlisting}
+    if (b == 0)
+      printf ("Bitte nicht durch 0 teilen!\n");
+    else
+      {
+        printf ("Die erste Zahl geteilt durch die zweite ergibt: ");
+        printf ("%d, Rest %d \n", a / b, a % b);
+      }
+  \end{lstlisting}
+
+  Achtung: Die Anweisungen
+  \begin{lstlisting}[belowskip=0pt]
+    if (b = 0)
+      printf ("Bitte nicht durch 0 teilen!\n");
+    else
+      {
+        printf ("Die erste Zahl geteilt durch die zweite ergibt: ");
+        printf ("%d, Rest %d \n", a / b, a % b);
+      }
+  \end{lstlisting}
+  (mit \lstinline{=} anstelle von \lstinline{==}) sind ebenfalls gültiges C,
+  haben jedoch eine andere Bedeutung!
+  \goodbreak
+
+  Der Hintergrund ist der folgende:
+  Alle binären Operatoren, sei es \lstinline{+} oder \lstinline{=} oder \lstinline{==},
+  sind in C vom Prinzip her gleichwertig.
+  Alle nehmen zwei numerische Operanden entgegen und liefern einen numerischen Wert zurück.
+  Wenn wir nun beispielsweise annehmen, daß die Variable \lstinline{a} den Wert 3 hat, dann gilt:
+  \begin{center}
+    \begin{tabular}{cl}
+      \lstinline|a + 7| & ergibt \lstinline|10|. \\
+      \lstinline|a = 7| & ergibt \lstinline|7| (und weist \lstinline|a| den Wert 7 zu). \\
+      \lstinline|a == 7| & ergibt \lstinline|0|.
+    \end{tabular}
+  \end{center}
+  Das o.\,a.\ Programmfragment bedeutet demnach:
+  Weise der Variablen \lstinline{b} den Wert \lstinline{0} zu,
+  und führe anschließend \emph{immer\/} eine Division durch \lstinline{b} aus.
+  (Die \lstinline{if}-Bedingung bekommt den Wert \lstinline{0}, ist also niemals erfüllt.)
+
+  \breath
+
+  Daß es sich bei Wahrheitswerten in C tatsächlich um Integer-Werte handelt, wird auch deutlich,
+  wenn man sich diese mittels \lstinline{printf()} ausgeben läßt.
+
+  Wenn man beispielsweise in dem folgenden Programm \gitfile{hp}{script}{if-6.c}
+  den Wert \lstinline{7} für die Variable \lstinline{b} eingibt,
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int b;
+      printf ("Bitte b eingeben: ");
+      scanf ("%d", &b);
+      printf ("Der Ausdruck b != 0 hat den Wert %d\n", b != 0);
+      printf ("Der Ausdruck b == 0 hat den Wert %d\n", b == 0);
+      printf ("Der Ausdruck b = 23 hat den Wert %d\n", b = 23);
+      return 0;
+    }
+  \end{lstlisting}
+  \goodbreak
+  lautet die Ausgabe:
+  \goodbreak
+  \begin{lstlisting}[style=terminal]
+    $ ¡./if-6¿
+    Bitte b eingeben: ¡7¿
+    Der Ausdruck b != 0 hat den Wert 1
+    Der Ausdruck b == 0 hat den Wert 0
+    Der Ausdruck b = 23 hat den Wert 23
+  \end{lstlisting}
+  In der ersten und zweiten Zeile wird geprüft, ob \lstinline{b} den Wert 0 hat,
+  und \lstinline{1} für "`ja"' bzw.\ \lstinline{0} für "`nein"' ausgegeben.
+  In der dritten Zeile wird \lstinline{b} der Wert \lstinline{23} zugewiesen
+  und anschließend der neue Wert von \lstinline{b} ausgegeben.
+
+  \subsection{Schleifen}
+
+  Mit Hilfe der \lstinline{while}-Anweisung ist es möglich,
+  Anweisungen in Abhängigkeit von einer Bedingung mehrfach auszuführen.
+
+  Das folgende Beispielprogramm \gitfile{hp}{script}{loop-1.c}
+  schreibt die Zahlen von 1 bis einschließlich 10 auf den Bildschirm:
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int i = 1;
+      while (i <= 10)
+        {
+          printf ("%d\n", i);
+          i = i + 1;
+        }
+      return 0;
+    }
+  \end{lstlisting}
+  Die Auswertung der Bedingung erfolgt analog zur \lstinline{if}-Anweisung.
+  Ebenso folgt auf \lstinline{while} nur eine eine einzige Anweisung, die wiederholt ausgeführt wird;
+  mehrere Anweisungen müssen mit geschweiften Klammern zu einem Anweisungsblock zusammengefaßt werden.
+
+  Der binäre Operator \lstinline{<=} liefert 1 zurück,
+  wenn der linke Operand kleiner oder gleich dem rechten ist, ansonsten 0.
+  Entsprechend sind die Operatoren \lstinline{>=}, \lstinline{<} und \lstinline{>} definiert.
+
+\if 0
+
+  \breath
+
+  Wenn man eine Bedingung angibt, die niemals 0 wird,
+  erzeugt man eine Endlosschleife (\gitfile{hp}{script}{while-2.c}):
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int i;
+      i = 1;
+      while (1)
+        {
+          i = i + i;
+          printf ("%d\n", i);
+        }
+      return 0;
+    }
+  \end{lstlisting}
+  Das endlos laufende Programm kann nur noch über das Betriebssystem beendet werden.
+  Von der Unix-Shell aus geschieht dies durch Eingabe von \lstinline[style=cmd]{Strg+C}.
+
+  In der Ausgabe des oben dargestellten Beispielprogramms fällt auf,
+  daß die Zweierpotenzen zunächst wie erwartet anwachsen,
+  später aber nur noch der Zahlenwert 0 ausgegeben wird:
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall while-2.c -o while-2¿
+    $ ¡./while-2¿
+    2
+    4
+    8
+    16
+    32
+    64
+    128
+    256
+    512
+    1024
+    2048
+    4096
+    8192
+    16384
+    32768
+    65536
+    131072
+    262144
+    524288
+    1048576
+    2097152
+    4194304
+    8388608
+    16777216
+    33554432
+    67108864
+    134217728
+    268435456
+    536870912
+    1073741824
+    -2147483648
+    0
+    0
+    0
+    ...
+  \end{lstlisting}
+  \goodbreak
+  Dies hängt mit der Art und Weise zusammen,
+  wie Zahlen in einem Computer gespeichert werden.
+  Im Detail ist dies Gegenstand der Vorlesung "`Rechnertechnik"';
+  ein paar für uns wichtige Eckdaten seien an dieser Stelle erwähnt:
+  \begin{itemize}
+    \item
+      Computer speichern Zahlen im Binärformat, das nur die Ziffern 0 und 1 kennt.\\
+      Beispielsweise lautet die Dezimalzahl 9 in Binärdarstellung 1001.
+    \item
+      Zweierpotenzen entsprechen jeweils einer 1 mit folgenden Nullen.\\
+      Die Dezimalzahlen 2, 4, 8 und 16 haben die Binärdarstellungen 10, 100, 1000 und 10000.
+    \item
+      Auf einem 32-Bit-Prozessor zeigt die zweiundreißigste Ziffer von rechts das Vorzeichen an.
+      Steht hier eine 1, ist die Zahl negativ.
+      Dies erklärt, weshalb die Verdopplung von 1073741824 (binär: eine 1 mit 30 Nullen)
+      $-$2147483648 ergibt (binär: eine 1 mit 31 Nullen).
+    \item
+      Bei einer weiteren Verdopplung würde binär eine 1 mit 32 Nullen entstehen,
+      die aber von einem 32-Bit-Prozessor nicht mehr dargestellt werden kann.
+      Ohne weitere Maßnahmen ist daher das Doppelte von $-$2147483648 auf einem 32-Bit-Prozessor
+      die Zahl 0.
+  \end{itemize}
+
+\fi
+
+  \breath
+
+  Ein wichtiger Spezialfall einer \lstinline{while}-Schleife ist die folgende Situation:
+  \begin{itemize}
+    \item
+      Vor dem Betreten der Schleife findet eine Initialisierung statt, z.\,B.\ \lstinline{i = 1}.
+    \item
+      Am Ende jedes Schleifendurchlaufs wird eine "`Schritt-Anweisung"' durchgeführt,
+      z.\,B.\ \lstinline{i = i + 1}.
+  \end{itemize}
+  Für dieses spezielle \lstinline{while} kennt C die Abkürzung \lstinline{for}:
+  \begin{center}
+    \begin{minipage}{4cm}
+      \begin{lstlisting}[gobble=8]
+        int i = 1;
+        while (i <= 10)
+          {
+            printf ("%d\n", i);
+            i = i + 1;
+          }
+      \end{lstlisting}
+    \end{minipage}%
+    \quad
+    ist genau dasselbe wie
+    \quad
+    \begin{minipage}{4.9cm}
+      \begin{lstlisting}[gobble=8]
+        int i;
+        for (i = 1; i <= 10; i = i + 1)
+          printf ("%d\n", i);
+      \end{lstlisting}
+      \quad oder
+      \begin{lstlisting}[gobble=8]
+        for (int i = 1; i <= 10; i = i + 1)
+          printf ("%d\n", i);
+      \end{lstlisting}
+      \bigskip
+      \quad(Datei: \gitfile{hp}{script}{loop-2.c})
+    \end{minipage}
+  \end{center}
+
+  Achtung: Zwischen den Klammern nach \lstinline{for} stehen zwei Semikolons, keine Kommata.
+
+  \begin{hint}
+    Die Schreibweise mit der Deklaration \lstinline{int i = 1}
+    \emph{innerhalb\/} der \lstinline{for}-Schleife
+    ist erst ab dem C-Standard C99 zulässig.
+    Beim Compilieren mit älteren Versionen des \lstinline[style=cmd]{gcc}
+    muß daher zusätzlich die Option \lstinline[style=cmd]{-std=c99} angegeben werden.
+  \end{hint}
+
+  \breath
+
+  Als eine weitere Schleife kennt C die \lstinline{do}-\lstinline{while}-Schleife:
+  \begin{lstlisting}
+    i = 1;
+    do
+      {
+        printf ("%d\n", i);
+        i = i + 1;
+      }
+    while (i <= 10)
+  \end{lstlisting}
+  Der Unterschied zur "`normalen"' \lstinline{while}-Schleife besteht darin,
+  daß eine \lstinline{do}-\lstinline{while}-Schleife mindestens einmal ausgeführt wird,
+  weil die Bedingung nicht bereits am Anfang, sondern erst am Ende des Schleifendurchlaufs geprüft wird.
+
+  \bigbreak
+
+  Zwischen einer "`normalen"' \lstinline{while}-Schleife
+  und einer \lstinline{for}-Schleife besteht hingegen \emph{kein\/} Unterschied.
+  Insbesondere ist eine Schreibweise wie
+  \begin{lstlisting}
+    for (i = 1; 10; i + 1)
+      printf ("%d\n", i);
+  \end{lstlisting}
+  \vspace{-\smallskipamount}
+  zwar zulässiges C, aber nicht sinnvoll (Datei: \gitfile{hp}{script}{loop-3.c}).
+  Dies kann man sofort erkennen, indem man die \lstinline{for}-Schleife
+  in eine \lstinline{while}-Schleife übersetzt:
+  \begin{lstlisting}
+    i = 1; 
+    while (10)
+      {
+        printf ("%d\n", i);
+        i + 1;
+      }
+  \end{lstlisting}
+  Dieses Programmfragment setzt einmalig \lstinline{i} auf den Wert 1
+  und springt danach in eine Endlosschleife zur Ausgabe von \lstinline{i}.
+  (Die \lstinline{while}-Bedingung \lstinline{10} ist ungleich Null, hat also stets den Wahrheitswert "`wahr"'.)
+  Am Ende jedes Schleifendurchlaufs wird \lstinline{i + 1} berechnet;
+  der berechnete Wert wird jedoch nirgendwo verwendet, sondern schlichtweg verworfen.
+  Insbesondere ändert \lstinline{i} seinen Wert nicht.
+
+  \subsection{Seiteneffekte\label{Seiteneffekte}}
+
+  Das Verwerfen berechneter Werte verdient eine nähere Betrachtung
+  -- insbesondere in der Programmiersprache C.
+  Wie das Beispielprogramm \gitfile{hp}{script}{statements-1.c} illustriert,
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      2 + 2;
+      return 0;
+    }
+  \end{lstlisting}
+  ist es anscheinend zulässig, Werte als Anweisung zu verwenden.
+
+  Grundsätzlich gilt in C:
+  Man kann jeden gültigen Ausdruck als Anweisung verwenden.
+  Der Wert des Ausdrucks wird dabei ignoriert.
+
+  Die Bedeutung der (gültigen!) C-Anweisung \lstinline{2 + 2;} lautet somit:
+  "`Berechne den Wert \lstinline{2 + 2} und vergiß ihn wieder."'
+
+  Tatsächlich gilt dasselbe auch für \lstinline{printf()}:
+  Die Funktion \lstinline{printf()} liefert eine ganze Zahl zurück.
+  Der \lstinline{printf()}-Aufruf ist somit ein Ausdruck,
+  dessen Wert ignoriert wird.
+
+  "`Nebenbei"' hat \lstinline{printf()} aber noch eine weitere Bedeutung,
+  nämlich die Ausgabe des Textes auf dem Standardausgabegerät (Bildschirm).
+  Diese weitere Bedeutung heißt \newterm{Seiteneffekt\/} des Ausdrucks.
+
+  Das Beispielprogramm \gitfile{hp}{script}{statements-2.c}
+  gibt den vom ersten \lstinline{printf()} zurückgegebenen Wert
+  mit Hilfe eines zweiten \lstinline{printf()} aus:
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int x;
+      x = printf ("%d\n", 2 + 2);
+      printf ("%d\n", x);
+      return 0;
+    }
+  \end{lstlisting}
+  Die Ausgabe lautet:
+  \begin{lstlisting}[style=terminal]
+    4
+    2
+  \end{lstlisting}
+  Bei dem von \lstinline{printf()} zurückgegebenen Wert handelt es sich um die Anzahl der geschriebenen Zeichen.
+  In diesem Fall ist sind es zwei Zeichen, nämlich die Ziffer \lstinline{4}
+  sowie das Zeilenendesymbol, im Programm als \lstinline{\n} notiert.
+
+  \breath
+
+  Auch Operatoren können in C Seiteneffekte haben.
+
+  \begin{itemize}
+    \item
+      Der binäre Operator \lstinline{=} (Zuweisung)
+      hat als Seiteneffekt die Zuweisung des zweiten Operanden an den ersten Operanden
+      und als Rückgabewert den zugewiesenen Wert.
+    \item
+      Ähnlich funktionieren die binären Operatoren \lstinline{+= -= *= /* %=}.
+      Sie wenden die vor dem \lstinline{=} stehende Rechenoperation auf die beiden Operatoren an,
+      weisen als Seiteneffekt das Ergebnis dem ersten Operanden zu
+      und geben das Rechenergebnis als Wert zurück.
+    \item
+      Die binären Rechnoperatoren \lstinline{+ - * / %}
+      und Vergleichsoperatoren \lstinline{== != < > <= >=}
+      haben \emph{keinen\/} Seiteneffekt.
+    \item
+      Der unäre Rechenoperator \lstinline{-} (arithmetische Negation, Vorzeichen)
+      hat ebenfalls \emph{keinen\/} Seiteneffekt.
+    \item
+      Ein weiterer unärer Operator \emph{ohne\/} Seiteneffekt ist die logische Negation,\\
+      in C ausgedrückt durch ein Ausrufezeichen: \lstinline{!}\\
+      \lstinline{!a} ist 1, wenn \lstinline{a} den Wert 0 hat; ansonsten ist es 0.\\
+      \lstinline{!(a < b)} ist demzufolge dasselbe wie \lstinline{a >= b}.
+    \item
+      Der Funktionsaufruf \lstinline{()} (Klammerpaar) ist in C ebenfalls ein unärer Operator.
+      Er liefert einen Wert zurück (Rückgabewert der Funktion)
+      und hat einen Seiteneffekt (Aufruf der Funktion).
+    \item
+      Die unären Operatoren \lstinline{++} und \lstinline{--} haben den Seiteneffekt,
+      daß sie die Variable, vor oder hinter der sie stehen, um 1 erhöhen (\lstinline{++})
+      bzw.\ vermindern (\lstinline{--}).
+      Wenn der Operator \emph{vor\/} der Variablen steht (\lstinline{++a}),
+      ist der Rückgabewert der um 1 erhöhte/verminderte Wert der Variablen.
+      Wenn er hingegen \emph{hinter\/} der Variablen steht (\lstinline{a++}),
+      ist der Rückgabewert der ursprüngliche Wert der Variablen;
+      das Erhöhen/Vermindern findet in diesem Fall erst danach statt.
+      
+      \begin{experts}
+        Da die Reihenfolge, in der ein Ausdruck ausgewertet wird, nicht immer festliegt,
+        sollte man darauf achten, daß die Seiteneffekte eines Ausdruck dessen Wert nicht beeinflussen.
+        (\lstinline[style=cmd]{gcc} warnt in derartigen Fällen.)
+      \end{experts}
+
+    \begin{experts}
+      \item
+        Ein weiterer binärer Operator \emph{ohne\/} Seiteneffekt ist das Komma.
+        Der Ausdruck \lstinline{a, b} bedeutet:
+        "`Berechne \lstinline{a}, vergiß es wieder, und gib stattdessen \lstinline{b} zurück."'
+        Dies ist nur dann sinnvoll, wenn der Ausdruck \lstinline{a} einen Seiteneffekt hat.
+    \end{experts}
+  \end{itemize}
+
+  Die folgenden vier Programmfragmente sind verschiedene Schreibweisen für genau denselben Code.
+  \begin{lstlisting}
+    int i;
+
+    i = 0;
+    while (i < 10)
+      {
+        printf ("%d\n", i);
+        i += 1;
+      }
+
+    for (i = 0; i < 10; i++)
+      printf ("%d\n", i);
+
+    i = 0;
+    while (i < 10)
+      printf ("%d\n", i++);
+
+    for (i = 0; i < 10; printf ("%d\n", i++));
+  \end{lstlisting}
+  Sie bewirken nicht nur dasselbe (Ausgabe der Zahlen von 0 bis 9),
+  sondern stehen tatsächlich für \emph{genau dasselbe Programm}.
+  Sie laufen genau gleich schnell und unterscheiden sich nur hinsichtlich ihrer Lesbarkeit,
+  wobei es vom persönlichen Geschmack abhängt, welche Variante man jeweils als lesbarer empfindet.
+  \begin{hint}
+    Schreiben Sie Ihre Programme stets so lesbar wie möglich.\\
+    Platzsparende Schreibweise macht ein Programm nicht schneller.
+  \end{hint}
+
+  \subsection{Strukturierte Programmierung}
+
+  Bei den bisher vorgestellten Verzweigungen und Schleifen
+  ist die Reihenfolge, in der die Befehle abgearbeitet werden, klar erkennbar.
+  Darüberhinaus kennt C auch Anweisungen,
+  die einen Sprung des Programms bewirken, der diese Struktur durchbricht:
+  \begin{itemize}
+    \item
+      Mit der \lstinline{break}-Anweisung kann das Programm
+      die nächst"-äußere \lstinline{while}- oder \lstinline{for}-Schleife
+      unmittelbar verlassen.
+
+      Das folgende Beispielprogramm zählt von 0 bis 9,
+      indem es eine Endlosschleife beim Erreichen von 10
+      mittels \lstinline{break} unterbricht.
+      Der Schleifenzäher \lstinline{i} wird innerhalb des \lstinline{printf()}
+      "`nebenbei"' inkrementiert.
+      \begin{lstlisting}[gobble=8]
+        int i = 0;
+        while (1)
+          {
+            if (i >= 10)
+              break;
+            printf ("%d\n", i++);
+          }
+      \end{lstlisting}
+      Eine übersichtlichere Schreibweise derselben Schleife lautet:
+      \begin{lstlisting}[gobble=8]
+        for (int i = 0; i < 10; i++)
+          printf ("%d\n", i++);
+      \end{lstlisting}
+      (Der erzeugte Code ist in beiden Fällen genau derselbe.)
+    \item
+      Mit der \lstinline{continue}-Anweisung springt ein Programm
+      unmittelbar in den nächsten Durchlauf der nächst"-äußeren Schleife.
+    \item
+      Mit der \lstinline{return}-Anweisung kann man eine Funktion
+      (siehe Abschnitt~\ref{Funktionen}) ohne Umweg direkt verlassen.
+    \item
+      Mit der \lstinline{goto}-Anweisung springt ein Programm
+      direkt an einen \newterm{Label}.
+      Dieser besteht aus einem Namen, gefolgt von einem Doppelpunkt.
+      \begin{lstlisting}[gobble=8]
+          int i = 0;
+        loop:
+          if (i >= 10)
+            goto endloop;
+          printf ("%d\n", i++);
+          goto loop;
+        endloop:
+      \end{lstlisting}
+  \end{itemize}
+
+  Ein Programmquelltext sollte immer so gestaltet werden,
+  daß er den Ablauf des Programms unmittelbar ersichtlich macht.
+  Ein vorzeitiges \lstinline{return} stellt einen "`Hinterausgang"'
+  einer Funktion dar und sollte mit Bedacht eingesetzt werden.
+
+  Ähnliches gilt in noch stärkerem Maße für \lstinline{break} und \lstinline{continue}
+  als "`Hinterausgänge"' von Schleifen.
+  Diese sind sicherlich bequeme Möglichkeiten, zusätzliche \lstinline{if}s
+  und zusätzliche Wahrheitswert-Variable zu vermeiden,
+  verschleiern aber langfristig den Ablauf der Befehle.
+  Statt eine Schleife mit \lstinline{break} zu verlassen
+  oder Teile des Schleifeninneren mit \lstinline{continue} zu überspringen,
+  ist es besser, die Schleifenbedingung
+  und \lstinline{if}-Anweisungen innerhalb der Schleife so zu formulieren,
+  daß Sie kein \lstinline{break} oder \lstinline{continue} mehr benötigen.
+  Dadurch versteht man auch selbst besser, was das Programm eigentlich tut.
+  Das Programm wird übersichtlicher und oft sogar kürzer.
+
+  In besonderem Maße gilt dies für die \lstinline{goto}-Anweisung.
+  Hier ist nicht erkennbar, ob der Sprung nach oben geht (Schleife) oder nach unten (Verzweigung).
+  Verschachtelungen von Blöcken und \lstinline{goto}-Sprüngen
+  bereiten dem Compiler zusätzliche Arbeit und stehen somit der Optimierung entgegen.
+  (Es stimmt insbesondere nicht, daß Konstruktionen mit \lstinline{goto}
+  schneller abgearbeitet würden als Konstruktionen mit \lstinline{if} und \lstinline{while}.)
+  Es ist daher besser, \lstinline{goto} nicht zu verwenden
+  und stattdessen den Programmablauf mit Hilfe von Verzweigungen und Schleifen
+  zu strukturieren.
+  (Siehe auch: \url{http://xkcd.com/292/})
+
+  Zusammengefaßt:
+  \begin{hint}
+    Verwenden Sie vorzeitiges \lstinline{return} mit Bedacht.
+
+    Vermeiden Sie die Verwendung von \lstinline{break} und \lstinline{continue}.
+    
+    Verwenden Sie kein \lstinline{goto}.
+  \end{hint}
+
+  \subsection{Funktionen\label{Funktionen}}
+
+  Eine Funktionsdeklaration hat in C die Gestalt:
+  \begin{quote}
+    Typ Name ( Parameterliste )\\
+    \{\\
+    \strut\quad Anweisungen\\
+    \}
+  \end{quote}
+
+  Beispielprogramm: \gitfile{hp}{script}{functions-1.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    void foo (int a, int b)
+    {
+      printf ("foo(): a = %d, b = %d\n", a, b);
+    }
+
+    int main (void)
+    {
+      foo (3, 7);
+      return 0;
+    }
+  \end{lstlisting}
+  (Das Wort "`foo"' ist eine sog.\ \newterm{metasyntaktische Variable} --
+  ein Wort, das absichtlich nichts bedeutet und für einen beliebig austauschbaren Namen steht.)
+
+  Mit dem Funktionsaufruf \lstinline{foo (3, 7)} stellt das Hauptprogramm der Funktion \lstinline{foo()}
+  die Parameterwerte 3 für \lstinline{a} und 7 für \lstinline{b} zur Verfügung.
+
+  Der Rückgabewert der Funktion \lstinline{foo()} ist vom Typ \lstinline{void}.
+  Im Gegensatz zu Datentypen wie z.\,B.\ \lstinline{int}, das für ganze Zahlen steht,
+  steht \lstinline{void} für "`nichts"'.
+
+  Von Ausdrücken zurückgegebene \lstinline{void}-Werte \emph{müssen\/} ignoriert werden.
+  (Von Ausdrücken zurückgegebene Werte anderer Typen \emph{dürfen\/} ignoriert werden.)
+  
+  \breath
+
+  Das Hauptprogramm ist in C eine ganz normale Funktion.
+  Dadurch, daß sie den Namen \lstinline{main} hat,
+  weiß das Betriebssystem, daß es sie bei Programmbeginn aufrufen soll.
+  \lstinline{main()} kann dann seinerseits weitere Funktionen aufrufen.
+
+  Über seinen Rückgabewert (vom Typ \lstinline{int}) teilt \lstinline{main()} dem Betriebssystem mit,
+  ob das Programm erfolgreich beendet werden konnte.
+  Der Rückgabewert 0 steht für "`Erfolg"'; andere Werte stehen für verschiedenartige Fehler.
+  
+  \breath
+
+  Je nachdem, wo und wie Variable deklariert werden,
+  sind sie von verschiedenen Stellen im Programm aus zugänglich
+  und/oder verhalten sich unterschiedlich.
+
+  Beispielprogramm: \gitfile{hp}{script}{functions-2.c}
+  \begin{lstlisting}[style=numbered]
+    #include <stdio.h>
+
+    int a, b = 3;
+
+    void foo (void)
+    {
+      b++;
+      static int a = 5;
+      int b = 7;
+      printf ("foo(): a = %d, b = %d\n", a, b);
+      a++;
+      b++;
+    }
+
+    int main (void)
+    {
+      printf ("main(): a = %d, b = %d\n", a, b);
+      foo ();
+      printf ("main(): a = %d, b = %d\n", a, b);
+      a = b = 12;
+      printf ("main(): a = %d, b = %d\n", a, b);
+      foo ();
+      printf ("main(): a = %d, b = %d\n", a, b);
+      return 0;
+    }
+  \end{lstlisting}
+  Die Ausgabe dieses Programms lautet:
+  \begin{lstlisting}[style=terminal]
+    main(): a = 0, b = 3
+    foo(): a = 5, b = 7
+    main(): a = 0, b = 4
+    main(): a = 12, b = 12
+    foo(): a = 6, b = 7
+    main(): a = 12, b = 13
+  \end{lstlisting}
+  Erklärung:
+  \begin{itemize}
+    \item
+      Der erste Aufruf der Funktion \lstinline{printf()} in Zeile 17 des Programms
+      gibt die Werte der in Zeile 3 deklarierten Variablen aus.
+      Diese lauten 0 für \lstinline{a} und 3 für \lstinline{b}.
+
+      Weil es sich um sog.\ \newterm{globale Variable\/} handelt
+      (Die Deklaration steht außerhalb jeder Funktion.),
+      werden diese Variablen \emph{bei Programmbeginn\/} initialisiert.
+      Für \lstinline{b} steht der Wert 3 für die Initialisierung innerhalb der Deklaration;
+      für \lstinline{a} gilt der implizite Wert 0.
+    \item
+      Der zweite Aufruf von \lstinline{printf()} erfolgt indirekt über die Funktion \lstinline{foo()},
+      die ihrerseits vom Hauptprogramm aus aufgerufen wurde (Zeile 18).
+
+      Oberhalb des \lstinline{printf()} (Zeile 10) befinden sich neue Deklarationen für Variable,
+      die ebenfalls \lstinline{a} (Zeile 8) und \lstinline{b} heißen (Zeile 9).
+      Diese sog.\ \newterm{lokalen Variablen\/} werden auf neue Werte initialisiert,
+      die korrekt ausgegeben werden.
+
+      Ab den Zeilen 8 und 9 bis zum Ende der Funktion \lstinline{foo()}
+      sind die in Zeile 3 deklarierten globalen Variablen \lstinline{a} und \lstinline{b}
+      nicht mehr zugreifbar.
+    \item
+      Der dritte Aufruf von \lstinline{printf()} erfolgt wieder direkt durch das Hauptprogramm (Zeile 19).
+
+      \lstinline{a} hat immer noch den Wert 0,
+      weil durch das \lstinline{a++} in Zeile 11 eine andere Variable inkrementiert wurde,
+      die ebenfalls \lstinline{a} heißt, nämlich die lokale Variable, die in Zeile 8 deklariert wurde.
+
+      Dasselbe gilt für \lstinline{b} hinsichtlich der Zeile 12.
+      In Zeile 7 jedoch greift die Funktion \lstinline{foo()}
+      auf die in Zeile 3 deklarierte globale Variable \lstinline{b} zu,
+      die dadurch den Wert 4 (statt vorher: 3) erhält.
+    \item
+      In Zeile 20 weist das Hauptprogramm beiden in Zeile 3 deklarierten Variablen den Wert 12 zu.
+
+      Genauer: Es weist der Variablen \lstinline{a} den Wert \lstinline{b = 12} zu.
+      Bei \lstinline{b = 12} handelt es sich um einen Ausdruck mit Seiteneffekt,
+      nämlich die Zuweisung des Wertes 12 an die Variable \lstinline{b}.
+      Der Wert des Zuweisungsausdrucks ist ebenfalls 12.
+    \item
+      Der vierte Aufruf von \lstinline{printf()} erfolgt wieder direkt durch das Hauptprogramm (Zeile 21)
+      und gibt erwartungsgemäß zweimal den Wert 12 aus.
+    \item
+      Der fünfte Aufruf von \lstinline{printf()} erfolgt wieder indirekt über die Funktion \lstinline{foo()},
+      die ihrerseits vom Hauptprogramm aus aufgerufen wurde (Zeile 22).
+
+      Die Funktion \lstinline{foo()} gibt wiederum die Werte
+      der in den Zeilen 8 und 9 deklarierten Variablen aus.
+
+      Bei \lstinline{b} (Zeile 9) handelt es sich um eine \newterm{automatische Variable}.
+      Diese ist nur innerhalb des umgebenden Blockes -- hier der Funktion \lstinline{foo()} -- bekannt.
+      Sie wird beim Aufruf der Funktion initialisiert und hat daher in Zeile 10 stets den Wert 7,
+      den sie in Zeile 9 bekommen hat.
+
+      Die Variable \lstinline{a} (Zeile 8) ist hingegen als \newterm{statisch\/}
+      (engl.\ \lstinline{static}) deklariert.
+      Sie behält ihren Wert zwischen zwei Aufrufen von \lstinline{foo()},
+      wird nur zu Programmbeginn initialisiert
+      und ist von außerhalb der Funktion nicht veränderbar.
+
+      \begin{experts}
+        Ausnahme: Wenn einer anderen Funktion die Adresse der \lstinline{static}-Variablen bekannt ist,
+        kann diese die Variable über einen Zeiger verändern -- Siehe Abschnitt~\ref{Zeiger}.
+      \end{experts}
+
+      Da der Anfangswert 5 der Variablen \lstinline{a} bereits einmal erhöht wurde (Zeile 11),
+      wird der Wert 6 ausgegeben.
+      (Die Zuweisung des Wertes 12 im Hauptprogramm bezog sich auf ein anderes \lstinline{a},
+      nämlich das in Zeile 3 deklarierte.)
+    \item
+      Der letzte Aufruf von \lstinline{printf()} erfolgt wieder direkt durch das Hauptprogramm (Zeile 23).
+
+      \lstinline{a} hat immer noch den Wert 12,
+      weil durch das \lstinline{a++} in Zeile 11 eine andere Variable inkrementiert wurde,
+      die ebenfalls \lstinline{a} heißt, nämlich die, die in Zeile 8 deklariert wurde.
+
+      Dasselbe gilt für \lstinline{b} hinsichtlich der Zeile 12.
+      In Zeile 7 jedoch greift die Funktion \lstinline{foo()}
+      auf die in Zeile 3 deklarierte Variable \lstinline{b} zu,
+      die dadurch den Wert 13 (statt vorher: 12) erhält.
+  \end{itemize}
+
+  \subsection{Zeiger\label{Zeiger}}
+
+  In C können an Funktionen grundsätzlich nur Werte übergeben werden.
+  Vom Funktionsrückgabewert abgesehen, hat eine C-Funktion keine Möglichkeit,
+  dem Aufrufer Werte zurückzugeben.
+
+  Es ist dennoch möglich, eine C-Funktion aufzurufen,
+  um eine Variable (oder mehrere) auf einen Wert zu setzen.
+  Hierfür übergibt man der Funktion die \newterm{Speicheradresse\/} der Variablen als Wert.
+  Der Wert ist ein \newterm{Zeiger\/} auf die Variable.
+
+  Wenn einem Zeiger der unäre Operator \lstinline{*} vorangestellt wird,
+  ist der resultierende Ausdruck diejenige Variable, auf die der Zeiger zeigt.
+  In Deklarationen wird dasselbe Symbol dem Namen vorangestellt,
+  um anstelle einer Variablen des genannten Typs
+  eine Variable vom Typ "`Zeiger auf Variable des genannten Typs"' zu deklarieren.
+  (Das \lstinline{*}-Symbol wirkt jeweils nur auf den unmittelbar folgenden Bezeichner.)
+
+  Umgekehrt wird der unäre Operator \lstinline{&} einer Variablen vorangestellt,
+  um einen Ausdruck vom Typ "`Zeiger auf Variable dieses Typs"'
+  mit dem Wert "`Speicheradresse dieser Variablen"' zu erhalten.
+
+  \goodbreak
+  Beispielprogramm: \gitfile{hp}{script}{pointers-1.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    void calc_answer (int *a)
+    {
+      *a = 42;
+    }
+
+    int main (void)
+    {
+      int answer;
+      calc_answer (&answer);
+      printf ("The answer is %d.\n", answer);
+      return 0;
+    }
+  \end{lstlisting}
+  Die Funktion \lstinline{calc_answer()} läßt sich vom Hauptprogramm einen Zeiger \lstinline{a}
+  auf die lokale Variable \lstinline{answer} des Hauptprogramms übergeben.
+  (Aus Sicht des Hauptprogramms ist dieser Zeiger die Adresse \lstinline{&answer}
+  der lokalen Variablen \lstinline{answer}.)
+  Sie schreibt einen Wert in die Variable \lstinline{*a}, auf die der Zeiger \lstinline{a} zeigt.
+  Das Hauptprogramm kann diesen Wert anschließend seiner Variablen \lstinline{answer} entnehmen
+  und mit \lstinline{printf()} ausgeben.
+
+  Vergißt man beim Aufruf den Adreßoperator \lstinline{&},
+  übergibt man den aktuellen Wert der Variablen (hier: eine Zahl)
+  anstelle eines Zeigers (und erhält eine Warnung durch den Compiler).
+  Dieser Wert wird als eine Speicheradresse interpretiert.
+  Diese befindet sich in der Regel außerhalb des Bereichs,
+  den das Betriebssystem dem Programm zugewiesen hat.
+  Ein Versuch der Funktion, auf diese Speicheradresse zuzugreifen,
+  führt dann zum Absturz des Programms (Speicherschutzverletzung).
+
+  \subsection{Arrays und Strings\label{Strings}}
+
+  \subsubsection{Arrays}
+
+  In C ist es möglich, mit einem Zeiger Arithmetik zu betreiben,
+  so daß er nicht mehr auf die ursprüngliche Variable zeigt,
+  sondern auf ihren Nachbarn im Speicher.
+
+  Solche Nachbarn gibt es dann,
+  wenn mehrere Variable gleichen Typs gemeinsam angelegt werden.
+  Eine derartige Ansammlung von Variablen gleichen Typs heißt \newterm{Array\/} (Feldvariable, Vektor).
+
+  Beispielprogramm: \gitfile{hp}{script}{arrays-1.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int prime[5] = { 2, 3, 5, 7, 11 };
+      int *p = prime;
+      int i;
+      for (i = 0; i < 5; i++)
+        printf ("%d\n", *(p + i));
+      return 0;
+    }
+  \end{lstlisting}
+
+  Die initialisierte Variable \lstinline{prime} ist ein Array von fünf ganzen Zahlen.
+  Der Bezeichner \lstinline{prime} des Arrays wird als Zeiger auf eine \lstinline{int}-Variable verwendet.
+  In diesem Sinne sind Arrays und Zeiger in C dasselbe.
+
+  \lstinline{p + i} ist ein Zeiger auf den \lstinline{i}-ten Nachbarn von \lstinline{*p}.
+  Durch Dereferenzieren \lstinline{*(p + i)} erhalten wir
+  den \lstinline{i}-ten Nachbarn von \lstinline{*p} selbst.
+
+  Da diese Kombination -- Zeigerarithmetik mit anschließendem Dereferenzieren --
+  sehr häufig auftritt, stellt C für die Konstruktion \lstinline{*(p + i)}
+  die Abkürzung \lstinline{p[i]} zur Verfügung.
+
+  Die von anderen Sprachen her bekannte Schreibweise \lstinline{p[i]}
+  für das \lstinline{i}-te Element eines Arrays \lstinline{p}
+  ist also in C lediglich eine Abkürzung für \lstinline{*(p + i)},
+  wobei man \lstinline{p} gleichermaßen als Array wie als Zeiger auffassen kann.
+  
+  Wenn wir uns dieser Schreibweise bedienen
+  und anstelle des Zeigers \lstinline{p}, der durchgehend den Wert \lstinline{prime} hat,
+  direkt \lstinline{prime} verwenden,
+  erhalten wir das Beispielprogramm \gitfile{hp}{script}{arrays-2.c}:
+  \goodbreak
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      int prime[5] = { 2, 3, 5, 7, 11 };
+      int *p = prime;
+      int i;
+      for (i = 0; i < 5; i++)
+        printf ("%d\n", p[i]);
+      return 0;
+    }
+  \end{lstlisting}
+
+  Achtung: C prüft \emph{nicht}, ob der Array-Index
+  innerhalb des zulässigen Bereichs liegt,
+  ob also der durch Addition des Index auf die Array-Adresse erhaltene Zeiger
+  noch auf eine Adresse innerhalb des Arrays zeigt.
+
+  Übergelaufene Indizes führen nicht immer sofort zum Absturz des Programms,
+  sondern können z.\,B.\ andere Variablen des Programms überschreiben.
+  Da derartige Fehler äußerst schwer zu entdecken sind,
+  lohnt es sich, Array-Indices vor ihrer Verwendung
+  mit Hilfe von \lstinline{if}-Anweisungen "`von Hand"' zu prüfen.
+
+  \subsubsection{Strings}
+
+  Ein wichtiger Spezialfall ist ein Array, dessen Komponenten den Datentyp \lstinline{char} haben.
+  In C ist \lstinline{char} wie \lstinline{int} eine ganze Zahl;
+  der einzige Unterschied besteht darin, daß der Wertebereich von \lstinline{char} daran angepaßt ist,
+  ein Zeichen (Buchstabe, Ziffer, Satz- oder Sonderzeichen, engl.\ character) aufzunehmen.
+  Ein typischer Wertebereich für den Datentyp \lstinline{char} ist von $-$128 bis 127.
+
+  Ein Initialisierer für ein Array von \lstinline{char}-Variablen kann direkt als Folge von Zeichen
+  (Zeichenkette, engl.\ \newterm{String\/}) mit doppelten Anführungszeichen geschrieben werden.
+  Jedes Zeichen initialisiert eine ganzzahlige Variable mit seinem ASCII-Wert.
+  An das Ende eines in dieser Weise notierten Array-Initialisierers
+  fügt der Compiler implizit einen Ganzzahl-Initialisierer für den Zahlenwert 0 an.
+  Der Array-Initialisierer \lstinline{"Hello"} ist also gleichbedeutend mit
+  \lstinline|{ 72, 101, 108, 108, 111, 0 }|.
+  (Die 72 steht für ein großes H, die 111 für ein kleines o. Man beachte die abschließende 0 am Ende!)
+
+  Ein String in C ist also ein Array von \lstinline{char}s,
+  also ein Zeiger auf \lstinline{char}s,
+  also ein Zeiger auf ganze Zahlen, deren Wertebereich daran angepaßt ist, Zeichen aufzunehmen.
+
+  Wenn bei der Deklaration eines Arrays die Länge aus dem Initialisierer hervorgeht,
+  braucht diese nicht ausdrücklich angegeben zu werden.
+  In diesem Fall folgt auf den Bezeichner nur das Paar eckiger Klammern und der Initialisierer.
+
+  Das Beispielprogramm \gitfile{hp}{script}{strings-1.c} zeigt,
+  wie das Array durchlaufen werden kann, bis die Zahl 0 gefunden wird:
+  \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}
+
+  Durch die Formatangabe \lstinline{%d} wird jedes Zeichen -- korrektermaßen -- als Dezimalzahl ausgegeben.
+  Wenn wir stattdessen die Formatangabe \lstinline{%c} verwenden (für \emph{character\/}),
+  wird für jedes Zeichen -- ebenso korrektermaßen -- sein Zeichenwert (Buchstabe, Ziffer, \dots) ausgegeben
+  (Datei: \gitfile{hp}{script}{strings-2.c}):
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      char hello_world[] = "Hello, world!\n";
+      int i = 0;
+      while (hello_world[i] != 0)
+        printf ("%c", hello_world[i++]);
+      return 0;
+    }
+  \end{lstlisting}
+
+  Durch Verwendung von Pointer-Arithmetik
+  und Weglassen der überflüssigen Abfrage \lstinline{!= 0}
+  erhalten wir das äquivalente Beispielprogramm \gitfile{hp}{script}{strings-3.c}:
+  \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}
+  Dieses ist die in C übliche Art, eine Schleife zu schreiben,
+  die nacheinander alle Zeichen in einem String bearbeitet.
+
+  \breath
+
+  Eine weitere Formatangabe \lstinline{%s} dient in \lstinline{printf()} dazu,
+  direkt einen kompletten String bis ausschließlich der abschließenden 0 auszugeben.
+
+  Beispielprogramm: \gitfile{hp}{script}{strings-4.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      char *p = "Hello, world!";
+      printf ("%s\n", p);
+      return 0;
+    }
+  \end{lstlisting}
+
+  Anstatt als Array, das dann einem Zeiger zugewiesen wird,
+  deklarieren wir die Variable \lstinline{hello_world} direkt als Zeiger.
+  Dies ist die in C übliche Art, mit String-Konstanten umzugehen.
+
+  Allein die Formatspezifikation entscheidet darüber,
+  wie die Parameter von \lstinline{printf()} bei der Ausgabe dargestellt werden:
+  \begin{quote}
+    \begin{tabular}{cl}
+      \lstinline|%d| & Der Parameter wird als Zahlenwert interpretiert und dezimal ausgegeben. \\
+      \lstinline|%x| & Der Parameter wird als Zahlenwert interpretiert und hexadezimal ausgegegeben.\\
+      \lstinline|%c| & Der Parameter wird als Zahlenwert interpretiert und als Zeichen ausgegeben.\\
+      \lstinline|%s| & Der Parameter wird als Zeiger interpretiert und als Zeichenfolge ausgegeben.
+    \end{tabular}
+  \end{quote}
+
+  \subsection{String-Operationen}
+
+  Mit \lstinline{#include <string.h>} steht uns eine Sammlung von Funktionen
+  zur Bearbeitung von Strings (= Array von \lstinline{char}-Variablen
+  $\approx$ Zeiger auf \lstinline{char}-Variable) zur Verfügung:
+
+  \begin{itemize}
+    \item[\textbf{;\,)}]
+      \lstinline{+}-Operationen
+
+      Durch Addieren einer ganzen Zahl auf die Startadresse des Strings
+      entsteht ein Zeiger auf einen neuen String,
+      der erst ein paar Zeichen später beginnt.
+      Auf diese Weise kann man in C ganz ohne Benutzung einer Bibliothek
+      den Anfang eines Strings abschneiden.
+
+      \begin{lstlisting}[gobble=8]
+        char hello[] = "Hello, world!\n";
+        printf ("%s\n", hello + 7);
+      \end{lstlisting}
+
+      \textbf{Achtung:} Es findet keinerlei Prüfung statt,
+      ob der Zeiger nach der Addition
+      noch auf einen Bereich innerhalb des Strings zeigt.
+      Wenn man auf diese Weise über den String hinausliest,
+      führt dies zu unsinnigen Ergebnissen
+      bis hin zu einem Absturz (Speicherzugriffsfehler).
+
+      Beispielprogramm: \gitfile{hp}{20161024}{strings-14.c}
+
+    \item[\textbf{;\,)}]
+      Null-Zeichen in den String schreiben
+
+      Durch das Schreiben eines Null-Symbols (Zahlenwert 0) in den String
+      kann man diesen ganz ohne Benutzung einer Bibliothek
+      an dieser Stelle abschneiden.
+
+      \begin{lstlisting}[gobble=8]
+        char hello[] = "Hello, world!\n";
+        hello[5] = 0;
+        printf ("%s\n", hello);
+      \end{lstlisting}
+
+      \textbf{Achtung:} Es findet keinerlei Prüfung statt,
+      ob der Schreibvorgang noch innerhalb des Strings stattfindet.
+      Wenn man auf diese Weise über den String hinauschreibt,
+      werden andere Variable überschrieben,
+      was in der Regel zu einem Absturz führt (Speicherzugriffsfehler).
+
+      Beispielprogramm: \gitfile{hp}{20161024}{strings-14.c}
+
+    \item
+      \lstinline{strlen()} -- Ermitteln der Länge eines Strings
+
+      Das abschließende Null-Symbol wird für die Länge \emph{nicht\/} mitgezählt,
+      es verbraucht aber natürlich dennoch Speicherplatz.
+
+      \begin{lstlisting}[gobble=8]
+        char hello[] = "Hello, world!\n";
+        printf ("%s\n", strlen (hello));
+      \end{lstlisting}
+
+      Beispielprogramm: \gitfile{hp}{20161024}{strings-14.c}
+
+    \item
+      \lstinline{strcmp()} -- Strings vergleichen
+
+      Wenn der erste String-Parameter alphabetisch vor dem zweiten liegt,
+      gibt \lstinline{strcmp()} den Wert \lstinline{-1} zurück,
+      wenn es umgekehrt ist, den Wert \lstinline{1},
+      wenn die Strings gleich sind, den Wert \lstinline{0}.
+
+      \begin{lstlisting}[gobble=8]
+        char *anton = "Anton";
+        char *zacharias = "Zacharias";
+
+        printf ("%d\n", strcmp (anton, zacharias));
+        printf ("%d\n", strcmp (zacharias, anton));
+        printf ("%d\n", strcmp (anton, anton));
+      \end{lstlisting}
+      
+      Der Vergleich erfolgt im Sinne des verwendeten Zeichensatzes,
+      normalerweise ASCII. Dabei kommen z.\,B.\ Großbuchstaben grundsätzlich
+      \emph{vor\/} den Kleinbuchstaben.
+
+      Beispielprogramm: \gitfile{hp}{20161024}{strings-15.c}
+
+    \item
+      \lstinline{strcat()} -- String an anderen String anhängen
+
+      Die Funktion \lstinline{strcat()} hängt den zweiten String
+      an den ersten an.
+
+      \begin{lstlisting}[gobble=8]
+        char *anton = "Anton";
+        char buffer[100] = "Huber ";
+        strcat (buffer, anton);
+        printf ("%s\n", buffer);
+      \end{lstlisting}
+
+      \textbf{Achtung:} Es findet keinerlei Prüfung statt,
+      ob der resultierende String noch in den für den ersten Strng reservierten
+      Speicherbereich (Puffer) hineinpaßt.
+      Wenn man auf diese Weise über den String hinauschreibt,
+      werden andere Variable überschrieben,
+      was in der Regel zu einem Absturz führt (Speicherzugriffsfehler).
+      
+      Beispielprogramm: \gitfile{hp}{20161024}{strings-15.c}
+
+    \item
+      \lstinline{sprintf()} -- in String schreiben
+
+      \lstinline{sprintf()} funktioniert ähnlich wie \lstinline{printf()},
+      schreibt aber nicht zur Standardausgabe (Bildschirm),
+      sondern in einen String hinein, den man als ersten Parameter übergibt.
+
+      \begin{lstlisting}[gobble=8]
+        char buffer[100] = "";
+        sprintf (buffer, "Die Antwort lautet: %d", 42);
+        printf ("%s\n", buffer);
+      \end{lstlisting}
+
+      \textbf{Achtung:} Es findet keinerlei Prüfung statt, ob der Ziel-String
+      (Puffer -- \newterm{Buffer\/}) groß genug ist, um die Ausgabe aufzunehmen.
+      Wenn dies nicht der Fall ist un man über das Ende des Strings hinausschreibt,
+      werden andere Variable des Programms überschrieben (\newterm{Buffer Overflow}),
+      was in der Regel zu einem Absturz führt (Speicherzugriffsfehler).
+      Derartige Fehler sind schwer zu finden und befinden sich zum Teil bis heute
+      in Programmen, die im Internet zum Einsatz kommen
+      und Angreifern ermöglichen, Rechner von außen zu übernehmen.
+
+      Um dieses Problem zu vermeiden, empfiehlt es sich,
+      anstelle von \lstinline{sprintf()} die Funktion \lstinline{snprintf()}
+      zu verwenden. Diese erwartet als zweiten Parameter die Länge des Ziel-Strings
+      und sorgt dafür, daß nicht über dessen Ende hinausgeschrieben wird.
+
+      Beispielprogramm: \gitfile{hp}{20161024}{strings-16.c}
+
+    \item
+      \lstinline{strstr()} -- in String suchen
+
+      Die Funktion \lstinline{strstr()}
+      such im ersten String-Parameter nach dem zweiten
+      und gibt als Ergebnis einen Zeiger auf diejenige Stelle zurück,
+      an der der zweite String gefunden wurde.
+
+      \begin{lstlisting}[gobble=8]
+        char *answer = strstr (buffer, "Antwort");
+        printf ("%s\n", answer);
+        printf ("found at: %zd\n", answer - buffer);
+      \end{lstlisting}
+
+      Wenn man dies in einen Array-Index umrechnen will,
+      geschieht dies durch Subtrahieren des Zeigers auf den ersten String.
+      Das Ergebnis ist eine Integer vom Typ \lstinline{ssize_t}
+      (\emph{signed size type\/}). Um diese mit \lstinline{printf()} auszugeben,
+      verwendet man \lstinline{%zd} anstelle von \lstinline{%d}.
+
+      Beispielprogramm: \gitfile{hp}{20161024}{strings-16.c}
+      
+  \end{itemize}
+
+  \subsection{Parameter des Hauptprogramms}
+
+  Bisher haben wir das Hauptprogramm \lstinline{main()} immer in der Form
+  \begin{lstlisting}
+    int main (void)
+    {
+      ...
+      return 0;
+    }
+  \end{lstlisting}
+  geschrieben.
+  
+  Tatsächlich kann das Hauptprogramm vom Betriebssystem Parameter entgegennehmen
+  (Datei: \gitfile{hp}{script}{params-1.c}):
+  \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}
+  Bei der ganzen Zahl \lstinline{int argc} handelt es sich um die Anzahl der übergebenen Parameter.
+
+  \lstinline{char **argv} ist ein Zeiger auf einen Zeiger auf \lstinline{char}s,
+  also ein Array von Arrays von \lstinline{char}s,
+  also ein Array von Strings.
+  Wenn wir es mit einem Index \lstinline{i} versehen,
+  greifen wir auf auf den \lstinline{i}-ten Parameter zu.
+  Der Index \lstinline{i} läuft, wie in C üblich, von \lstinline{0} bis \lstinline{argc - 1}.
+  Das o.\,a.\ Beispielprogramm gibt alle übergebenen Parameter auf dem Standardausgabegerät aus:
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -std=c99 -Wall -O params-1.c -o params-1¿
+    $ ¡./params-1 foo bar baz¿
+    argc = 4
+    argv[0] = "./params-1"
+    argv[1] = "foo"
+    argv[2] = "bar"
+    argv[3] = "baz"
+  \end{lstlisting}
+  Genaugenommen übergibt das Betriebssystem dem Programm die gesamte Kommandozeile:
+  Der nullte Parameter ist der Aufruf der ausführbaren Datei selbst
+  -- in genau der Weise, in der er eingegeben wurde.
+
+  Neben \lstinline{argc} gibt es noch einen weiteren Mechanismus,
+  mit dem das Betriebssystem dem Programm die Anzahl der übergebenen Parameter mitteilt:
+  Als Markierung für das Ende der Liste wird ein zusätzlicher Zeiger übergeben, der auf "`nichts"' zeigt,
+  dargestellt durch die Speicheradresse mit dem Zahlenwert 0,
+  in C mit \lstinline{NULL} bezeichnet.
+
+  Um die Parameter des Programms in einer Schleife durchzugehen,
+  können wir also entweder von \lstinline{0} bis \lstinline{argc - 1} zählen
+  (Schleifenbedingung \lstinline{i < argc}, Datei: \gitfile{hp}{script}{params-1.c} -- siehe oben)
+  oder die Schleife mit dem Erreichen der Endmarkierung abbrechen
+  (Schleifenbedingung \lstinline{argv[i] != NULL}, Datei: \gitfile{hp}{script}{params-2.c}).
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (int argc, char **argv)
+    {
+      printf ("argc = %d\n", argc);
+      for (int i = 0; argv[i] != NULL; i++)
+        printf ("argv[%d] = \"%s\"\n", i, argv[i]);
+      return 0;
+    }
+  \end{lstlisting}
+  Auch für Zeiger gilt: \lstinline{NULL} entspricht dem Wahrheitswert "`falsch"';
+  alles andere dem Wahrheitswert "`wahr"'.
+  Wir dürfen die Schleifenbedingung also wie folgt abkürzen (Datei: \gitfile{hp}{script}{params-3.c}):
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (int argc, char **argv)
+    {
+      printf ("argc = %d\n", argc);
+      for (char **p = argv; *p; p++)
+        printf ("argv[p] = \"%s\"\n", *p);
+      return 0;
+    }
+  \end{lstlisting}
+
+  \subsection{Strukturen\label{Strukturen}}
+
+  In vielen Situationen ist es sinnvoll,
+  mehrere Variable zu einer Einheit zusammenzufassen.
+
+  Das folgende Beispielprogramm \gitfile{hp}{script}{structs-1.c}
+  faßt drei Variable \lstinline{day}, \lstinline{month} und \lstinline{year}
+  zu einem einzigen -- neuen -- Datentyp \lstinline{date} zusammen:
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    typedef struct
+    {
+      char day, month;
+      int year;
+    }
+    date;
+
+    int main (void)
+    {
+      date today = { 1, 11, 2016 };
+      printf ("%d.%d.%d\n", today.day, today.month, today.year);
+      return 0;
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(4,4.95){\makebox(0,0)[l]{$\left.\rule{0pt}{1.4cm}\right\}$ neuer Datentyp: date}}
+    \put(4.9,3){\vector(-1,-1){0.5}}
+    \put(5,3){\makebox(0,0)[l]{Variable deklarieren und initialisieren}}
+    \put(5.55,1.1){\vector(-1,1){0.5}}
+    \put(5.65,1.1){\makebox(0,0)[l]{Zugriff auf die Komponente day
+                                    der strukturierten Variablen today}}
+  \end{picture}%
+  (Zur Erinnerung: Der Datentyp \lstinline{char} steht für Zahlen,
+  die mindestens die Werte von $-$128 bis 127 annehmen können.
+  C unterscheidet nicht zwischen Zahlen und darstellbaren Zeichen.)
+
+  Eine wichtige Anwendung derartiger \newterm{strukturierter Datentypen\/} besteht darin,
+  zusammengehörige Daten als Einheit an Funktionen übergeben zu können
+  (Beispielprogramm: \gitfile{hp}{script}{structs-2.c}):
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    typedef struct
+    {
+      char day, month;
+      int year;
+    }
+    date;
+
+    void set_date (date *d)
+    {
+      (*d).day = 1;
+      (*d).month = 11;
+      (*d).year = 2016;
+    }
+
+    int main (void)
+    {
+      date today;
+      set_date (&today);
+      printf ("%d.%d.%d\n", today.day,
+              today.month, today.year);
+      return 0;
+    }
+  \end{lstlisting}
+  Die Funktion \lstinline{set_date()} hat die Aufgabe,
+  eine \lstinline{date}-Variable mit Werten zu füllen (sog.\ \newterm{Setter\/}-Funktion).
+  Damit dies funktionieren kann, übergibt das Hauptprogramm an die Funktion
+  einen Zeiger auf die strukturierte Variable.
+  Über diesen Zeiger kann die Funktion dann auf alle Komponenten der Struktur zugreifen.
+  (Die Alternative wäre gewesen, für jede Komponente einen separaten Zeiger zu übergeben.)
+
+  Da die Zeigerdereferenzierung \lstinline{*foo}
+  mit anschließendem Komponentenzugriff \lstinline{(*foo).bar}
+  eine sehr häufige Kombination ist, kennt C hierfür eine Abkürzung:
+  \lstinline{foo->bar}
+
+  \goodbreak
+  Beispielprogramm: \gitfile{hp}{script}{structs-3.c}
+  \goodbreak
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    typedef struct
+    {
+      char day, month;
+      int year;
+    }
+    date;
+
+    void set_date (date *d)
+    {
+      d->day = 1;
+      d->month = 11;
+      d->year = 2016;
+    }
+
+    int main (void)
+    {
+      date today;
+      set_date (&today);
+      printf ("%d.%d.%d\n", today.day,
+              today.month, today.year);
+      return 0;
+    }
+  \end{lstlisting}
+
+  \goodbreak
+  \subsubsection*{Aufgabe}
+
+  Schreiben Sie eine Funktion \lstinline{inc_date (date *d)}
+  die ein gegebenes Datum \lstinline{d}
+  unter Beachtung von Schaltjahren auf den nächsten Tag setzt.
+
+  \goodbreak
+  \subsubsection*{Lösung}
+
+  Wir lösen die Aufgabe über den sog.\ \newterm{Top-Down-Ansatz} ("`vom Allgemeinen zum Konkreten"').
+  Als besonderen Trick approximieren wir unfertige Programmteile zunächst durch einfachere, fehlerbehaftete.
+  Diese fehlerhaften Programmteile sind in den untenstehenden Beispielen rot markiert.
+  (In der Praxis würde man diese Zeilen unmittelbar durch die richtigen ersetzen;
+  die fehlerhaften "`Platzhalter"' sollten also jeweils nur für Sekundenbruchteile im Programm stehen.
+  Falls man einmal tatsächlich einen Platzhalter für mehrere Sekunden oder länger stehen lassen sollte
+  -- z.\,B., weil an mehreren Stellen Änderungen notwendig sind --,
+  sollte man ihn durch etwas Uncompilierbares (z.\,B.\ \lstinline{@@@}) markieren,
+  damit man auf jeden Fall vermeidet, ein fehlerhaftes Programm auszuliefern.)
+
+  Zunächst kopieren wir das Beispielprogramm \gitfile{hp}{script}{structs-3.c}
+  und ergänzen den Aufruf der -- noch nicht existierenden -- Funktion \lstinline{inc_date()}
+  (Datei: \gitfile{{hp}script}{incdate-0.c}):
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    typedef struct
+    {
+      char day, month;
+      int year;
+    }
+    date;
+  \end{lstlisting}
+  \begin{lstlisting}
+    void set_date (date *d)
+    {
+      d->day = 31;
+      d->month = 1;
+      d->year = 2012;
+    }
+  \end{lstlisting}
+  \begin{lstlisting}
+    int main (void)
+    {
+      date today;
+      set_date (&today);
+      ¡inc_date (&today);¿
+      printf ("%d.%d.%d\n", today.day, today.month, today.year);
+      return 0;
+    }
+  \end{lstlisting}
+
+  Als nächstes kopieren wir innerhalb des Programms die Funktion \lstinline{get_date()}
+  als "`Schablone"' für \lstinline{inc_date()}:
+  \begin{lstlisting}
+    void get_date (date *d)
+    {
+      d->day = 31;
+      d->month = 1;
+      d->year = 2012;
+    }
+
+    ¡void inc_date (date *d)
+    {
+      d->day = 31;
+      d->month = 1;
+      d->year = 2012;
+    }¿
+  \end{lstlisting}
+  Da die Funktion jetzt existiert, ist der Aufruf nicht mehr fehlerhaft.
+  Stattdessen haben wir jetzt eine fehlerhafte Funktion \lstinline{inc_date()}.
+
+  Im nächsten Schritt ersetzen wir die fehlerhafte Funktion
+  durch ein simples Hochzählen der \lstinline{day}-Kom\-po\-nen\-te (Datei: \gitfile{hp}{script}{incdate-1.c})
+  \begin{lstlisting}
+    void inc_date (date *d)
+    {
+      ¡d->day += 1;  /* FIXME */¿
+    }
+  \end{lstlisting}
+  Diese naive Vorgehensweise versagt, sobald wir den Tag über das Ende des Monats hinauszählen.
+  Dies reparieren wir im nächsten Schritt,
+  wobei wir für den Moment inkorrekterweise annehmen, daß alle Monate 30 Tage hätten
+  und das Jahr beliebig viele Monate.
+  (Datei: \gitfile{hp}{script}{incdate-2.c}):
+  \begin{lstlisting}
+    void inc_date (date *d)
+    {
+      d->day++;
+      ¡if (d->day > 31)  /* FIXME */
+        {
+          d->month++;  /* FIXME */
+          d->day = 1;
+        }¿
+    }
+  \end{lstlisting}
+  Zunächst reparieren wir den Fehler, der am Ende des Jahres entsteht
+  (Datei: \gitfile{hp}{script}{incdate-3.c}).
+  \begin{lstlisting}
+    void inc_date (date *d)
+    {
+      d->day++;
+      if (d->day > 31)  /* FIXME */
+        {
+          d->month++;
+          d->day = 1;
+          ¡if (d->month > 12)
+            {
+              d->year++;
+              d->month = 1;
+            }¿
+        }
+    }
+  \end{lstlisting}
+  Das Problem der unterschiedlich langen Monate gehen wir wieder stufenweise an.
+  Zunächst ersetzen wir die Konstante \lstinline{31}
+  durch eine Variable \lstinline{days_in_month}.
+  (Datei: \gitfile{hp}{script}{incdate-4.c})
+  \begin{lstlisting}
+    void inc_date (date *d)
+    {
+      d->day++;
+      ¡int days_in_month = 31;  /* FIXME */
+      if (d->day > days_in_month)¿
+        {
+          d->month++;
+          d->day = 1;
+          if (d->month > 12)
+            {
+              d->year++;
+              d->month = 1;
+            }
+        }
+    }
+  \end{lstlisting}
+  Anschließend reparieren wir den fehlerhaften (konstanten) Wert der Variablen,
+  wobei wir zunächst das Problem der Schaltjahre aussparen (Datei: \gitfile{hp}{script}{incdate-5.c}):
+  \begin{lstlisting}
+    void inc_date (date *d)
+    {
+      d->day++;
+      int days_in_month = 31;
+      ¡if (d->month == 2)
+        days_in_month = 28;  /* FIXME */
+      else if (d->month == 4 || d->month == 6 || d->month == 9 || d->month == 11)
+        days_in_month = 30;¿
+      if (d->day > days_in_month)
+        {
+          d->month++;
+          d->day = 1;
+          if (d->month > 12)
+            {
+              d->year++;
+              d->month = 1;
+            }
+        }
+    }
+  \end{lstlisting}
+  Auf dieselbe Weise lagern wir das Problem "`Schaltjahr oder nicht?"'
+  in eine Variable aus. Diese ist wieder zunächst konstant
+  (Datei: \gitfile{hp}{script}{incdate-6.c}):
+  \begin{lstlisting}
+    void inc_date (date *d)
+    {
+      d->day++;
+      int days_in_month = 31;
+      if (d->month == 2)
+        {
+          ¡int is_leap_year = 1;  /* FIXME */
+          if (is_leap_year)
+            days_in_month = 29;
+          else
+            days_in_month = 28;¿
+        }
+      else if (d->month == 4 || d->month == 6 || d->month == 9 || d->month == 11)
+        days_in_month = 30;
+      if (d->day > days_in_month)
+        {
+          d->month++;
+          d->day = 1;
+          if (d->month > 12)
+            {
+              d->year++;
+              d->month = 1;
+            }
+        }
+    }
+  \end{lstlisting}
+  Als nächstes ergänzen wir die Vier-Jahres-Regel für Schaltjahre
+  (Datei \gitfile{hp}{script}{incdate-7.c}):
+  \begin{lstlisting}
+          ¡int is_leap_year = 0;
+          if (d->year % 4 == 0)
+            is_leap_year = 1;  /* FIXME */¿
+          if (is_leap_year)
+            days_in_month = 29;
+          else
+            days_in_month = 28;
+  \end{lstlisting}
+  Das nun vorliegende Programm arbeitet bereits für den julianischen Kalender
+  sowie für alle Jahre von 1901 bis 2099 korrekt,
+  nicht jedoch für z.\,B.\ das Jahr 2100 (Datei: \gitfile{hp}{script}{incdate-8.c}).
+  Damit das Programm für den aktuell verwendeten gregorianischen Kalender korrekt arbeitet,
+  ergänzen wir noch die Ausnahme, daß durch 100 teilbare Jahre keine Schaltjahre sind,
+  sowie die Ausnahme von der Ausnahme, daß durch 400 teilbare Jahre
+  (z.\,B.\ das Jahr 2000) eben doch Schaltjahre sind (Datei: \gitfile{hp}{script}{incdate-9.c}):
+  \begin{lstlisting}
+          int is_leap_year = 0;
+          if (d->year % 4 == 0)
+            ¡{
+              is_leap_year = 1;
+              if (d->year % 100 == 0)
+                {
+                  is_leap_year = 0;
+                  if (d->year % 400 == 0)
+                    is_leap_year = 1;
+                }
+            }¿
+          if (is_leap_year)
+            days_in_month = 29;
+          else
+            days_in_month = 28;
+  \end{lstlisting}
+  Damit ist die Aufgabe gelöst.
+  Der vollständige Quelltext der Lösung (Datei: \gitfile{hp}{script}{incdate-9.c}) lautet:
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    typedef struct
+    {
+      char day, month;
+      int year;
+    }
+    date;
+  \end{lstlisting}
+  \begin{lstlisting}
+    void set_date (date *d)
+    {
+      d->day = 28;
+      d->month = 2;
+      d->year = 2000;
+    }
+  \end{lstlisting}
+  \begin{lstlisting}
+    void inc_date (date *d)
+    {
+      d->day++;
+      int days_in_month = 31;
+      if (d->month == 2)
+        {
+          int is_leap_year = 0;
+          if (d->year % 4 == 0)
+            {
+              is_leap_year = 1;
+              if (d->year % 100 == 0)
+                {
+                  is_leap_year = 0;
+                  if (d->year % 400 == 0)
+                    is_leap_year = 1;
+                }
+            }
+          if (is_leap_year)
+            days_in_month = 29;
+          else
+            days_in_month = 28;
+        }
+      else if (d->month == 4 || d->month == 6 || d->month == 9 || d->month == 11)
+        days_in_month = 30;
+      if (d->day > days_in_month)
+        {
+          d->month++;
+          d->day = 1;
+          if (d->month > 12)
+            {
+              d->year++;
+              d->month = 1;
+            }
+        }
+    }
+  \end{lstlisting}
+  \begin{lstlisting}
+    int main (void)
+    {
+      date today;
+      set_date (&today);
+      inc_date (&today);
+      printf ("%d.%d.%d\n", today.day, today.month, today.year);
+      return 0;
+    }
+  \end{lstlisting}
+  Bemerkungen:
+  \begin{itemize}
+    \item
+      Anstatt die Anzahl der Tage in einem Monat
+      innerhalb der Funktion \lstinline{set_date()} zu berechnen,
+      ist es sinnvoll, hierfür eine eigene Funktion zu schreiben.
+      Dasselbe gilt für die Berechnung,
+      ob es sich bei einem gegebenem Jahr um ein Schaltjahr handelt.
+    \item
+      Der Top-Down-Ansatz ist eine bewährte Methode,
+      um eine zunächst komplexe Aufgabe in handhabbare Teilaufgaben zu zerlegen.
+      Dies hilft ungemein, in längeren Programmen (mehrere Zehntausend bis Millionen Zeilen)
+      die Übersicht zu behalten.
+    \item
+      Der Trick mit dem zunächst fehlerhaften Code hat den Vorteil,
+      daß man jeden Zwischenstand des Programms compilieren und somit austesten kann.
+      Er birgt andererseits die Gefahr in sich,
+      die Übersicht über den fehlerhaften Code zu verlieren,
+      so daß es dieser bis in die Endfassung schafft.
+      Neben dem bereits erwähnten Trick uncompilierbarer Symbole
+      haben sich hier Kommentare wie \lstinline{/* FIXME */} bewährt,
+      auf die man seinen Code vor der Auslieferung der Endfassung
+      noch einmal automatisch durchsuchen läßt.
+%    \item
+%      Allen an der Berechnung beteiligten Funktionen
+%      wurde hier ein Zeiger \lstinline{d} auf die vollständige \lstinline{date}-Struktur übergeben.
+%      Dies ist ein \newterm{objektorientierter Ansatz},
+%      bei dem man die Funktionen als \newterm{Methoden\/} der \newterm{Klasse\/} \lstinline{date} auffaßt.
+%      (Von sich aus unterstützt die Sprache C -- im Gegensatz zu z.\,B.\ C++ -- keine Klassen und Methoden,
+%      sondern man muß diese bei Bedarf in der oben beschrieben Weise selbst basteln.
+%      Für eine fertige Lösung siehe z.\,B.\ die \file{GObject}-Bibliothek -- \url{http://gtk.org}.)
+%
+%      Alternativ könnte man sich mit den zu übergebenden Parametern auf diejenigen beschränken,
+%      die in der Funktion tatsächlich benötigt werden,
+%      also z.\,B.\ \lstinline{int days_in_month (int month, int year)}
+%      und \lstinline{int is_leap_year (int year)}.
+%      Damit wären die Funktionen allgemeiner verwendbar.
+%
+%      Welcher dieser beiden Ansätze der bessere ist, hängt von der Situation
+%      und von persönlichen Vorlieben ab.
+  \end{itemize}
+
+  \subsection{Dateien und Fehlerbehandlung}
+
+  Die einfachste Weise, in C mit Dateien umzugehen,
+  ist über sog.\ \newterm{Streams}.
+
+  Die Funktion \lstinline{fopen()}
+  erwartet als Parameter einen Dateinamen und einen Modus
+  und gibt als Rückgabewert einen Zeiger auf einen Stream
+  -- eine Struktur vom Typ \lstinline{FILE} -- zurück:
+  \begin{lstlisting}
+    FILE *f = fopen ("fhello.txt", "w");
+  \end{lstlisting}
+  Als Modus übergibt man eine String-Konstante.
+  Diese kann die Buchstaben \lstinline{r} für Lesezugriff (\emph{read\/}),
+  \lstinline{w} für Schreibzugriff mit Überschreiben (\emph{write\/})
+  sowie \lstinline{a} für Schreibzugriff mit Anhängen (\emph{append\/}) enthalten
+  und zusätzlich den Buchstaben \lstinline{b} für Binärdaten (im Gegensatz zu Text).
+
+  Die in C üblichen Ein-/Ausgabefunktionen wie z.\,B.\ \lstinline{printf()}
+  haben Varianten mit vorangestelltem "`f-"', z.\,B.\ \lstinline{fprintf()}.
+  Wenn man diesen Funktionen als ersten Parameter einen Zeiger auf ein
+  \lstinline{FILE} übergibt, verhalten sie sich in der üblichen Weise,
+  nur daß sie nicht zur Standardausgabe schreiben (Bildschirm),
+  sondern in die Datei, deren Name beim Öffnen des \lstinline{FILE}
+  angegeben wurde (Datei \gitfile{hp}{script}{fhello-1.c}):
+
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      FILE *f = fopen ("fhello.txt", "w");
+      fprintf (f, "Hello, world!\n");
+      fclose (f);
+      return 0;
+    }
+  \end{lstlisting}
+
+  Der von \lstinline{fopen()} zurückgegebene Wert ist ein Zeiger.
+  Ein Aufruf von \lstinline{fprintf()} oder \lstinline{fclose()}
+  stellt eine Verwendung dieses Zeigers dar.
+  Wenn die Datei -- aus welchen Gründen auch immer -- nicht geöffnet werden konnte,
+  ist dieser Zeiger \lstinline{NULL}, und seine Verwendung führt
+  zum Absturz des Programms.
+  Es ist daher dringend empfohlen, diesen Fall zu prüfen
+  (Datei: \gitfile{hp}{script}{fhello-2.c}):
+
+  \begin{lstlisting}
+    #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}
+
+  Anstatt einfach nur "`nichts"' zu machen,
+  ist es besser, eine sinnvolle Fehlermeldung auszugeben.
+  Dabei sind wir nicht allein auf "`Fehler beim Öffnen der Datei"' angewiesen:
+  Das Betriebssystem teilt uns über die globale Variable \lstinline{errno} mit,
+  was genau beim Öffnen der Datei fehlgeschlagen ist.
+  Mit \lstinline{#include <errno.h>} erhält unser Programm
+  Zugriff auf diese Variable
+  und kann den Fehler-Code in seiner Fehlermeldung mit ausgeben
+  (Datei: \gitfile{hp}{script}{fhello-3.c}):
+
+  \begin{lstlisting}
+    #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}
+
+  Die Ausgabe von Fehler erfolgt üblicherweise nicht mit einem "`normalen"'
+  \lstinline{printf()}, sondern mit einem \lstinline{fprintf()} in die
+  bereits standardmäßig geöffnete Datei \lstinline{stderr}, die
+  \newterm{Fehlerausgabe}-Datei.
+  Diese landet -- genau wie die Standardausgabe -- zunächst auf dem Bildschirm,
+  kann aber separat von der Standardausgabe umgeleitet werden,
+  z.\,B.\ in eine separate Datei.
+
+  Die Bedeutung der Fehler-Codes ist
+  nicht nur in der Dokumentation des Betriebssystems,
+  sondern auch in einer C-Bibliothek hinterlegt.
+  Mit \lstinline{#include <string.h>} erhalten wir
+  eine Funktion \lstinline{strerror()},
+  die den Fehler-Code in eine für Menschen lesbare Fehlermeldung umwandelt
+  (Datei: \gitfile{hp}{script}{fhello-4.c}):
+
+  \begin{lstlisting}
+    #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}
+
+  Ein häufiger Fall ist, daß das Programm nach Ausgabe der Fehlermeldung
+  direkt beendet werden soll.
+  Hierbei wird nicht das sonst übliche \lstinline{return 0}
+  des Hauptprogramms aufgerufen, sondern \lstinline{return}
+  mit einer anderen Zahl als 0, z.\,B.\ \lstinline{return 1}
+  für "`allgemeiner Fehler"'.
+  Üblich ist es, den Fehler-Code zurückgegeben
+  -- \lstinline{return errno} --, um diesen auch an denjenigen,
+  der das Programm aufgerufen hat, weiterzureichen.
+
+  Für diese standardisierte Reaktion auf Fehler
+  steht mit \lstinline{#include <error.h>}
+  eine Funktion \lstinline{error()} zur Verfügung,
+  die eine zum übergebenen Fehler-Code gehörende Fehlermeldung ausgibt
+  und anschließend das Programm mit einem übergebenen Fehler-Code beendet
+  (Datei: \gitfile{hp}{script}{fhello-5.c}):
+
+  \begin{lstlisting}
+    #include <stdio.h>
+    #include <errno.h>
+    #include <error.h>
+
+    int main (void)
+    {
+      FILE *f = fopen ("fhello.txt", "w");
+      if (!f)
+         error (1, errno, "cannot open file");
+      fprintf (f, "Hello, world!\n");
+      fclose (f);
+      return 0;
+    }
+  \end{lstlisting}
+
+  In diesem Fall ist \lstinline{1} der Code,
+  den das Programm im Fehlerfall zurückgeben soll,
+  und \lstinline{errno} ist die Nummer des Fehlers,
+  dessen Fehlermeldung auf dem Bildschirm (\lstinline{stderr})
+  ausgegeben werden soll.
+  (Üblich wäre wie gesagt auch, hier zweimal \lstinline{errno} zu übergeben.)
+
+  \textbf{Bitte niemals Fehler einfach ignorieren!}
+  Ein Programm, das bereits auf eine nicht gefundene Datei
+  mit einem Absturz reagiert, ist der Alptraum jedes Benutzers
+  und eines jeden, der versucht, in dem Programm Fehler zu beheben.
+  Ein korrekt geschriebenes Programm stürzt \emph{niemals\/} ab,
+  sondern beendet sich schlimmstensfalls mit einer aussagekräftigen Fehlermeldung,
+  die uns in die Lage versetzt, die Fehlerursache zu beheben.
+
+  \section{Bibliotheken}
+
+  \subsection{Der Präprozessor\label{Praeprozessor}}
+
+  Der erste Schritt beim Compilieren eines C-Programms ist das
+  Auflösen der sogenannten Präprozessor-Direktiven und -Macros.
+  \begin{lstlisting}
+    #include <stdio.h>
+  \end{lstlisting}
+  \vspace{-\medskipamount}
+  bewirkt, daß aus Sicht des Compilers anstelle der Zeile
+  der Inhalt der Datei \file{stdio.h} im C-Quelltext erscheint.
+  Dies ist zunächst unabhängig von Bibliotheken und auch nicht auf die Programmiersprache C beschränkt.
+
+  Beispiel:
+  Die Datei \gitfile{hp}{script}{maerchen.c} enthält:
+  \begin{lstlisting}[language={}]
+    Vor langer, langer Zeit
+    gab es einmal
+    #include "hexe.h"
+    Die lebte in einem Wald.
+  \end{lstlisting}
+  Die Datei \gitfile{hp}{script}{hexe.h} enthält:
+  \begin{lstlisting}[language={}]
+    eine kleine Hexe.
+  \end{lstlisting}
+  Der Aufruf
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -E -P maerchen.c¿
+  \end{lstlisting}
+  produziert die Ausgabe
+  \begin{lstlisting}[style=terminal]
+    Vor langer, langer Zeit
+    gab es einmal
+    eine kleine Hexe.
+    Die lebte in einem Wald.
+  \end{lstlisting}
+  Mit der Option \lstinline[style=cmd]{-E} weisen wir \lstinline[style=cmd]{gcc} an,
+  nicht zu compilieren, sondern nur den Präprozessor aufzurufen.
+  Die Option \lstinline[style=cmd]{-P} unterdrückt Herkunftsangaben,
+  die normalerweise vom Compiler verwendet werden,
+  um Fehlermeldungen den richtigen Zeilen in den richtigen Dateien
+  zuordnen zu können. Ohne das \lstinline[style=cmd]{-P} lautet die Ausgabe:
+  \begin{lstlisting}[style=terminal]
+    # 1 "maerchen.c"
+    # 1 "<built-in>"
+    # 1 "<command-line>"
+    # 1 "maerchen.c"
+    Vor langer, langer Zeit
+    gab es einmal
+    # 1 "hexe.h" 1
+    eine kleine Hexe.
+    # 3 "maerchen.c" 2
+    Die lebte in einem Wald.
+  \end{lstlisting}
+
+  Nichts anderes geschieht, wenn man das klassische \file{hello.c}
+  (Datei: \gitfile{hp}{script}{hello-1.c} compiliert:
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    int main (void)
+    {
+      printf ("Hello, world!\n");
+      return 0;
+    }
+  \end{lstlisting}
+  Die Datei \file{stdio.h} ist wesentlich länger als \gitfile{hp}{script}{hexe.txt} in dem o.\,a.\
+  Beispiel, und sie ruft weitere Include-Dateien auf,
+  so daß wir insgesamt auf über 800 Zeilen Quelltext kommen.
+
+  Die spitzen Klammern anstelle der Anführungszeichen bedeuten,
+  daß es sich um eine \newterm{Standard-Include-Datei\/} handelt,
+  die nur in den Standard-Include-Verzeichnissen gesucht werden soll,
+  nicht jedoch im aktuellen Verzeichnis.
+
+  \subsection{Bibliotheken einbinden}
+
+  Tatsächlich ist von den über 800 Zeilen aus \file{stdio.h} nur eine
+  einzige relevant, nämlich:
+  \begin{lstlisting}
+    extern int printf (__const char *__restrict __format, ...);
+  \end{lstlisting}
+  Dies ist die Deklaration einer Funktion, die sich von einer
+  "`normalen"' Funktionsdefinition nur wie folgt unterscheidet:
+  \begin{itemize}
+    \item
+      Die Parameter \lstinline{__const char *__restrict __format, ...}
+      heißen etwas ungewöhnlich.
+    \item
+      Der Funktionskörper \lstinline|{ ... }| fehlt. Stattdessen folgt auf die
+      Kopfzeile direkt ein Semikolon \lstinline{;}.
+    \item
+      Der Deklaration ist das Schlüsselwort \lstinline{extern} vorangestellt.
+  \end{itemize}
+  Dies bedeutet für den Compiler:
+  "`Es gibt diese Funktion und sie sieht aus, wie beschrieben.
+  Benutze sie einfach, und kümmere dich nicht darum, wer die Funktion schreibt."'
+
+  \begin{experts}
+    Wenn wir tatsächlich nur \lstinline{printf()} benötigen,
+    können wir also die Standard-Datei \file{stdio.h} durch eine eigene ersetzen,
+    die nur die o.\,a.\ Zeile \lstinline{extern int printf (...)} enthält.
+    (Dies ist in der Praxis natürlich keine gute Idee, weil nur derjenige, der die
+    Funktion \lstinline{printf()} geschrieben hat, den korrekten Aufruf kennt.
+    In der Praxis sollten wir immer diejenige Include-Datei benutzen,
+    die gemeinsam mit der tatsächlichen Funktion ausgeliefert wurde.)
+  \end{experts}
+
+  \breath
+
+  Der Präprozessor kann nicht nur \lstinline{#include}-Direktiven auflösen.
+  Mit \lstinline{#define} kann man sog.\ \newterm{Makros\/} definieren,
+  die bei Benutzung durch einen Text ersetzt werden.
+  Auf diese Weise kann man \newterm{Konstante\/} definieren.
+
+  Beispiel: \gitfile{hp}{script}{higher-math-1.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    #define VIER 4
+
+    int main (void)
+    {
+      printf ("2 + 2 = %d\n", VIER);
+      return 0;
+    }
+  \end{lstlisting}
+
+  Genau wie bei \lstinline{#include} nimmt der Präprozessor auch bei \lstinline{#define}
+  eine rein textuelle Ersetzung vor, ohne sich um den Sinn des Ersetzten zu kümmern.
+
+  Beispiel: \gitfile{hp}{script}{higher-math-2.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    #define wuppdich printf
+    #define holla main
+    #define pruzzel return
+    #define VIER 4
+
+    int holla (void)
+    {
+      wuppdich ("2 + 2 = %d\n", VIER);
+      pruzzel 0;
+    }
+  \end{lstlisting}
+
+  Dies kann zu Problemen führen, sobald Berechnungen ins Spiel kommen.
+
+  Beispiel: \gitfile{hp}{script}{higher-math-3.c}
+  \begin{lstlisting}
+    #include <stdio.h>
+
+    #define VIER 2 + 2
+
+    int main (void)
+    {
+      printf ("2 + 3 * 4 = %d\n", 2 + 3 * VIER);
+      return 0;
+    }
+  \end{lstlisting}
+  Hier z.\,B.\ sieht man mit \lstinline[style=cmd]{gcc -E rechnen.c},
+  daß die Ersetzung des Makros \lstinline{VIER} wie folgt lautet:
+  \begin{lstlisting}
+      printf ("2 + 3 * 4 = %d\n", 2 + 3 * 2 + 2);
+  \end{lstlisting}
+  Der C-Compiler wendet die Regel "`Punktrechnung geht vor Strichrechnung"' an
+  und erfährt überhaupt nicht, daß das \lstinline{2 + 2} aus einem Makro enstanden ist.
+
+  Um derartige Effekte zu vermeiden, setzt man arithmetische
+  Operationen innerhalb von Makros in Klammern.
+
+  Beispiel: \gitfile{hp}{script}{higher-math-4.c}
+  \begin{lstlisting}
+    #define VIER (2 + 2)
+  \end{lstlisting}
+
+  (Es ist in den meisten Situationen üblich, Makros in \lstinline{GROSSBUCHSTABEN} zu benennen,
+  um darauf hinzuweisen, daß es sich eben um einen Makro handelt.)
+
+  Achtung: Hinter Makro-Deklaration kommt üblicherweise \emph{kein\/} Semikolon.
+
+  \begin{experts}
+    Wenn man ein Semikolon setzt, gehört dies mit zum Ersetzungstext des Makros.
+    Dies ist grundsätzlich zulässig, führt aber zu sehr seltsamen C-Quelltexten.
+    -- siehe z.\,B.\ \gitfile{hp}{script}{higher-math-5.c}.
+  \end{experts}
+
+  \breath
+
+  Das nächste Beispiel illustriert, wie man Bibliotheken schreibt und verwendet.
+  
+  Es besteht aus drei Quelltexten:
+
+  \gitfile{hp}{script}{philosophy.c}:
+  \begin{lstlisting}
+    #include <stdio.h>
+    #include "answer.h"
+
+    int main (void)
+    {
+      printf ("The answer is %d.\n", answer ());
+      return 0;
+    }
+  \end{lstlisting}
+ 
+  \goodbreak
+  \gitfile{hp}{script}{answer.c}:
+  \begin{lstlisting}
+    int answer (void)
+    {
+      return 42;
+    }
+  \end{lstlisting}
+ 
+  \goodbreak
+  \gitfile{hp}{script}{answer.h}:
+  \begin{lstlisting}
+    extern int answer (void);
+  \end{lstlisting}
+
+  Das Programm \gitfile{hp}{script}{philosophy.c} verwendet eine Funktion \lstinline{answer()}, die
+  in der Datei \gitfile{hp}{script}{answer.h} extern deklariert ist.
+
+  Der "`normale"' Aufruf
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall -O philosophy.c -o philosophy¿
+  \end{lstlisting}
+  liefert die Fehlermeldung:
+  \begin{lstlisting}[style=terminal]
+    /tmp/ccr4Njg7.o: In function `main':
+    philosophy.c:(.text+0xa): undefined reference to `answer'
+    collect2: ld returned 1 exit status
+  \end{lstlisting}
+  Diese stammt nicht vom Compiler, sondern vom \newterm{Linker}.
+  Das Programm ist syntaktisch korrekt und wird auch korrekt in eine Binärdatei umgewandelt
+  (hier: \file{/tmp/ccr4Njg7.o}).
+  Erst beim Zusammenbau ("`Linken"') der ausführbaren Datei (\file{philosophy})
+  tritt ein Fehler auf.
+
+  Tatsächlich wird die Funktion \lstinline{answer()}
+  nicht innerhalb von \gitfile{hp}{script}{philosophy.c}, sondern in einer separaten Datei \gitfile{hp}{script}{answer.c},
+  einer sog.\ \newterm{Bibliothek\/} definiert.
+  Es ist möglich (und üblich), Bibliotheken separat vom Hauptprogramm zu compilieren.
+  Dadurch spart man sich das Neucompilieren,
+  wenn im Hauptprogramm etwas geändert wurde, nicht jedoch in der Bibliothek.
+
+  Mit der Option \lstinline[style=cmd]{-c} weisen wir \lstinline[style=cmd]{gcc} an,
+  nur zu compilieren, jedoch nicht zu linken. Die Aufrufe
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall -O -c philosophy.c¿
+    $ ¡gcc -Wall -O -c answer.c¿
+  \end{lstlisting}
+  produzieren die Binärdateien \file{philosophy.o} und \file{answer.o},
+  die sogenannten \newterm{Objekt-Dateien} (daher die Endung \file{.o} oder \file{.obj}).
+
+  Mit dem Aufruf
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc philosophy.o answer.o -o philosophy¿
+  \end{lstlisting}
+  bauen wir die beiden bereits compilierten Objekt-Dateien zu einer
+  ausführbaren Datei \file{philosophy} (hier ohne Endung) zusammen.
+
+  Es ist auch möglich, im Compiler-Aufruf gleich beide C-Quelltexte zu
+  übergeben:
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall -O philosophy.c answer.c -o philosophy¿
+  \end{lstlisting}
+  In diesem Fall ruft \lstinline[style=cmd]{gcc} zweimal den Compiler auf
+  (für jede C-Datei einmal) und anschließend den Linker.
+
+  \subsection{Bibliotheken verwenden (Beispiel: OpenGL)}
+
+  Die \newterm{OpenGL\/}-Bibilothek dient dazu,
+  unter Verwendung von Hardware-Unterstützung dreidimensionale Grafik auszugeben.
+
+  Die einfachste Art und Weise, OpenGL in seinen Programmen einzusetzen,
+  erfolgt über eine weitere Bibliothek, das \newterm{OpenGL Utility Toolkit (GLUT)}.
+
+  Die Verwendung von OpenGL und GLUT erfolgt durch Einbinden der Include-Dateien
+  \begin{lstlisting}
+    #include <GL/gl.h>
+    #include <GL/glu.h>
+    #include <GL/glut.h>
+  \end{lstlisting}
+  und die Übergabe der Bibliotheken \lstinline[style=cmd]{-lGL -lGLU -lglut} im Compiler-Aufruf: 
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall -O cube.c -lGL -lGLU -lglut -o cube¿
+  \end{lstlisting}
+  (Dies ist der Aufruf unter Unix.
+  Unter Microsoft Windows ist der Aufruf etwas anders
+  und hängt von der verwendeten Version der GLUT-Bibliothek ab.
+  Für Details siehe die Dokumentation der GLUT-Bibliothek
+  sowie die Datei \gitfile{hp}{20161031}{egal.txt}.)
+
+  Die Bibliothek stellt uns fertig geschriebene Programmfragmente zur Verfügung, insbesondere:
+  \begin{itemize}
+    \item
+      Funktionen: z.\,B.\ \lstinline{glutInit (&argc, argv);}
+    \item
+      Konstante: z.\,B.\ \lstinline{GLUT_RGBA}
+    \item
+      Datentypen: z.\,B.\ \lstinline{GLfloat}
+  \end{itemize}
+
+  Manche OpenGL-Funktionen erwarten als Parameter ein Array.
+  Dies gilt z.\,B.\ beim Setzen von Farben oder beim Positionieren einer Lichtquelle:
+  \begin{lstlisting}
+    GLfloat light0_position[] = {1.0, 2.0, -2.0, 1.0};
+    glLightfv (GL_LIGHT0, GL_POSITION, light0_position);
+  \end{lstlisting}
+
+  Ein weiteres wichtiges allgemeines Konzept,
+  das in OpenGL eine Rolle spielt, ist die Übergabe einer Funktion an die Bibliothek.
+  Man nennt dies das \newterm{Installieren einer Callback-Funktion}.
+  \begin{lstlisting}
+    void draw (void)
+    { ... }
+
+    glutDisplayFunc (draw);
+  \end{lstlisting}
+  Wir übergeben die -- von uns geschriebene -- Funktion \lstinline{draw()}
+  an die OpenGL-Funktion \lstinline{glutDisplayFunc()}.
+  Dies bewirkt, daß OpenGL immer dann, wenn etwas gezeichnet werden soll, \lstinline{draw()} aufruft.
+  Innerhalb von \lstinline{draw()} können wir also unsere Zeichenbefehle unterbringen.
+
+  \breath
+
+  Die OpenGL-Bibliothek ist sehr umfangreich
+  und kann im Rahmen dieser Vorlesung nicht im Detail behandelt werden.
+  Um trotzdem damit arbeiten zu können,
+  lagern wir bestimmte Teile -- Initialisierung und das Setzen von Farben --
+  in eine eigene Bibliothek \file{opengl-magic} aus, die wir als "`Black Box"' verwenden.
+  Der Compiler-Aufruf lautet dann:
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall -O cube.c -lGL -lGLU -lglut opengl-magic.c -o cube¿
+  \end{lstlisting}
+  (Wer in eigenen Projekten mehr mit OpenGL machen möchte,
+  ist herzlich eingeladen, die Funktionsweise von \file{opengl-magic} zu studieren.)
+
+  \begin{itemize}
+    \item
+      Das Beispielprogramm \gitfile{hp}{script}{cube-1.c} illustriert,
+      wie man grundsätzlich überhaupt ein geometrisches Objekt zeichnet.
+      In diesem Fall handelt es sich um einen Würfel der Kantenlänge \lstinline{0.5},
+      von dem wir nur die Vorderfläche sehen, also ein Quadrat.
+      \begin{lstlisting}[gobble=8]
+        #include <GL/gl.h>
+        #include <GL/glu.h>
+        #include <GL/glut.h>
+        #include "opengl-magic.h"
+
+        void draw (void)
+        {
+          glClear (GL_COLOR_BUFFER_BIT + GL_DEPTH_BUFFER_BIT);
+          set_material_color (1.0, 0.7, 0.0);
+          glutSolidCube (0.75);
+          glFlush ();
+          glutSwapBuffers ();
+        }
+
+        int main (int argc, char **argv)
+        {
+          init_opengl (&argc, argv, "Cube");
+          glutDisplayFunc (draw);
+          glutMainLoop ();
+          return 0;
+        }
+      \end{lstlisting}
+      \begin{picture}(0,0)
+        \color{red}
+        \put(12.5,6.4){\vector(-1,0){1}}
+        \put(12.6,6.4){\makebox(0,0)[l]{Bildschirm löschen}}
+        \put(7.5,5.95){\vector(-1,0){1}}
+        \put(7.6,5.95){\makebox(0,0)[l]{Rotanteil 100\,\%, Grünanteil 70\,\%, Blauanteil 0\,\%}}
+        \put(5.5,5.5){\vector(-1,0){1}}
+        \put(5.6,5.5){\makebox(0,0)[l]{Würfel zeichnen}}
+        \put(4.0,5.05){\vector(-1,0){1}}
+        \put(4.1,5.05){\makebox(0,0)[l]{Zeichnung "`abschicken"'}}
+        \put(5.2,4.6){\vector(-1,0){1}}
+        \put(5.3,4.6){\makebox(0,0)[l]{fertige Zeichnung zeigen; neues "`Zeichenpapier"' bereitlegen}}
+        \put(6.0,2.15){\vector(-1,0){1}}
+        \put(6.1,2.15){\makebox(0,0)[l]{Callback-Funktion installieren (s.\,o.)}}
+        \put(5.0,1.7){\vector(-1,0){1}}
+        \put(5.1,1.7){\makebox(0,0)[l]{Endlosschleife: Ab jetzt werden nur noch Callbacks aufgerufen.}}
+      \end{picture}
+    \item
+      In \gitfile{hp}{script}{cube-2.c} kommt eine Drehung um \lstinline{-30} Grad
+      um eine schräge Achse \lstinline{(0.5, 1.0, 0.0)} hinzu.
+      Der Würfel ist jetzt als solcher zu erkennen.
+
+      Jeder Aufruf von \lstinline{glRotatef()} bewirkt,
+      daß alle nachfolgenden Zeichenoperationen gedreht ausgeführt werden.
+
+    \item
+      In \gitfile{hp}{script}{cube-3.c} kommt als zusätzliches Konzept eine weitere Callback-Funktion hinzu,
+      nämlich ein \newterm{Timer-Handler}.
+      Durch den \lstinline{glutTimerFunc()}-Aufruf veranlassen wir OpenGL,
+      die von uns geschriebene Funktion \lstinline{timer_handler()} aufzurufen,
+      sobald \lstinline{50} Millisekunden vergangen sind.
+
+      Innerhalb von \lstinline{timer_handler()} rufen wir \lstinline{glutTimerFunc()} erneut auf,
+      was insgesamt zur Folge hat, daß \lstinline{timer_handler()} periodisch alle 50 Millisekunden
+      aufgerufen wird.
+
+      Die "`Nutzlast"' der Funktion \lstinline{timer_handler()} besteht darin,
+      eine Variable \lstinline{t} um den Wert \lstinline{0.05} zu erhöhen
+      und anschließend mittels \lstinline{glutPostRedisplay()} ein Neuzeichnen anzufordern.
+      Dies alles bewirkt, daß die Variable \lstinline{t} die aktuelle Zeit seit Programmbeginn
+      in Sekunden enthält und daß \lstinline{draw()} zwanzigmal pro Sekunde aufgerufen wird.
+
+%    \item
+%      Weil das Bild während des Neuzeichnens die ganze Zeit zu sehen ist,
+%      flackert in \gitfile{hp}{script}{cube-3.c} der Bildschirm.
+%      Dies wird in \gitfile{hp}{script}{cube-3a.c} dadurch behoben,
+%      daß die Zeichnung zunächst in einem unsichtbaren Pufferspeicher aufgebaut wird.
+%      Erst die fertige Zeichnung wird mit dem Funktionsaufruf \lstinline{swapBuffers()} sichtbar gemacht.
+%
+%      Damit dies möglich ist, muß beim Initialisieren ein doppelter Puffer angefordert werden.
+%      Zu diesem Zweck ersetzen wir die Bibliothek \gitfile{hp}{script}{opengl-magic.c}
+%      durch \gitfile{hp}{script}{opengl-magic-double.c}.
+%
+%      Der Compiler-Aufruf lautet dann:
+%      \begin{lstlisting}[style=terminal,gobble=8]
+%        $ ¡gcc -Wall -O cube.c -lGL -lGLU -lglut opengl-magic-double.c -o cube¿
+%      \end{lstlisting}
+%
+%      Unabhängig davon heißt die Include-Datei weiterhin \gitfile{hp}{script}{opengl-magic.h}.
+%      Dies illustriert, daß der Include-Mechanismus des Präprozessors
+%      und der Zusammenbau-Mecha"-nismus des Linkers tatsächlich voneinander unabhängig sind.
+%
+%      \begin{experts}
+%        (Durch das Austauschen von Bibliotheken, insbesondere bei dynamischen Bibliotheken
+%        (Endung \file{.so} unter Unix bzw.\ \file{.dll} unter Microsoft Windows)
+%        ist es möglich, das Verhalten bereits fertiger Programme zu beeinflussen,
+%        ohne das Programm neu compilieren zu müssen.
+%        Dies kann zu Testzwecken geschehen, zur Erweiterung des Funktionsumfangs
+%        oder auch zum Einschleusen von Schadfunktionen.)
+%      \end{experts}
+
+    \item
+      In \gitfile{hp}{script}{cube-3.c} dreht sich der Würfel zunächst langsam, dann immer schneller.
+      Dies liegt daran, daß sich jedes \lstinline{glRotatef()}
+      auf alle nachfolgenden Zeichenbefehle auswirkt,
+      so daß sich sämtliche \lstinline{glRotatef()} aufaddieren.
+
+      Eine Möglichkeit, stattdessen eine gleichmäßige Drehung zu erreichen,
+      besteht darin, den Wirkungsbereich des \lstinline{glRotatef()} zu begrenzen.
+      Dies geschieht durch Einschließen der Rotation in das Befehlspaar \lstinline{glPushMatrix()}
+      und \lstinline{glPopMatrix()}:
+      Durch \lstinline{glPopMatrix()} wird das System wieder in denjenigen Zustand versetzt,
+      in dem es sich vor dem Aufruf von \lstinline{glPushMatrix()} befand.
+
+      Dies ist in \gitfile{hp}{script}{cube-4.c} (langsame Drehung) und \gitfile{hp}{script}{cube-5.c} (schnelle Drehung) umgesetzt.
+
+  \end{itemize}
+
+  \subsubsection*{Aufgabe}
+
+  Für welche elementaren geometrischen Körper
+  stellt die GLUT-Bibliothek Zeichenroutinen zur Verfügung?
+
+  \subsubsection*{Lösung}
+
+  Ein Blick in die Include-Datei \file{glut.h}
+  verweist uns auf eine andere Include-Datei:
+  \begin{lstlisting}
+    #include "freeglut_std.h"
+  \end{lstlisting}
+  Wenn wir darin nach dem Wort \lstinline{glutSolidCube} suchen,
+  finden wir die Funktionen:
+  \begin{lstlisting}
+    glutSolidCube (GLdouble size);
+    glutSolidSphere (GLdouble radius, GLint slices, GLint stacks);
+    glutSolidCone (GLdouble base, GLdouble height, GLint slices, GLint stacks);
+    glutSolidTorus (GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings);
+    glutSolidDodecahedron (void);
+    glutSolidOctahedron (void);
+    glutSolidTetrahedron (void);
+    glutSolidIcosahedron (void);
+    glutSolidTeapot (GLdouble size);
+  \end{lstlisting}
+  Zu jeder \lstinline{glutSolid}-Funktion gibt es auch eine \lstinline{glutWire}-Funktion,
+  beispielsweise \lstinline{glutWireCube()} als Gegenstück zu \lstinline{glutSolidCube()}.
+
+  In demselben Verzeichnis finden wir auch eine Datei \file{freeglut\_ext.h}
+  mit weiteren Funktionen dieses Typs:
+  \begin{lstlisting}
+    glutSolidRhombicDodecahedron (void);
+    glutSolidSierpinskiSponge (int num_levels, GLdouble offset[3], GLdouble scale);
+    glutSolidCylinder (GLdouble radius, GLdouble height, GLint slices, GLint stacks);
+  \end{lstlisting}
+
+  Die GLUT-Bibliothek kennt insbesondere standardmäßig eine Funktion zum Zeichnen einer Teekanne
+  und als Erweiterung eine Funktion zum Zeichnen eines Sierpinski-Schwamms.
+
+  \breath
+
+  Die weiteren OpenGL-Beispielprogramme illustrieren den Umgang mit Transformationen.
+  \begin{itemize}
+    \item
+      Die Beispielprogramme \gitfile{hp}{script}{cube-5.c} und \gitfile{hp}{script}{cube-6.c}
+      illustrieren eine weitere Transformation der gezeichneten Objekte,
+      nämlich die Translation (Verschiebung).
+
+      Jeder Transformationsbefehl wirkt sich jeweils
+      auf die \emph{danach\/} erfolgenden Zeichenbefehle aus.
+      Um sich zu veranschaulichen, welche Transformationen auf ein gezeichnetes Objekt wirken
+      (hier z.\,B.\ auf \lstinline{glutSolidCube()}),
+      muß man die Transformationen in der Reihenfolge \emph{von unten nach oben\/} ausführen.
+
+    \item
+      Das Beispielprogramm \gitfile{hp}{script}{orbit-1.c} 
+      verwendet weitere Transformationen und geometrische Objekte,
+      um die Umlaufbahn des Mondes um die Erde zu illustrieren.
+
+      Darüberhinaus versieht es die gezeichneten Objekte "`Mond"' und "`Erde"' mit realistischen Texturen (NASA-Fotos).
+      Die hierfür notwendigen doch eher komplizierten Funktionsaufrufe
+      wurden wiederum in eine Bibliothek (\file{textured-spheres}) ausgelagert.
+      
+  \end{itemize}
+
+\iffalse
+
+  \subsection{Standard-Pfade}
+
+  Wenn eine Bibliothek regelmäßig von vielen Programmierern benutzt
+  wird, wird sie üblicherweise an einem Standard-Ort abgelegt, z.\,B.\ in
+  dem Verzeichnis \file{/usr/lib}.
+
+  \lstinline[style=cmd]{gcc} erwartet, daß die Namen von Bibliotheksdateien mit \file{lib}
+  beginnen und die Endung \file{.a} oder \file{.so} haben. (\file{.a} steht für
+  "`Archiv"', da eine \file{.a}-Datei mehrere \file{.o}-Dateien enthält.
+  \file{.so} steht für "`shared object"' und bezeichnet eine Bibliothek, die
+  erst zur Laufzeit eingebunden wird und von mehreren Programmen
+  gleichzeitig benutzt werden kann. Andere übliche Bezeichnungen
+  sind \file{.lib} anstelle von \file{.a} und \file{.dll} anstelle von \file{.so}.)
+
+  Mit der Option \lstinline[style=cmd]{-lfoo} teilen wir \lstinline[style=cmd]{gcc} mit, daß wir eine Datei
+  \file{libfoo.a} aus einem der Standardverzeichnisse verwenden möchten.
+  ("`foo"' ist eine metasyntaktische Variable und steht für ein
+  beliebiges Wort.) Auch der Aufruf \lstinline[style=cmd]{-lm} zum Einbinden der
+  Mathematik-Bibliothek ist nichts anderes. Tatsächlich gibt es
+  eine Datei \file{libm.a} im Verzeichnis \file{/usr/lib}.
+  \begin{verbatim}
+    gcc test.c -lm -o test\end{verbatim}
+  ist somit dasselbe wie
+  \begin{verbatim}
+    gcc test.c /usr/lib/libm.a -o test\end{verbatim}
+
+  Mit der Option \lstinline[style=cmd]{-L /foo/bar} können wir ein Verzeichnis \file{/foo/bar}
+  dem Suchpfad hinzufügen. ("`bar"' ist eine weitere metasyntaktische
+  Variable.)
+  \begin{verbatim}
+    gcc test.c -L /home/joe/my_libs -lmy -o test\end{verbatim}
+  compiliert \file{test.c} und linkt es mit einer Bibliothek \file{libmy.a},
+  nach der nicht nur in den Standardverzeichnissen (\file{/usr/lib},
+  \file{/usr/local/lib} u.\,a.), sondern zusätzlich im Verzeichnis
+  \file{/home/joe/my\_libs} gesucht wird.
+
+  Auf gleiche Weise kann man mit \lstinline[style=cmd]{-I /foo/bar} Verzeichnisse für
+  Include-Dateien (s.\,o.)\ dem Standardsuchpfad hinzufügen.
+
+\fi
+
+  \subsection{Projekt organisieren: make}
+
+  In größeren Projekten ruft man den Compiler (und Präprozessor und
+  Linker) nicht "`von Hand"' auf, sondern überläßt dies einem weiteren
+  Programm namens \lstinline[style=cmd]{make}.
+
+  \lstinline[style=cmd]{make} sucht im aktuellen Verzeichnis nach einer Datei \file{Makefile}
+  (ohne Dateiendung). (Normalerweise gibt es nur ein Makefile pro
+  Verzeichnis. Falls es doch mehrere gibt, kann man die Datei, z.\,B.\
+  \file{Makefile.1}, mit \lstinline[style=cmd]{-f}
+  auch explizit angeben: \lstinline[style=cmd]{make -f Makefile.1}.)
+
+  \subsubsection{make-Regeln}
+
+  Ein Makefile enthält sog.\ Regeln, um Ziele zu erzeugen.
+  Eine Regel beginnt mit der Angabe des Ziels, gefolgt von einem
+  Doppelpunkt und den Dateien (oder anderen Zielen), von denen es
+  abhängt. Darunter steht, mit einem Tabulator-Zeichen eingerückt, der
+  Programmaufruf, der nötig ist, um das Ziel zu bauen.
+  \begin{lstlisting}[language=make]
+    philosophy.o: philosophy.c answer.h
+            gcc -c philosophy.c -o philosophy.o
+  \end{lstlisting}
+  Achtung: Ein Tabulator-Zeichen läßt sich optisch häufig nicht von
+  mehreren Leerzeichen unterscheiden. \lstinline[style=cmd]{make}
+  akzeptiert jedoch nur das Tabulator-Zeichen.
+
+  Die o.\,a.\ Regel bedeutet, daß jedesmal, wenn sich \gitfile{hp}{script}{philosophy.c} oder
+  \gitfile{hp}{script}{answer.h} geändert hat, \lstinline[style=cmd]{make}
+  das Programm \lstinline[style=cmd]{gcc} in der beschriebenen Weise aufrufen soll.
+
+  Durch die Kombination mehrerer Regeln lernt \lstinline[style=cmd]{make},
+  welche Befehle in welcher Reihenfolge aufgerufen werden müssen,
+  je nachdem, welche Dateien geändert wurden.
+
+  \breath
+
+  Beispiel: \file{Makefile.orbit-x1}
+
+  Der Aufruf
+  \begin{lstlisting}[style=terminal]
+    $ ¡make -f Makefile.orbit-x1¿
+  \end{lstlisting}
+  bewirkt beim ersten Mal:
+  \begin{lstlisting}[style=terminal]
+    gcc -Wall -O orbit-x1.c opengl-magic-double.c textured-spheres.c \
+              -lGL -lGLU -lglut -o orbit-x1
+  \end{lstlisting}
+  Beim zweiten Aufruf stellt \lstinline[style=cmd]{make} fest, daß sich keine der Dateien
+  auf der rechten Seite der Regeln (rechts vom Doppelpunkt) geändert
+  hat und ruft keine Programme auf:
+  \begin{lstlisting}[style=terminal]
+    make: »orbit-x1« ist bereits aktualisiert.
+  \end{lstlisting}
+
+  \subsubsection{make-Macros}
+
+  Um wiederkehrende Dinge (typischerweise: Listen von Dateinamen oder
+  Compiler-Optionen) nicht mehrfach eingeben zu müssen, kennt \lstinline[style=cmd]{make}
+  sog.\ Macros:
+  \begin{lstlisting}[language=make]
+    PHILOSOPHY_SOURCES = philosophy.c answer.h
+  \end{lstlisting}
+  Um den Macro zu expandieren, setzt man ihn in runde Klammern mit
+  einem vorangestellten Dollarzeichen. Die Regel
+  \begin{lstlisting}[language=make]
+    philosophy.o: $(PHILOSOPHY_SOURCES)
+            gcc -c philosophy.c -o philosophy.o
+  \end{lstlisting}
+  ist also nur eine andere Schreibweise für:
+  \begin{lstlisting}[language=make]
+    philosophy.o: philosophy.c answer.h
+            gcc -c philosophy.c -o philosophy.o
+  \end{lstlisting}
+
+  \breath
+
+  Beispiel: \file{Makefile.blink}
+
+  Die Beispielprogramme \file{blink-\lstinline{*}.c} sind dafür gedacht,
+  auf einem Mikrocontroller zu laufen.
+  Der Compiler-Aufruf erfordert zusätzliche Optionen
+  (z.\,B.\ \lstinline[style=cmd]{-Os -mmcu=atmega32}),
+  und es müssen zusätzliche Entwicklungswerkzeuge
+  (z.\,B.\ \lstinline[style=cmd]{avr-objcopy}) aufgerufen werden --
+  ebenfalls mit den richtigen Optionen.
+  Der Prozeß des Zusammenbauens wird durch ein Makefile \file{Makefile.blink} verwaltet.
+
+  \file{Makefile.blink} speichert den Namen des Quelltextes
+  (ohne die Endung \file{.c}) in einem Macro.
+  Durch Ändern allein dieses Macros ist es daher möglich,
+  das Makefile für ein anderes Projekt einzusetzen.
+  
+  Zusätzlich führt \file{Makefile.blink} eine neue Regel \lstinline{clean} ein.
+  Diese bewirkt üblicherweise, daß alle automatisch erzeugten Dateien
+  gelöscht werden:
+  \begin{lstlisting}[language=make]
+    clean:
+            rm -f $(TARGET).elf $(TARGET).hex
+  \end{lstlisting}
+  Rechts vom Doppelpunkt nach \lstinline[language=make]{clean} befinden sich keine
+  Abhängigkeitsdateien. Dies hat zur Folge, daß die Aktion
+  (\lstinline{rm -f ...}) bei \lstinline[style=cmd]{make clean}
+  grundsätzlich immer ausgeführt wird, also nicht nur, wenn sich irgendeine Datei geändert hat.
+
+  \begin{experts}
+    Ebenfalls üblich ist eine weitere Regel \lstinline[language=make]{install},
+    die bewirkt, daß die Zieldateien
+    (bei einem Programm typischerweise eine ausführbare Datei,
+    bei einer Bibliothek typischerweise \file{.a}-, \file{.so}- sowie \file{.h}-Dateien)
+    an ihren endgültigen Bestimmungsort kopiert werden.
+  \end{experts}
+
+  \subsubsection{Fazit: 3 Sprachen}
+
+  Um in C programmieren zu können, muß man also tatsächlich drei
+  Sprachen lernen:
+  \begin{itemize}
+    \item C selbst,
+    \item die Präprozessor-Sprache
+    \item und die \lstinline[style=cmd]{make}-Sprache.
+  \end{itemize}
+  Durch Entwicklungsumgebungen wie z.\,B.\ \file{Eclipse} läßt sich der
+  \lstinline[style=cmd]{make}-Anteil teilweise automatisieren. (\file{Eclipse} z.\,B.\ schreibt ein
+  Makefile; andere Umgebungen übernehmen die Funktionalität von \lstinline[style=cmd]{make}
+  selbst.) Auch dort muß man jedoch die zu einem Projekt gehörenden
+  Dateien verwalten.
+
+  Wenn sich dann eine Datei nicht an dem Ort befindet,
+  erhält man u.\,U.\ wenig aussagekräftige Fehlermeldungen, z.\,B.: 
+  \begin{lstlisting}[style=terminal]
+    make: *** No rule to make target `MeinProgramm.elf', needed by `elf'.  Stop.
+  \end{lstlisting}
+  Wenn man dann um die Zusammenhänge weiß ("`Welche Bibliotheken verwendet mein
+  Programm? Wo befinden sich diese? Und wie erfährt der Linker davon?"'),
+  kann man das Problem systematisch angehen und ist nicht auf Herumraten
+  angewiesen.
+
+  \section{Hardwarenahe Programmierung}
+
+  \subsection{Bit-Operationen}
+
+  \setlength{\unitlength}{12pt}
+
+  \subsubsection{Zahlensysteme}
+
+  \subsubsection*{Dezimalsystem}
+  \begin{itemize}
+    \item
+      Basis: 10
+    \item
+      Gültige Ziffern: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+  \end{itemize}
+  \begin{verbatim}
+    137                               137
+                                    +  42
+                                     ----
+                                      179
+  \end{verbatim}
+  \begin{picture}(0,0)(0,-0.25)
+    \color{red}
+    \put(5.0,4.25){\vector(-1,1){1.41}}
+    \put(5.5,4){\mbox{Einer: $7 \cdot 10^0$}}
+    \put(5.5,3.25){\vector(-1,1){2.41}}
+    \put(6.0,3){\mbox{Zehner: $3 \cdot 10^1$}}
+    \put(6.0,2.25){\vector(-1,1){3.41}}
+    \put(6.5,2){\mbox{Hunderter: $1 \cdot 10^2$}}
+    \put(2.5,0.5){\mbox{$137_{10} = 1 \cdot 10^2 + 3 \cdot 10^1 + 7 \cdot 10^0
+                                  = 100 + 30 + 7 = 137$}}
+  \end{picture}
+
+  \goodbreak
+  \subsubsection*{Hexadezimalsystem}
+  \begin{itemize}
+    \item
+      Basis: 16
+    \item
+      Gültige Ziffern: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
+  \end{itemize}
+  \begin{verbatim}
+    137                               A380
+                                    + B747
+                                     -----
+                                     15AC7
+  \end{verbatim}
+  \begin{picture}(0,0)(-0,-0.25)
+    \put(18.6,4.2){\mbox{\scriptsize\texttt{1}}}
+    \color{red}
+    \put(5.0,4.25){\vector(-1,1){1.41}}
+    \put(5.5,4){\mbox{$7 \cdot 16^0$}}
+    \put(5.5,3.25){\vector(-1,1){2.41}}
+    \put(6.0,3){\mbox{$3 \cdot 16^1$}}
+    \put(6.0,2.25){\vector(-1,1){3.41}}
+    \put(6.5,2){\mbox{$1 \cdot 16^2$}}
+    \put(2.5,0.5){\mbox{$137_{16} = 1 \cdot 16^2 + 3 \cdot 16^1 + 7 \cdot 16^0
+                                  = 256 + 48 + 7 = 311$}}
+  \end{picture}
+  \begin{itemize}
+    \item
+      Schreibweise in C: \quad \texttt{0x137}
+  \end{itemize}
+
+  \goodbreak
+  \subsubsection*{Oktalsystem}
+  \begin{itemize}
+    \item
+      Basis: 8
+    \item
+      Gültige Ziffern: 0, 1, 2, 3, 4, 5, 6, 7
+  \end{itemize}
+  \begin{verbatim}
+    137                               137
+                                    +  42
+                                     ----
+                                      201
+  \end{verbatim}
+  \begin{picture}(0,0)(0,-0.25)
+    \put(19.6,3.7){\mbox{\scriptsize\texttt{1}}}
+    \put(19.1,3.7){\mbox{\scriptsize\texttt{1}}}
+    \color{red}
+    \put(5.0,4.25){\vector(-1,1){1.41}}
+    \put(5.5,4){\mbox{$7 \cdot 8^0$}}
+    \put(5.5,3.25){\vector(-1,1){2.41}}
+    \put(6.0,3){\mbox{$3 \cdot 8^1$}}
+    \put(6.0,2.25){\vector(-1,1){3.41}}
+    \put(6.5,2){\mbox{$1 \cdot 8^2$}}
+    \put(2.5,0.5){\mbox{$137_8 = 1 \cdot 8^2 + 3 \cdot 8^1 + 7 \cdot 8^0
+                               = 64 + 24 + 7 = 95$}}
+    \put(2.5,-0.6){\mbox{$42_8 = 4 \cdot 8^1 + 2 \cdot 8^0
+                               = 32 + 2 = 34$}}
+    \put(2.5,-1.7){\mbox{$201_8 = 2 \cdot 8^2 + 0 \cdot 8^1 + 1 \cdot 8^0
+                               = 128 + 1 = 129$}}
+  \end{picture}
+  \vspace{0.75cm}
+  \begin{itemize}
+    \item
+      Schreibweise in C: \quad \texttt{0137}
+  \end{itemize}
+
+  \subsubsection*{Rechner für beliebige Zahlensysteme: GNU bc}
+  \begin{lstlisting}[style=terminal]
+    $ ¡bc
+    ibase=8
+    137¿
+    95
+    ¡obase=10
+    137 + 42¿
+    201
+  \end{lstlisting}
+  \begin{picture}(0,0)(0.5,1.2)
+    \color{red}
+    \put(8.0,7.25){\vector(-1,0){3}}
+    \put(8.5,7){\mbox{Eingabe zur Basis 8}}
+    \put(8.0,6.25){\vector(-1,0){4}}
+    \put(8.5,6){\mbox{Ausgabe zur Basis 10}}
+    \put(9.0,5.25){\vector(-1,0){2}}
+    \put(9.5,5){\mbox{Eingabe zur Basis 8 ($10_8 = 8$)}}
+    \put(8.0,3.25){\vector(-1,0){4}}
+    \put(8.5,3){\mbox{Ausgabe zur Basis 8}}
+  \end{picture}\vspace{-2ex}
+
+  \goodbreak
+  \subsubsection*{Binärsystem}
+  \begin{itemize}
+    \item
+      Basis: 2
+    \item
+      Gültige Ziffern: 0, 1
+  \end{itemize}
+  \begin{verbatim}
+    110                                110
+                                    + 1100
+                                     -----
+                                     10010
+  \end{verbatim}
+  \begin{picture}(0,0)(0,-0.25)
+    \put(19.1,3.8){\mbox{\scriptsize\texttt{1}}}
+    \put(18.6,3.8){\mbox{\scriptsize\texttt{1}}}
+    \color{red}
+    \put(5.0,4.25){\vector(-1,1){1.41}}
+    \put(5.5,4){\mbox{$0 \cdot 2^0$}}
+    \put(5.5,3.25){\vector(-1,1){2.41}}
+    \put(6.0,3){\mbox{$1 \cdot 2^1$}}
+    \put(6.0,2.25){\vector(-1,1){3.41}}
+    \put(6.5,2){\mbox{$1 \cdot 2^2$}}
+    \put(2.5,0.5){\mbox{$110_2 = 1 \cdot 2^2 + 1 \cdot 2^1 + 0 \cdot 2^0
+                                  = 4 + 2 + 0 = 6$}}
+  \end{picture}
+  \begin{itemize}
+    \item
+      Binär-Zahlen ermöglichen es, elektronisch zu rechnen \dots
+    \item
+      und mehrere "`Ja/Nein"' (Bits) zu einer einzigen Zahl zusammenzufassen.
+    \goodbreak
+    \item
+      \textbf{Oktal- und Hexadezimal-Zahlen lassen sich ziffernweise
+      in Binär-Zahlen umrechnen:}
+  \end{itemize}
+  \vspace*{-6mm}
+  \begin{verbatim}
+     000 0        0000 0  1000 8
+     001 1        0001 1  1001 9
+     010 2        0010 2  1010 A
+     011 3        0011 3  1011 B
+     100 4        0100 4  1100 C
+     101 5        0101 5  1101 D
+     110 6        0110 6  1110 E
+     111 7        0111 7  1111 F
+  \end{verbatim}
+  \vspace*{-1cm}
+  \begin{itemize}
+    \item[]
+      Beispiel: $1101011_2 = 153_8 = 6{\rm B}_{16}$
+    \item[]
+      Anwendungsbeispiel: Oktal-Schreibweise für Unix-Zugriffsrechte\\
+      \lstinline[style=terminal]|-rw-r-----| $= 0\,110\,100\,000_2 = 640_8$ \qquad \lstinline[style=terminal]|$ chmod 640 file.c|\\
+      \lstinline[style=terminal]|-rwxr-x---| $= 0\,111\,101\,000_2 = 750_8$ \qquad \lstinline[style=terminal]|$ chmod 750 subdir|
+  \end{itemize}
+
+  \goodbreak
+  \subsubsection*{IP-Adressen (IPv4)}
+  \begin{itemize}
+    \item
+      Basis: 256
+    \item
+      Gültige Ziffern: 0 bis 255, getrennt durch Punkte
+    \item
+      Kompakte Schreibweise für Binärzahlen mit 32 Ziffern (Bits)
+  \end{itemize}
+  \begin{verbatim}
+    192.168.0.1
+
+
+
+
+  \end{verbatim}
+  \begin{picture}(0,0)(0,-0.25)
+    \color{red}
+    \put(8.75,5.25){\vector(-1,1){1.41}}
+    \put(9.25,5){\mbox{$1 \cdot 256^0$}}
+    \put(8.75,4.25){\vector(-1,1){2.41}}
+    \put(9.25,4){\mbox{$0 \cdot 256^1$}}
+    \put(8.25,3.25){\vector(-1,1){3.41}}
+    \put(8.75,3){\mbox{$168 \cdot 256^2$}}
+    \put(7.5,2.25){\vector(-1,1){4.41}}
+    \put(8.0,2){\mbox{$192 \cdot 256^3$}}
+    \put(2.5,0.5){\mbox{$192.168.0.1_{256} = 11000000\,10101000\,00000000\,00000001_2$}}
+  \end{picture}
+  \vspace*{-0.5cm}
+
+  \goodbreak
+  \subsubsection{Bit-Operationen in C}
+  \begin{verbatim}
+      0110       0110       0110       0110                  0110
+    + 1100     | 1100    &  1100    ^  1100    ~  1100   >>     2
+     -----      -----      -----      -----      -----      -----
+     10010       1110       0100       1010       0011       0001
+  \end{verbatim}
+  \begin{picture}(0,0)(0,-0.25)
+    \color{red}
+    \put(2.5,1.0){\mbox{Addition}}
+    \put(8.5,1.0){\mbox{Oder}}
+    \put(14.0,1.0){\mbox{Und}}
+    \put(18.0,1.0){\mbox{Exklusiv-Oder}}
+    \put(24.5,1.0){\mbox{Negation}}
+    \put(29.0,1.0){\mbox{Bit-Verschiebung}}
+  \end{picture}
+
+  \begin{verbatim}
+      01101100            01101100            01101100
+    | 00000010          & 11110111          ^ 00010000
+     ---------           ---------           ---------
+      01101110            01100100            01111100
+  \end{verbatim}
+  \begin{picture}(0,0)(0,-0.25)
+    \color{red}
+    \put(2.5,1.0){\mbox{Bit gezielt setzen}}
+    \put(12.5,1.0){\mbox{Bit gezielt löschen}}
+    \put(22.5,1.0){\mbox{Bit gezielt umklappen}}
+  \end{picture}
+  \begin{itemize}
+    \item
+      Bits werden häufig von rechts und ab 0 numeriert (hier: 0 bis 7),\\
+      um die Maskenerzeugung mittels Schiebeoperatoren zu erleichtern.
+    \item
+      Die Bit-Operatoren (z.\,B.\ \lstinline|&| in C)
+      wirken jeweils auf alle Bits der Zahlen.
+      \hfill{\color{red}\lstinline|6 & 12 == 4|}\qquad\strut\\
+      Die logischen Operatoren (z.\,B.\ \lstinline|&&| in C)
+      prüfen die Zahl insgesamt auf $\ne 0$.
+      \hfill{\color{red}\lstinline|6 && 12 == 1|}\qquad\strut\\
+      Nicht verwechseln!
+  \end{itemize}
+
+  \bigbreak
+  
+  Anwendung: Bit 2 (also das dritte Bit von rechts) in einer 8-Bit-Zahl auf 1 setzen:
+  \begin{verbatim}
+      00000001            01101100
+   <<        2          | 00000100
+     ---------           ---------
+      00000100            01101100
+  \end{verbatim}
+  \begin{picture}(0,0)(0,-0.25)
+    \color{red}
+    \put(3.5,1.0){\mbox{Maske für Bit 2}}
+    \put(12.5,1.0){\mbox{Bit gezielt setzen}}
+  \end{picture}\vspace{-4ex}
+  \begin{itemize}
+    \item
+      Schreibweise in C:\quad
+      \lstinline,a |= 1 << 2;,
+  \end{itemize}
+
+  \bigbreak
+  
+  Anwendung: Bit 2 in einer 8-Bit-Zahl auf 0 setzen:
+  \begin{verbatim}
+      00000001                                01101100
+   <<        2          ~ 00000100          & 11111011
+     ---------           ---------           ---------
+      00000100            11111011            01101000
+  \end{verbatim}
+  \begin{picture}(0,0)(0,-0.25)
+    \color{red}
+    \put(3.5,1.0){\mbox{Maske zum Löschen von Bit 2 erzeugen}}
+    \put(22.5,1.0){\mbox{Bit gezielt löschen}}
+  \end{picture}\vspace{-4ex}
+  \begin{itemize}
+    \item
+      Schreibweise in C:\quad
+      \lstinline,a &= ~(1 << 2);,
+  \end{itemize}
+
+  \bigbreak
+
+  Anwendung: Bit 2 aus einer 8-Bit-Zahl extrahieren:
+  \begin{verbatim}
+      00000001            01101100            00000100
+   <<        2          & 00000100         >>        2
+     ---------           ---------           ---------
+      00000100            00000100            00000001
+  \end{verbatim}
+  \begin{picture}(0,0)(0,-0.25)
+    \color{red}
+    \put(2.5,1.0){\mbox{Maske für Bit 2}}
+    \put(12.5,1.0){\mbox{Bit 2 isolieren}}
+    \put(22.5,1.0){\mbox{in Zahl 0 oder 1 umwandeln}}
+  \end{picture}\vspace{-4ex}
+  \begin{itemize}
+    \item
+      Schreibweise in C:\quad
+      \lstinline,x = (a & (1 << 2)) >> 2;,
+  \end{itemize}
+
+  \bigbreak
+
+  Beispiel: Netzmaske für 256 IP-Adressen
+  \begin{verbatim}
+      192.168.  1.123
+    & 255.255.255.  0
+     ----------------
+      192.168.  1.  0
+  \end{verbatim}
+  \begin{picture}(0,0)(0,0)
+    \color{red}
+    \put(14.0,6.25){\vector(-1,0){2}}
+    \put(14.5,6){\mbox{IP-Adresse eines Rechners}}
+    \put(14.0,5.25){\vector(-1,0){2}}
+    \put(14.5,5){\mbox{Netzmaske: $255 = 11111111_2$}}
+    \put(14.0,3.25){\vector(-1,0){2}}
+    \put(14.5,3){\mbox{IP-Adresse des Sub-Netzes}}
+  \end{picture}\vspace{-6ex}
+
+  \bigbreak
+
+  Beispiel: Netzmaske für 8 IP-Adressen
+  \begin{verbatim}
+      192.168.  1.123                                   01111011
+    & 255.255.255.248                                 & 11111000
+     ----------------                                  ---------
+      192.168.  1.120                                   01111000
+  \end{verbatim}
+  \begin{picture}(0,0)(0,0)
+    \color{red}
+    \put(14.0,6.25){\vector(-1,0){2}}
+    \put(14.5,6){\mbox{IP-Adresse eines Rechners}}
+    \put(14.0,5.25){\vector(-1,0){2}}
+    \put(14.5,5){\mbox{Netzmaske}}
+    \put(14.0,3.25){\vector(-1,0){2}}
+    \put(14.5,3){\mbox{IP-Adresse des Sub-Netzes}}
+  \end{picture}\vspace{-6ex}
+
+  \subsection{Programmierung von Mikrocontrollern}
+
+  Ein Mikrocontroller ist ein elektronischer Baustein,
+  der einen kompletten Computer mit eingeschränkter Funktionalität enthält.
+
+  Mit "`eingeschränkter Funktionalität"' ist gemeint,
+  daß auf einem Mikrocontroller kein Universal-Betriebssystem läuft,
+  sondern daß darauf nur ein einziges Programm läuft,
+  nämlich die Anwendungs-Software.
+
+  Wenn ein Baustein einen kompletten Computer enthält,
+  der leistungsfähig genug ist,
+  daß darauf ein Universal-Betriebssystem laufen kann,
+  spricht man normalerweise nicht mehr von einem Mikrocontroller,
+  sondern von einem Ein-Chip-Computer.
+  Der Übergang ist fließend.
+
+  \breath
+
+  Da ein Mikrocontroller nicht über die Leistung verfügt,
+  einen Compiler laufen zu lassen,
+  erfolgt die Entwicklung von Software für Mikrocontroller
+  auf einem "`normalen"' Computer.
+  Diese Art der Software-Entwicklung,
+  bei der ein Computer Software für einen ganz anderen Computer erzeugt,
+  bezeichnet man als \newterm{Cross-Entwicklung}.
+  Die einzelnen Werkzeuge heißen entsprechend
+  \newterm{Cross-Compiler}, \newterm{Cross-Assembler\/} und \newterm{Cross-Linker}.
+
+  Beispiel: Erzeugen einer ausführbaren Datei \file{blink.elf}
+  aus einem C-Quelltext \file{blink.c}
+  für einen Mikrocontroller vom Typ ATmega328P
+  \begin{lstlisting}[style=cmd]
+    avr-gcc -Wall -Os -mmcu=atmega328p blink.c -o blink.elf
+  \end{lstlisting}
+
+  Damit der Mikrocontroller die ausführbare Datei ausführen kann,
+  muß man sie mit einem speziellen Werkzeug auf den Mikrocontroller
+  \newterm{herunterladen}.
+  Hierfür ist es oft notwendig, die Datei vorher in ein anderes Dateiformat
+  zu konvertieren.
+
+  Beispiel: Konvertierung der ausführbaren Datei \file{blink.elf}
+  aus dem ELF-Dateiformat in das Intel-HEX-Format:
+  \begin{lstlisting}[style=cmd]
+    avr-objcopy -O ihex blink.elf blink.hex
+  \end{lstlisting}
+
+  Anschließend kann die Datei auf den Mikrocontroller heruntergeladen werden.
+  Beispiel: Herunterladen der Datei \file{blink.hex}
+  in den Flash-Speicher eines ATmega328P-Mikrocontrollers
+  auf einem Mikrocontroller-Board vom Typ Arduino Uno
+  über die Schnittstelle \file{/dev/ttyACM0}
+  \begin{lstlisting}[style=cmd]
+    avrdude -P /dev/ttyACM0 -c arduino -p m328p -U flash:w:blink.hex
+  \end{lstlisting}
+
+  \subsection{I/O-Ports}
+
+  Es gibt drei grundlegende Mechanismen für die Kommunikation zwischen dem Prozessor
+  und einem externen Gerät:
+  \begin{itemize}
+    \item
+      Über Output-Ports kann der Prozessor das Gerät aktiv steuern,
+    \item
+      über Input-Ports kann er es aktiv abfragen,
+    \item
+      und über Interrupts kann das externe Gerät im Prozessor Aktivitäten auslösen.
+  \end{itemize}
+
+  \begin{center}
+    \includegraphics{io-ports-and-interrupts.pdf}
+  \end{center}
+
+  \setlength{\unitlength}{1cm}
+
+  Input- und Output-Ports, zusammengefaßt: I/O-Ports,
+  sind spezielle Speicherzellen, die mit einem externen Gerät verbunden sind.
+  \begin{itemize}
+    \item
+      Ein in einen Output-Port geschriebener Wert bewirkt eine Spannungsänderung in einer Leitung,
+      die zu einem externen Gerät führt.
+    \item
+      Wenn ein externes Gerät eine Spannung an eine Leitung anlegt, die zu einer Speicherzelle führt,
+      kann der Prozessor diese als Input-Port lesen.
+  \end{itemize}
+
+  Um z.\,B.\ auf einen Druck auf einen Taster zu warten,
+  kann ein Program periodisch in einer Schleife einen Input-Port lesen
+  und die Schleife erst dann beenden, wenn der Wert für "`Taster gedrückt"' gelesen wurde.
+
+  Diese Methode heißt "`Busy Waiting"': Der Prozessor ist vollständig mit Warten beschäftigt.
+  Wenn gleichzeitig noch andere Aktionen stattfinden sollen,
+  müssen diese in der Schleife mit berücksichtigt werden.
+
+  \bigskip
+  \goodbreak
+
+  Beispiel für die Verwendung eines Output-Ports: Roboter-Steuerung\\
+  Datei: RP6Base/RP6Base\_Examples/RP6Examples\_20080915/RP6Lib/RP6base/RP6RobotBaseLib.c\\
+  Suchbegriff: setMotorDir
+  \goodbreak
+  \begin{lstlisting}
+    void setMotorDir(uint8_t left_dir, uint8_t right_dir)
+    {
+            mleft_dir = left_dir;
+            mright_dir = right_dir;
+            mleft_des_dir = left_dir;
+            mright_des_dir = right_dir;
+            if(left_dir)
+                    PORTC |= DIR_L;
+            else
+                    PORTC &= ~DIR_L;
+            if(right_dir)
+                    PORTC |= DIR_R;
+            else
+                    PORTC &= ~DIR_R;
+    }
+  \end{lstlisting}
+
+  Die Variable \lstinline|PORTC| ist ein Output-Port.
+  Durch Manipulation einzelner Bits in dieser Variablen
+  ändert sich die Spannung an den elektrischen "`Beinchen"' des Mikrocontrollers.
+  Hierdurch wird die Beschaltung von Elektromotoren umgepolt.
+
+  (Die Konstanten \lstinline|DIR_L| und \lstinline|DIR_R| sind "`Bitmasken"',
+  d.\,h.\ Zahlen, die in ihrer Binärdarstellung nur eine einzige $1$ und ansonsten Nullen haben.
+  Durch die Oder- und Und-Nicht-Operationen werden einzelne Bits in \lstinline|PORTC| auf $1$ bzw.\ $0$ gesetzt.)
+
+  \bigskip
+
+  Die direkte Ansteuerung von I/O-Ports ist nur auf Mikrocontrollern üblich.
+  Auf Personal-Computern erfolgt die gesamte Ein- und Ausgabe über Betriebssystem-"`Treiber"'.
+  Anwenderprogramme greifen dort i.\,d.\,R.\ nicht direkt auf I/O-Ports zu.
+
+  \subsection{Interrupts}
+
+  Ein Interrupt ist ein Unterprogramm, das nicht durch einen Befehl (\lstinline|call|),
+  sondern durch ein externes Gerät (über ein Stromsignal) aufgerufen wird.
+
+  Damit dies funktionieret, muß die Adresse, an der sich das Unterprogramm befindet,
+  an einer jederzeit auffindbaren Stelle im Speicher hinterlegt sein.
+  Diese Stelle heißt "`Interrupt-Vektor"'.
+
+  Da ein Interrupt jederzeit erfolgen kann,
+  hat das Hauptprogramm keine Chance, vor dem Aufruf die Registerinhalte zu sichern.
+  Für Interrupt-Unterprogramme, sog.\ Interrupt-Handler,
+  ist es daher zwingend notwendig, sämtliche Register vor Verwendung zu sichern
+  und hinterher zurückzuholen.
+
+  \bigskip
+
+  Beispiel für die Verwendung eines Interrupts: Roboter-Steuerung\\
+  Datei: RP6Base/RP6Base\_Examples/RP6Examples\_20080915/RP6Lib/RP6base/RP6RobotBaseLib.c\\
+  Suchbegriff: ISR
+  \begin{lstlisting}
+    ISR (INT0_vect)
+    {
+            mleft_dist++;
+            mleft_counter++;
+            /* ... */
+    }
+  \end{lstlisting}
+  \begin{itemize}
+    \item
+      Durch das Schlüsselwort \lstinline|ISR| anstelle von z.\,B.\ \lstinline|void|
+      teilen wir dem Compiler mit, daß es sich um einen Interrupt-Handler handelt,
+      so daß er entsprechenden Code zum Sichern der Registerinhalte einfügt.
+    \item
+      Durch die Namensgebung \lstinline|INT0_vect| teilen wir dem Compiler mit,
+      daß er den Interrupt-Vektor Nr.\ 0 (also den ersten)
+      auf diesen Interrupt-Handler zeigen lassen soll.
+  \end{itemize}
+  (Tatsächlich handelt es sich bei \lstinline|ISR| und \lstinline|INT0_vect| um Macros.)
+
+  Die Schreibweise ist spezifisch für die Programmierung des Atmel AVR ATmega
+  unter Verwendung der GNU Compiler Collection (GCC).
+  Bei Verwendung anderer Werkzeuge und/oder Prozessoren
+  kann dasselbe Programm völlig anders aussehen.
+  Wie man Interrupt-Handler schreibt und wie man Interrupt-Vektoren setzt,
+  ist ein wichtiger Bestandteil der Dokumentation der Entwicklungswerkzeuge.
+
+  \bigskip
+
+  Die so geschriebene Funktion wird immer dann aufgerufen, wenn die
+  Hardware den Interrupt Nr.\ 0 auslöst. Wann das der Fall ist, hängt
+  von der Beschaltung ab. Im Falle des RP6 geschieht es dann, wenn
+  ein Sensor an der linken Raupenkette einen schwarzen Streifen auf
+  der Encoder-Scheibe registriert, also immer dann, wenn sich die
+  linke Raupenkette des Roboters um eine bestimmte Strecke gedreht
+  hat.
+
+  Jedesmal wenn sich die Raupenkette um einen Teilstrich weitergedreht hat,
+  werden also zwei Zähler inkrementiert.
+  Wir können dies nutzen, um z.\,B.\ durch Auslesen des Zählers \lstinline|mleft_dist|
+  die zurückgelegte Entfernung zu messen.
+  (Die RP6-Bibliothek selbst stellt nur eine Zeit- und eine Geschwindigkeitsmessung zur Verfügung.)
+  Wie dies konkret geschehen kann, sei im folgenden vorgestellt.
+
+  \goodbreak
+
+  Methode 1: Verändern des Interrupt-Handlers
+  \begin{itemize}
+    \item
+      Da die Bibliothek \lstinline|RP6RobotBase| im Quelltext vorhanden ist,
+      können wir sie selbst ändern und in den Interrupt-Handler
+      \lstinline|ISR (INT0_vect)| einen eigenen Zähler für Sensor-Ticks einbauen.
+    \item
+      Wenn wir diesen zum Zeitpunkt A auf 0 setzen und zum Zeitpunkt B
+      auslesen, erfahren wir, wieviele "`Ticks"' der Roboter dazwischen
+      zurückgelegt hat.
+  \end{itemize}
+
+  Methode 2: Verwenden eines vorhandenen Zählers
+  \begin{itemize}
+    \item
+      Tatsächlich enthält \lstinline|ISR (INT0_vect)| bereits zwei Zähler, die
+      bei jedem Sensor-"`Tick"' hochgezählt werden: \lstinline|mleft_dist| und
+      \lstinline|mleft_counter|.
+    \item
+      Einer davon (\lstinline|mleft_dist|) wird bei jedem \lstinline|move()| auf 0
+      zurückgesetzt. Für diesen Zähler enthält \lstinline|RP6RobotBaseLib.h|
+      einen "`undokumentierten"' Makro \lstinline|getLeftDistance()|, um ihn
+      auszulesen.
+    \item
+      Bei sorgfältiger Lektüre von \lstinline|RP6RobotBaseLib.c| erkennt man, daß
+      es unproblematisch ist, den Zähler vom Hauptprogramm aus auf 0 zu
+      setzen. (Dies ist jedoch mit Vorsicht zu genießen: In einer
+      eventuellen Nachfolgeversion der Bibliothek muß dies nicht mehr
+      der Fall sein!)
+  \end{itemize}
+
+  Methode 3: Abfrage der Sensoren mittels Busy Waiting
+  \begin{itemize}
+    \item
+      Alternativ zur Verwendung des Interrupt-Handlers kann man auch
+      von der eigenen Hauptschleife aus den Sensor periodisch abfragen
+      und bei jeder Änderung einen Zähler hochzählen. 
+    \item
+      Diese Methode heißt "`Busy Waiting"'. Sie hat den Vorteil der
+      Einfachheit aber den Nachteil, daß der Prozessor "`in Vollzeit"'
+      damit beschäftigt ist, einen Sensor abzufragen, und eventuelle
+      andere Aufgaben nur noch "`nebenher"' erledigen kann. 
+    \item
+      Wenn aus irgendwelchen Gründen der Interrupt-Mechanismus nicht
+      verwendet werden kann (z.B. weil der Prozessor über kein
+      Interrupt-Konzept verfügt), könnten wir die Lichtschranke alternativ auch mit einem Input-Port
+      verdrahten und mittels Busy Waiting abfragen.
+
+      Dies funktioniert nur dann, wenn die Schleife wirklich regelmäßig den Sensor abfragt.
+      Sobald der Prozessor längere Zeit mit anderen Dingen beschäftigt ist,
+      können beim Busy Waiting Signale der Lichtschranke verlorengehen.
+      Dieses Problem besteht nicht bei Verwendung von Interrupts.
+  \end{itemize}
+
+  \subsection{volatile-Variable}
+
+  Im C-Quelltext fällt auf, daß die Zähler-Variablen \lstinline|mleft_dist| und \lstinline|mleft_counter|\\
+  als \lstinline|volatile uint16_t mleft_counter| bzw.\ \lstinline|volatile uint16_t mleft_dist| deklariert sind\\
+  anstatt einfach nur als \lstinline|uint16_t mleft_counter| und \lstinline|uint16_t mleft_dist|.
+
+  Das Schlüsselwort \lstinline|volatile| teilt dem C-Compiler mit,
+  daß eine Variable immer im Speicher (RAM) aufbewahrt werden muß
+  und nicht in einem Prozessorregister zwischengespeichert werden darf.
+
+  Dies ist deswegen wichtig, weil jederzeit ein Interrupt erfolgen
+  kann, der den Wert der Variablen im Speicher verändert. Wenn im
+  Hauptprogramm alle "`überflüssigen"' Speicherzugriffe wegoptimiert
+  wurden, erfährt es nichts von der Änderung.
+
+  Entsprechendes gilt für I/O-Ports:
+  Wenn ein Programm einen Wert in einen Output-Port schreiben oder aus einem Input-Port lesen soll,
+  ist es wichtig, daß der Speicherzugriff auch tatsächlich stattfindet.
+
+\iffalse
+
+  \subsection{Software-Interrupts}
+ 
+  Manche Prozessoren verfügen über einen Befehl, um Interrupts "`künstlich"' auszulösen.
+
+  Das Betriebssystem MS-DOS verwendet derartige Aufrufe
+  anstelle von "`normalen"' Unterprogrammaufrufen,
+  um Programmen Funktionen zur Verfügung zu stellen.
+
+  \bigskip
+  \goodbreak
+
+  Beispiel: Assembler-Version von \lstinline| printf ("Hello, world!\n") | unter MS-DOS bzw.\ Unix
+
+  \medskip
+
+  \lstinline|  |MS-DOS-Version für FASM (gekürzt)\hspace{3cm} Unix-Version für GCC (gekürzt)
+  \begin{verbatim}
+  hello  db 'Hello, world', 10, 13, '$'     hello:
+                                                    .string "Hello, world!\n"
+  mov ah, 09h
+  mov dx, hello                                     pushl   $hello
+  int 21h                                           call    printf\end{verbatim}
+
+  \begin{itemize}
+    \item
+      Die MS-DOS-Version ruft den Interrupt Nr.\ 33 (hexadezimal: 21) auf: \lstinline| int 21h|.\\
+      Die Unix-Version verwendet stattdessen einen normalen Unterprogrammaufruf: \lstinline| call printf|.
+    \item
+      Die MS-DOS-Version übergibt Parameter in Prozessorregistern:\\
+      Die Konstante \lstinline|09h| im \lstinline|ah|-Register wählt die Funktion "`Textausgabe"' aus;\\
+      das \lstinline|dx|-Register enthält einen Zeiger auf den Text.
+
+      Die Unix-Version benutzt den Stack zur Übergabe des Parameters: \lstinline| pushl $hello|.\\
+      (\lstinline|$hello| ist ein Zeiger auf den Text.)
+    \item
+      Obwohl beide Programme auf demselben Prozessor laufen,
+      unterscheiden sich die Sprachdialekte der beiden Assember FASM und GCC erheblich voneinander.\\
+      (Reihenfolge der Operanden umgekehrt, Suffix \lstinline|l| für "`long"', Präfix \lstinline|$| für Konstanten, \dots)
+  \end{itemize}
+
+  Derartige "`Software-Interrupts"' verursachen Probleme,
+  sobald ein Gerät den Interrupt für seinen eigentlichen Zweck verwendet.
+  MS-Windows verwendet -- außer zur Emulation von MS-DOS -- keine Software-Interrupts mehr.
+
+  \bigskip
+
+  (Ein sehr ähnlicher Mechanismus wird von modernen Betriebssystemen weiterhin für Systemaufrufe genutzt.
+  Hier geht es darum, den Übergang von potentiell unsicherem Code in Anwenderprogrammen
+  zum vertrauenswürdigen Code des Betriebssystems zu kontrollieren. Für Details siehe:\\
+  \url{http://de.wikipedia.org/wiki/Software-Interrupt}, \url{http://de.wikipedia.org/wiki/Systemaufruf})
+
+\fi
+
+  \subsection{Byte-Reihenfolge -- Endianness}
+
+  \subsubsection{Konzept}
+
+  Beim Speichern von Werten,
+  die größer sind als die kleinste adressierbare Einheit\\
+  (= Speicherzelle oder Speicherwort, häufig 1 Byte), werden mehrere Speicherworte belegt.
+
+  Beispiel: 16-Bit-Zahl in 2 8-Bit-Speicherzellen
+  \begin{displaymath}
+    1027 = 1024 + 2 + 1 = 0000\,0100\,0000\,0011_2 = 0403_{16}
+  \end{displaymath}
+
+  Diese 16-Bit-Zahl kann auf zwei verschiedene Weisen
+  in zwei 8-Bit-Speicherzellen gespeichert werden:
+  \begin{center}
+    \begin{tabular}{|c|c|l}\cline{1-2}
+      \raisebox{-1pt}{04} & \raisebox{-1pt}{03} & \strut \newterm{Big-Endian}, "`großes Ende zuerst"', \\\cline{1-2}
+      \multicolumn{2}{c}{} & für Menschen leichter lesbar \\
+      \multicolumn{3}{c}{} \\[-5pt]\cline{1-2}
+      \raisebox{-1pt}{03} & \raisebox{-1pt}{04} & \strut \newterm{Little-Endian}, "`kleines Ende zuerst"', \\\cline{1-2}
+      \multicolumn{2}{c}{} & bei Additionen effizienter \\
+      \multicolumn{2}{c}{} & (Schriftliches Addieren beginnt immer beim Einer.)
+    \end{tabular}
+  \end{center}
+  Welche Konvention man verwendet, ist letztlich Geschmackssache
+  und hängt von der verwendeten Hardware (Prozessor) und Software ab.
+  Man spricht hier von der \newterm{Endianness\/} (Byte-Reihenfolge) der Hardware bzw.\ der Software.
+
+  Im Kontext des Datenaustausches ist es wichtig,
+  sich auf eine einheitliche Endianness zu verständigen.
+  Dies gilt insbesondere für:
+  \begin{itemize}
+    \item
+      Dateiformate
+    \item
+      Datenübertragung
+  \end{itemize}
+
+  \goodbreak
+  \subsubsection{Dateiformate}
+
+  Als Beispiel für Dateiformate, in denen die Reihenfolge der Bytes
+  in 16- und 32-Bit-Zahlen spezifiziert ist, seien hier Audio-Formate genannt:
+  \begin{itemize}
+    \item
+      RIFF-WAVE-Dateien (\file{.wav}): Little-Endian
+    \item
+      Au-Dateien (\file{.au}): Big-Endian
+    \goodbreak
+    \item
+      ältere AIFF-Dateien (\file{.aiff}): Big-Endian
+    \item
+      neuere AIFF-Dateien (\file{.aiff}): Little-Endian
+  \end{itemize}
+  Insbesondere ist es bei AIFF-Dateien wichtig, zu prüfen,
+  um welche Variante es sich handelt, anstatt sich auf eine bestimmte Byte-Reihenfolge zu verlassen.
+
+  Bei Dateiformaten mit variabler Endianness ist es sinnvoll und üblich,
+  die Endianness durch eine Kennung anzuzeigen.
+  Dies geschieht häufig am Anfang der Datei (im "`Vorspann"' -- "`Header"').
+
+  \bigbreak
+
+  Als weiteres Beispiel seien zwei Monochrom-Grafik-Formate genannt.
+  Hier steht jedes Bit für einen schwarzen bzw.\ weißen Bildpunkt,
+  daher spielt die Reihenfolge der Bits in den Bytes eine entscheidende Rolle.
+  (Diese Grafik-Formate werden in Übungsaufgaben weiter vertieft.)
+  \begin{itemize}
+    \item
+      PBM-Dateien: Big-Endian, \newterm{MSB first\/} -- die höchstwertige Binärziffer ist im Bild links
+    \item
+      XBM-Dateien: Little-Endian, \newterm{LSB first\/} -- die höchstwertige Binärziffer ist im Bild rechts
+  \end{itemize}
+  MSB/LSB = most/least significant bit
+
+  Achtung: Die Abkürzungen "`MSB/LSB"' werden manchmal auch für "`most/least significant \emph{byte}"' verwendet.
+  Im konkreten Fall ist es ratsam, die verwendete Byte- und Bit-Reihenfolge genau zu recherchieren
+  bzw.\ präzise zu dokumentieren.
+
+%  \bigbreak
+%
+%  Weiteres Beispiel: Textdateien im Format "`UTF-16"'.
+%  Hier stehen jeweils zwei aufeinanderfolgende Bytes für eine 16-Bit-Zahl.
+%  Am Dateianfang steht stets der Wert $65279 = \lstinline|FEFF|_{16}$ \dots
+
+  \subsubsection{Datenübertragung}
+
+  Bei der Übertragung von Daten über Leitungen
+  spielt sowohl die Reihenfolge der Bits in den Bytes ("`MSB first"' bzw.\ "`LSB first"')
+  als auch die Reihenfolge der Bytes in den übertragenen Zahlen ("`Big-/Little-Endian"') eine Rolle.
+
+  Als Beispiele seien genannt:
+  \begin{itemize}
+    \item
+      RS-232 (serielle Schnittstelle): MSB first
+    \item
+      I$^2$C: LSB first
+    \item
+      USB: beides
+
+      Um Übertragungsfehler erkennen zu können, werden im USB-Protokoll
+      bestimmte Werte einmal gemäß der MSB-first- und einmal gemäß der LSB-first-Konvention
+      übertragen und anschließend auf Gleichheit geprüft.
+    \medskip
+    \item
+      Ethernet: LSB first
+    \item
+      TCP/IP (Internet): Big-Endian
+  \end{itemize}
+  Insbesondere gilt für die Übertragung z.\,B.\ einer 32-Bit-Zahl über das Internet,
+  daß die vier Bytes von links nach rechts (Big-Endian) übertragen werden,
+  die acht Bits innerhalb jedes Bytes hingegen von rechts nach links (LSB first).
+
+  \subsection{Binärdarstellung von Zahlen}
+
+  Es gibt unendlich viele verschiedene ganze Zahlen.
+  Da Speicherplatz begrenzt ist, können Rechner nur begrenzt viele Zahlen darstellen.
+  In der Praxis legt man sich auf eine Anzahl von Bits fest,
+  die eine Zahl maximal belegen darf.
+  Typischerweise handelt es sich bei dieser Anzahl von Bits
+  um eine Zweierpotenz: 8, 16, 32, 64.
+
+  Eine 8-Bit-Zahl kann per definitionem Binärzahlen von 0000\,0000 bis 1111\,1111
+  darstellen. Dezimal sind dies die Zahlen von 0 bis 255.
+  Wenn man die 8-Bit-Zahl 255 inkrementiert (= um 1 erhöht),
+  gibt es einen Überlauf, und das Rechenergebnis ist 0:
+  Die Binärzahl 1111\,1111 + 1 = 1\,0000\,0000 hat 9 Bits.
+  Wenn man das oberste Bit abschneidet, bleibt der Wert 0 übrig.
+
+  Auf Computern macht man sich dieses Verhalten
+  für die Binärdarstellung negativer Zahlen zunutze:
+  Wenn 255 + 1 (dezimal geschrieben, mit 8-Bit-Zahlen berechnet) den Wert 0 ergibt,
+  dann ist 255 dasselbe wie $-1$.
+
+  Allgemein gilt: Diejenige Zahl $y$, die ich auf eine Zahl $x$ addieren muß,
+  um auf einem $n$-Bit-Rechner einen Überlauf und das Rechenergebnis $0$ zu erhalten,
+  ist die \emph{$n$-Bit-Binärdarstellung von $-x$\/}).
+
+  Um diese Zahl direkt auszurechnen, geht man folgendermaßen vor:
+  \begin{enumerate}
+    \item
+      Man invertiert alle Bits der Zahl.\\
+      Aus 0010\,1100 (= Binärdarstellung von 44) wird so zum Beispiel 1101\,0011.
+    \item
+      Man addiert 1 zu der erhaltenen Zahl:\\
+      1101\,0011 + 1 = 1101\,0100 (= 8-Bit-Binärdarstellung von $-44$).
+  \end{enumerate}
+  Diese Darstellung negativer Zahlen heißt \newterm{Zweierkomplement}.
+
+  \goodbreak
+
+  Theoretisch kann man jede Zahl bei gegebener Rechengenauigkeit
+  sowohl als postive als auch als negative Zahl interpretieren.
+  Die folgende Konvention hat sich als sinnvoll heraugestellt:
+  \begin{itemize}
+    \item
+      Entweder betrachtet man alle Zahlen als positiv,
+    \item
+      oder man betrachtet Zahlen, deren oberstes Bit gesetzt ist, als negativ\\
+      und die anderen als positiv.
+  \end{itemize}
+
+  Für normale Anwendungen ist die genaue Anzahl der Bits einer Ganzzahl-Variablen
+  unerheblich, sofern der Wertebereich groß genug für die durchzuführenden
+  Rechnungen ist. In diesen Fällen verwendet man in C den Datentyp \lstinline{int}
+  für vorzeichenbehaftete ganze Zahlen und \lstinline{unsigned int} (oder kurz:
+  \lstinline{unsigned}) für vorzeichenlose. Für die Ausgabe mit \lstinline{printf()}
+  verwendet man \lstinline{%d} oder \lstinline{%i} für vorzeichenbehaftete und
+  \lstinline{%u} für vorzeichenlose ganze Zahlen.
+
+  Für spezielle Situationen, in denen die genaue Anzahl der Bits eine Rolle spielt,
+  stellt C (unter Verwendung von \lstinline{#include <stdint.h>}) spezielle Datentypen bereit:
+
+  \begin{center}
+    \renewcommand{\arraystretch}{1.2}
+    \newcommand{\xdots}{\hspace*{-0.7em}\dots,\hspace*{-0.7em}}
+    \begin{tabular}{|c|c|c|rcl|}\hline
+      C-Datentyp & Bits & Vorzeichen & \multicolumn{3}{c|}{Wertebereich} \\\hline\hline
+      \lstinline,int8_t, & 8 & ja & $-128$, & \xdots & $127$ \\\hline
+      \lstinline,uint8_t, & 8 & nein & $0$, & \xdots & $255$ \\\hline
+      \lstinline,int16_t, & 16 & ja & $-32\,768$, & \xdots & $32\,767$ \\\hline
+      \lstinline,uint16_t, & 16 & nein & $0$, & \xdots & $65\,535$ \\\hline
+      \lstinline,int32_t, & 32 & ja & $-2\,147\,483\,648$, & \xdots & $2\,147\,483\,647$ \\\hline
+      \lstinline,uint32_t, & 32 & nein & $0$, & \xdots & $4\,294\,967\,295$ \\\hline
+      \lstinline,int64_t, & 64 & ja & $9\,223\,372\,036\,854\,775\,808$, & \xdots & $9\,223\,372\,036\,854\,775\,807$ \\\hline
+      \lstinline,uint64_t, & 64 & nein & $0$, & \xdots & $18\,446\,744\,073\,709\,551\,615$ \\\hline
+    \end{tabular}
+  \end{center}
+
+  Man beachte, daß es keine "`allein richtige"' Binärdarstellung einer negativen Zahl gibt;
+  diese hängt vielmehr von der Genauigkeit $n$ des $n$-Bit-Rechenwerks ab.
+  Auf einem 8-Bit-Rechner ist $255$ dasselbe wie $-1$,
+  auf einem 16-Bit-Rechner ist $255$ eine "`völlig normale"' Zahl;
+  stattdessen ist $65535$ dasselbe wie $-1$.
+
+  Ebensowenig gibt es einen "`allein richtigen"' Zahlenwert eines Bitmusters.
+  Dieser Zahlenwert hängt von der Genauigkeit $n$ des $n$-Bit-Rechenwerks ab
+  und davon, ob man überhaupt negative Zahlen zuläßt
+  oder vielleicht alle Zahlen als positive Zahlen interpretiert.
+
+  \breath
+
+  Beispiel: Für welche Zahl steht der Speicherinhalt 1001\,0000\,1100\,0011
+  (binär) = 90a3 (hexadezimal)?
+
+  Die richtige Antwort auf diese Frage hängt vom Datentyp ab,
+  also von der Bitgenauigkeit des Rechenwerks
+  und davon, ob wir überhaupt mit Vorzeichen rechnen:
+
+  \begin{tabular}{lrl}
+    als \lstinline,int8_t,: & $-93$ & (nur unteres Byte, Little-Endian)\\
+    als \lstinline,uint8_t,: & $163$ & (nur unteres Byte, Little-Endian)\\
+    als \lstinline,int16_t,: & $-28509$\\
+    als \lstinline,uint16_t,: & $37027$\\
+    \lstinline,int32_t, oder größer: & $37027$
+      & (zusätzliche Bytes mit Nullen aufgefüllt)
+  \end{tabular}
+
+  \breath
+
+  Siehe auch: \url{http://xkcd.com/571/}
+
+  \subsection{Speicherausrichtung -- Alignment}
+
+  Ein 32-Bit-Prozessor kann auf eine 32-Bit-Variable effizienter zugreifen,
+  wenn die Speicheradresse der Variablen ein Vielfaches von 32 Bits, also 4 Bytes ist.
+  Eine Variable, auf die dies zutrifft, heißt "`korrekt im Speicher ausgerichtet"' ("`aligned"').
+
+  "`Effizienter"' kann bedeuten,
+  daß Maschinenbefehle zum Arbeiten mit den Variablen schneller abgearbeitet werden.
+  Es kann aber auch bedeuten,
+  daß der Prozessor gar keine direkte Bearbeitung von inkorrekt ausgerichteten Variablen erlaubt.
+  In diesem Fall bedeutet eine inkorrekte Speicherausrichtung,
+  daß für jede Operation mit der Variablen anstelle eines einzelnen Maschinenbefehls
+  ein kleines Programm aufgerufen werden muß.
+
+  \bigskip
+
+  Um zu verstehen, welche Konsequenzen dies für die Arbeit mit Rechnern hat,
+  betrachten wir die folgenden Variablen:
+
+  \begin{lstlisting}
+    #include <stdint.h>
+
+    uint8_t a;
+    uint16_t b;
+    uint8_t c;
+  \end{lstlisting}
+
+  Die Anordnung dieser Variablen im Speicher könnte z.\,B.\ folgendermaßen aussehen:
+
+  \begin{quote}
+    \newcommand{\bup}{\begin{picture}(0,0)\put(-0.1,0.2){\mbox{\lstinline|b|}}\end{picture}}
+    \begin{tabular}{r|ccc|}
+                    & & \dots         & \\\cline{2-4}
+      \texttt{3005} & &               & \\\cline{2-4}
+      \texttt{3004} & &               & \\\cline{2-4}
+      \texttt{3003} & & \lstinline|c| & \\\cline{2-4}
+      \texttt{3002} & &               & \\\cline{2-2}\cline{4-4}
+      \texttt{3001} & & \bup          & \\\cline{2-4}
+      \texttt{3000} & & \lstinline|a| & \\\cline{2-4}
+      \texttt{2fff} & &               & \\\cline{2-4}
+                    & & \dots         &
+    \end{tabular}
+  \end{quote}
+
+  Ein optimierender Compiler wird für eine korrekte Ausrichtung der Variablen \lstinline|b| sorgen,
+  beispielsweise durch Auffüllen mit unbenutzten Speicherzellen:
+
+  \begin{quote}
+    \newcommand{\bup}{\begin{picture}(0,0)\put(-0.1,0.2){\mbox{\lstinline|b|}}\end{picture}}
+    \begin{tabular}{r|ccc|}
+                    & & \dots         & \\\cline{2-4}
+      \texttt{3005} & &               & \\\cline{2-4}
+      \texttt{3004} & & \lstinline|c| & \\\cline{2-4}
+      \texttt{3003} & &               & \\\cline{2-2}\cline{4-4}
+      \texttt{3002} & & \bup          & \\\cline{2-4}
+      \texttt{3001} & &               & \\\cline{2-4}
+      \texttt{3000} & & \lstinline|a| & \\\cline{2-4}
+      \texttt{2fff} & &               & \\\cline{2-4}
+                    & & \dots         &
+    \end{tabular}
+  \end{quote}
+
+  Alternativ ist es dem Compiler auch möglich,
+  die korrekte Ausrichtung durch "`Umsortieren"' der Variablen herzustellen
+  und dadurch "`Löcher"' zu vermeiden:
+
+  \begin{quote}
+    \newcommand{\bup}{\begin{picture}(0,0)\put(-0.1,0.2){\mbox{\lstinline|b|}}\end{picture}}
+    \begin{tabular}{r|ccc|}
+                    & & \dots         & \\\cline{2-4}
+      \texttt{3005} & &               & \\\cline{2-4}
+      \texttt{3004} & &               & \\\cline{2-4}
+      \texttt{3003} & &               & \\\cline{2-2}\cline{4-4}
+      \texttt{3002} & & \bup          & \\\cline{2-4}
+      \texttt{3001} & & \lstinline|c| & \\\cline{2-4}
+      \texttt{3000} & & \lstinline|a| & \\\cline{2-4}
+      \texttt{2fff} & &               & \\\cline{2-4}
+                    & & \dots         &
+    \end{tabular}
+  \end{quote}
+
+  Fazit: Man kann sich als Programmierer nicht immer darauf verlassen,
+  daß die Variablen im Speicher in einer spezifischen Weise angeordnet sind.
+
+  In vielen existierenden Programmen geschieht dies dennoch.
+  Diese Programme sind fehlerhaft.
+  Dort kann es z.\,B.\ passieren, daß nach einem Upgrade des Compilers
+  schwer lokalisierbare Fehler auftreten.
+
+  \bigskip
+  \goodbreak
+
+  Entsprechende Überlegungen gelten für 64-Bit- und 16-Bit-Prozessoren.
+  Die Größe der Variablen, aufgerundet auf die nächste Zweierpotenz, gibt eine Ausrichtung vor.
+  Die Registerbreite des Prozessors markiert die größte Ausrichtung, die noch berücksichtigt werden muß.
+
+  Bei 8-Bit-Prozessoren stellt sich die Frage nach der Speicherausrichtung normalerweise nicht,
+  weil die kleinste adressierbare Einheit eines Speichers selten kleiner als 8 Bits ist.
+
+  Beispiele:
+  \begin{itemize}
+    \item
+      Eine 64-Bit-Variable auf einem 64-Bit-Prozessor muß auf 64 Bits ausgerichtet sein.
+    \item
+      Eine 32-Bit-Variable auf einem 64-Bit-Prozessor braucht nur auf 32 Bits ausgerichtet zu sein.
+    \item
+      Eine 64-Bit-Variable auf einem 32-Bit-Prozessor braucht nur auf 32 Bits ausgerichtet zu sein.
+    \item
+      Eine 64-Bit-Variable auf einem 8-Bit-Prozessor braucht nur auf 8 Bits ausgerichtet zu sein.
+  \end{itemize}
+
+  Bei der Definition von Datenformaten tut man gut daran,
+  die Ausrichtung der Daten von vorneherein zu berücksichtigen,
+  um auf möglichst vielen -- auch zukünftigen -- Prozessoren
+  eine möglichst effiziente Bearbeitung zu ermöglichen.
+
+  Wenn ich beispielsweise ein Dateiformat definiere, in dem 128-Bit-Werte vorkommen,
+  ist es sinnvoll, diese innerhalb der Datei auf 128 Bits (16 Bytes) auszurichten,
+  auch wenn mein eigener Rechner nur über einen 64-Bit-Prozessor verfügt.
+
+\iffalse
+
+  \section{Ergänzungen und Ausblicke}
+
+  \subsection{String-Operationen}
+
+  Die Include-Datei \file{string.h} deklariert eine Sammlung nützlicher Funktionen
+  für den Umgang mit Strings (\lstinline{char *}).
+
+  In den Sortierprogrammen \file{sort-\lstinline{*}.c} wurde davon bereits
+  die Funktion \lstinline{strcmp()} verwendet.
+
+  \lstinline{strcmp (foo, bar)} liefert den Wert \lstinline{-1} zurück,
+  wenn der String \lstinline{foo} alphabetisch kleiner ist als der String \lstinline{bar},
+  sie liefert \lstinline{0} zurück, wenn beide Strings gleich sind,
+  und sie liefert \lstinline{1} zurück, wenn \lstinline{foo} alphabetisch größer ist als \lstinline{bar}.
+
+  \subsection{Dateien}
+
+  \begin{itemize}
+    \item
+      \file{fhello.c} ist das klassische "`Hello, world!"`-Programm in einer Variante,
+      die in eine Datei \file{hello.txt} anstelle der Standardausgabe schreibt.
+
+      \begin{experts}
+        Auch die Standardausgabe ist übrigens eine "`normale"' Datei.
+        \lstinline{printf (foo)} ist nur eine Abkürzung für \lstinline{fprintf (stdout, foo)}.
+      \end{experts}
+    \item
+      \file{fread-1.c} zeigt, wie man zeilenweise aus einer Textdatei liest.
+
+      Dieses Programm prüft nicht, ob die Datei tatsächlich
+      erfolgreich geöffnet werden konnte.
+      Dies hat zur Folge, daß im Fehlerfall versucht wird,
+      auf einen \lstinline{NULL}-Pointer zuzugreifen -- also einen Absturz.
+
+      Das Programm ist somit grob fehlerhaft.
+    \item
+      \file{fread-2.c} zeigt, wie es besser geht:
+      Wenn die Datei nicht geöffnet werden kann,
+      wird eine Fehlermeldung ausgegeben und das Programm kontrolliert beendet.
+
+      Es besteht aber weiterhin ein Problem:
+      Die Fehlerursache "`Datei nicht gefunden"' wurde lediglich geraten.
+      Sie kann falsch sein und somit, anstatt hilfreich zu sein,
+      den Benutzer in die Irre führen.
+
+      Auch dieses Programm ist also noch grob fehlerhaft.
+    \item
+      \file{fread-3.c} zeigt die korrekte Vorgehensweise:
+      Mit Hilfe der Systemvariablen \lstinline{errno} (deklariert in \file{errno.h})
+      und der Funktion \lstinline{strerror()} (deklariert in \file{string.h})
+      wird geprüft, welcher Fehler vorliegt.
+      Anhand dieser Information wird dann die vom Betriebssystem
+      für diesen Fall vorgesehene Fehlermeldung ausgegeben.
+  \end{itemize}
+
+  Dieselben Überlegungen zur Fehlerbehandlung gelten natürlich auch
+  für das Öffnen einer Datei zum Schreiben, hier also auch für \file{fhello.c}.
+
+\fi
+
+  \section{Algorithmen}
+
+  \subsection{Differentialgleichungen}
+
+  Eine mathematische Gleichung mit einer gesuchten Zahl $x$, z.\,B.
+  \begin{displaymath}
+    x + 2 = -x
+  \end{displaymath}
+  läßt sich leicht nach der Unbekannten $x$ auflösen.
+  (In diesem Fall lautet die Lösung: $x = -1$.)
+
+  Wesentlich schwieriger ist es,
+  eine mathematische Gleichung mit einer gesuchten Funktion $x(t)$ zu lösen, z.\,B.:
+  \begin{displaymath}
+    x'(t) = -x(t)\qquad\mbox{mit}\qquad x(0) = 1
+  \end{displaymath}
+  Um hier auf die Lösung $x(t) = e^{-t}$ zu kommen,
+  sind bereits weitreichende mathematische Kenntnisse erforderlich.
+
+  Eine derartige Gleichung, die einen Zusammenhang zwischen der gesuchten Funktion
+  und ihren Ableitungen vorgibt, heißt \newterm{Differentialgleichung}.
+  Viele physikalisch-technische Probleme werden durch Differentialgleichungen beschrieben.
+
+  \goodbreak
+
+  \subsubsection{Beispiel: Pendelschwingung}
+
+  \begin{minipage}{9.4cm}
+    \setlength{\parskip}{\smallskipamount}
+    Das Verhalten eines Fadenpendels (mathematisches Pendel)
+    wird durch seine Auslenkung $\phi$ als Funktion der Zeit $t$ beschrieben.
+    Wie kann man $\phi(t)$ berechnen?
+
+    Wie aus anderen Veranstaltungen (Grundlagen der Physik, Mechanik) her bekannt sein sollte,
+    wirkt auf ein Fadenpendel, das um den Winkel $\phi(t)$ ausgelenkt ist,
+    die tangentiale Kraft $F = -m \cdot g \cdot \sin\phi(t)$.
+    Gemäß der Formel $F = m \cdot a$ bewirkt diese Kraft
+    eine tangentiale Beschleunigung $a = -g \cdot \sin\phi(t)$.
+    (Das Minuszeichen kommt daher, daß die Kraft der Auslenkung entgegengesetzt wirkt.)
+
+    Wenn das Pendel die Länge $l$ hat, können wir dieselbe tangentiale Beschleunigung
+    mit Hilfe der zweiten Ableitung des Auslenkungswinkels $\phi(t)$ berechnen:
+    $a = l \cdot \phi''(t)$ (Winkel in Bogenmaß).
+    Durch Gleichsetzen erhalten wir eine Gleichung,
+    die nur noch eine Unbekannte enthält, nämlich die Funktion $\phi(t)$.
+
+    Um $\phi(t)$ zu berechnen, müssen wir also die Differentialgleichung
+    \begin{displaymath}
+      \phi''(t) = -\frac{g}{l} \cdot \sin\phi(t)
+    \end{displaymath}
+    lösen.
+  \end{minipage}\hfill
+  \begin{minipage}{5.5cm}
+    \begin{center}
+      \begin{pdfpic}
+        \psset{unit=1.5cm}%
+        \begin{pspicture}(0,0)(0,0)
+          \SpecialCoor
+          \psline[linewidth=1pt](3;-110)(0,0)
+          \rput(3.25;-110){\psline[linewidth=0.5pt,linecolor=lightgray](0.34;-20)(1.00;-90)}
+          \rput(3.25;-110){\psline[linewidth=0.5pt,linecolor=lightgray](0.94;-110)(1.00;-90)}
+          \rput(3.25;-110){\psline[linewidth=0.5pt,arrows=->](0,0)(0.34;-20)}
+          \rput(3.25;-110){\psline[linewidth=0.5pt,arrows=->](0,0)(0.94;-110)}
+          \rput(3.25;-110){\psline[linewidth=0.5pt,arrows=->](0,0)(1.00;-90)}
+          \rput(3.25;-110){\rput(0.64;-20){\makebox(0,0){$F$}}}
+          \rput(3.25;-110){\rput(1.30;-90){\makebox(0,0){$m\cdot g$}}}
+          \pscircle*(3;-110){0.07}
+          \psline[linewidth=0.5pt,linestyle=dashed](0,0)(0,-1.9)
+          \psarc[linewidth=0.5pt,arrows=<-](0,0){1.5}{-110}{-90}
+          \rput(1.3;-100){\makebox(0,0){$\phi$}}
+          \psarc[linewidth=0.5pt,linestyle=dashed,arrows=<->,arcsepA=0.12](0,0){3}{-110}{-70}
+          \rput(0,-4.5){\psstrut}
+        \end{pspicture}
+      \end{pdfpic}
+    \end{center}
+  \end{minipage}
+
+  \breath
+    
+  \begin{experts}
+    Diese Differentialgleichung läßt sich mit "`normalen"' Mitteln nicht lösen,
+    daher verwendet man in der Praxis meistens die Kleinwinkelnäherung
+    $\sin\phi \approx \phi$ (für $\phi \ll 1$)
+    und löst stattdessen die Differentialgleichung:
+    \begin{displaymath}
+      \phi''(t) = -\frac{g}{l} \cdot \phi(t)
+    \end{displaymath}
+    Für ein mit der Anfangsauslenkung $\phi(0)$ losgelassenes Pendel
+    lautet dann das Ergebnis:
+    \begin{displaymath}
+      \phi(t) = \phi(0)\cdot\cos(\omega t)\qquad\mbox{mit}\qquad\omega=\sqrt{\frac{g}{l}}
+    \end{displaymath}
+    Das Beispielprogramm \gitfile{hp}{script}{pendulum-1.c} illustriert,
+    welche Bewegung sich aus diesem $\phi(t)$ ergibt.
+  \end{experts}
+
+  \subsubsection{Das explizite Euler-Verfahren}
+
+  Um eine Differentialgleichung mit Hilfe eines Computers näherungsweise \newterm{numerisch\/} zu lösen,
+  stehen zahlreiche Lösungsverfahren zur Verfügung.
+  Im folgenden soll das einfachste dieser Verfahren, das \newterm{explizite Euler-Verfahren\/}
+  (auch \newterm{Eulersches Polygonzugverfahren\/} genannt) vorgestellt werden.
+
+  Wir betrachten das System während eines kleinen Zeitintervalls $\Delta t$.
+  Während dieses Zeitintervalls sind alle von der Zeit $t$ abhängigen Funktionen
+  -- z.\,B.\ Ort, Geschwindigkeit, Beschleunigung, Kraft -- näherungsweise konstant.
+
+  Bei konstanter Geschwindigkeit $v$ ist es einfach,
+  aus dem Ort $x(t)$ zu Beginn des Zeitintervalls
+  den Ort $x(t + \Delta t)$ am Ende des Zeitintervalls zu berechnen:
+  \begin{displaymath}
+    x(t + \Delta t) = x(t) + \Delta t \cdot v
+  \end{displaymath}
+
+  Bei konstanter Kraft $F = m \cdot a$
+  und somit konstanter Beschleunigung $a$ ist es ebenso einfach,
+  aus der Geschwindigkeit $v(t)$ zu Beginn des Zeitintervalls
+  die Geschwindigkeit $v(t + \Delta t)$ am Ende des Zeitintervalls zu berechnen:
+  \begin{displaymath}
+    v(t + \Delta t) = v(t) + \Delta t \cdot a
+  \end{displaymath}
+
+  Wenn wir dies in einer Schleife durchführen und jedesmal $t$ um $\Delta t$ erhöhen,
+  erhalten wir Näherungen für die Funktionen $x(t)$ und $v(t)$.
+
+  \breath
+
+  Für das oben betrachtete Beispiel (Fadenpendel)
+  müssen wir in jedem Zeitintervall $\Delta t$
+  zunächst die tangentiale Beschleunigung $a(t)$ aus der tangentialen Kraft berechnen,
+  die sich wiederum aus der momentanen Auslenkung $\phi(t)$ ergibt:
+  \begin{displaymath}
+    a = -g \cdot \sin\phi
+  \end{displaymath}
+  Mit Hilfe dieser -- innerhalb des Zeitintervalls näherungsweise konstanten -- Beschleunigung
+  berechnen wir die neue tangentiale Geschwindigkeit:
+  \begin{displaymath}
+    v(t + \Delta t) = v(t) + \Delta t \cdot a
+  \end{displaymath}
+  Mit Hilfe dieser -- innerhalb des Zeitintervalls näherungsweise konstanten -- Geschwindigkeit
+  berechnen wir schließlich die neue Winkelauslenkung $\phi$,
+  wobei wir einen kleinen Umweg über den Kreisbogen $x = l\cdot\phi$ machen:
+  \begin{displaymath}
+    \phi(t + \Delta t) = \frac{x(t + \Delta t)}{l}
+                       = \frac{x(t) + \Delta t \cdot v}{l}
+                       = \phi(t) + \frac{\Delta t \cdot v}{l}
+  \end{displaymath}
+
+  Ein C-Programm, das diese Berechnungen durchführt (Datei: \gitfile{hp}{script}{pendulum-2.c}), enthält als Kernstück:
+  \goodbreak
+  \begin{lstlisting}
+    #define g 9.81
+    #define l 1.0
+    #define dt 0.05
+    #define phi0 30.0  /* degrees */
+
+    float t = 0.0;
+    float phi = phi0 * M_PI / 180.0;
+    float v = 0.0;
+
+    void calc (void)
+    {
+      float a = -g * sin (phi);
+      v += dt * a;
+      phi += dt * v / l;
+    }
+  \end{lstlisting}
+  \goodbreak
+  Jeder Aufruf der Funktion \lstinline{calc()}
+  versetzt das Pendel um das Zeitintervall \lstinline{dt} in die Zukunft.
+ 
+  Es ist vom Verfahren her nicht notwendig, mit der Kleinwinkelnäherung $\sin\phi\approx\phi$ zu arbeiten.
+  Das Beispielprogramm \gitfile{hp}{script}{pendulum-3.c} illustriert,
+  welchen Unterschied die Kleinwinkelnäherung ausmacht.
+
+  Wie gut arbeitet das explizite Euler-Verfahren?
+  Um dies zu untersuchen, lösen wir eine Differentialgleichung,
+  deren exakte Lösung aus der Literatur bekannt ist,
+  nämlich die Differentialgleichung mit Kleinwinkelnäherung.
+  Das Beispielprogramm \gitfile{hp}{script}{pendulum-4.c} vergleicht beide Lösungen miteinander.
+  Für das betrachtete Beispiel ist die Übereinstimmung recht gut;
+  für Präzisionsberechnungen ist das explizite Euler-Verfahren jedoch nicht genau (und stabil) genug.
+  Hierfür sei auf die Lehrveranstaltungen zur numerischen Mathematik verwiesen.
+
+  \subsubsection*{Bemerkung}
+
+  Das Beispielprogramm \gitfile{hp}{script}{pendulum-4.c} berechnet mit überzeugender Übereinstimmung
+  dasselbe Ergebnis für die Auslenkung des Pendels auf zwei verschiedene Weisen:
+  \begin{enumerate}
+    \item
+      über eine Formel, die einen Cosinus enthält,
+    \item
+      mit Hilfe der Funktion \lstinline{calc()}, die nur Grundrechenarten verwendet.
+  \end{enumerate}
+  Dies läßt die Natur der Verfahren erahnen, mit deren Hilfe es möglich ist,
+  Sinus, Cosinus und andere kompliziertere Funktionen
+  nur unter Verwendung der Grundrechenarten zu berechnen.
+
+  \goodbreak
+
+  \subsection{Rekursion}
+
+  Aus der Mathematik ist das Beweisprinzip der \newterm{vollständigen Induktion\/} bekannt:
+  \begin{displaymath}
+    \hspace*{4cm}
+    \left.
+      \begin{array}{r}
+        \mbox{Aussage gilt für $n = 1$}\\[2pt]
+        \mbox{Schluß von $n - 1$ auf $n$}
+      \end{array}
+    \right\}
+    \mbox{Aussage gilt für alle $n\in\mathbb{N}$}
+  \end{displaymath}
+  Wenn auf diese Weise die Lösbarkeit eines Problems bewiesen wurde,
+  ist es direkt möglich, das Problem im Computer \emph{tatsächlich\/} zu lösen,
+  nämlich durch einen \newterm{rekursiven Algorithmus}.
+
+  \breath
+
+  Ein klassisches Beispiel für ein rekursiv lösbares Problem sind die Türme von Hanoi:
+  \begin{itemize}
+    \item
+      64 Scheiben, 3 Plätze, immer 1 Scheibe verschieben
+    \item
+      Ziel: Turm verschieben
+    \item
+      Es dürfen nur kleinere Scheiben auf größeren liegen.
+  \end{itemize}
+
+  \goodbreak
+  \begin{center}
+    \includegraphics[width=12.2cm]{Tower_of_Hanoi.jpeg}
+
+    \small
+
+    Bildquelle: \url{http://commons.wikimedia.org/wiki/File:Tower\_of\_Hanoi.jpeg}\\
+    Urheber: \url{http://en.wikipedia.org/wiki/User:Evanherk}\\
+    Lizenz: GNU FDL (Version 1.2 oder später) oder\\
+    Creative Commons Attribution-Share Alike (Version 3.0 Unported)
+    
+  \end{center}
+
+  \goodbreak
+  Die rekursive Lösung des Problems lautet:
+  \begin{itemize}
+    \item
+      Wenn $n = 1$ ist, also nur eine Scheibe vorliegt,
+      läßt sich diese "`einfach so"' an den Zielplatz verschieben.
+      In diesem Fall sind wir direkt fertig.
+    \item
+      Wenn $n - 1$ Scheiben als verschiebbar vorausgesetzt werden,
+      lautet die Vorgehensweise:\\
+      verschiebe die oberen $n - 1$ Scheiben auf einen Hilfsplatz,\\
+      verschiebe die darunterliegende einzelne Scheibe auf den Zielplatz,\\
+      verschiebe die $n - 1$ Scheiben vom Hilfsplatz auf den Zielplatz.
+  \end{itemize}
+
+  \goodbreak
+  Dieser Algorithmus läßt sich unmittelbar in eine Programmiersprache übersetzen:
+  \begin{lstlisting}
+    void verschiebe (int n, int start, int ziel)
+    {
+      if (n == 1)
+        verschiebe_1_scheibe (start, ziel);
+      else
+        {
+          verschiebe (1, start, hilfsplatz);
+          verschiebe (n - 1, start, ziel);
+          verschiebe (1, hilfsplatz, ziel);
+        }
+    }
+  \end{lstlisting}
+
+\iffalse
+
+  \subsection{Floodfill}
+
+  Siehe die Vortragsfolien \file{ainf-20121220.pdf}\\
+  sowie die Beispielprogramme \file{fill-\lstinline{*}.c}
+
+  \subsection{Stack und FIFO}
+
+  Siehe Vortragsfolien und Beispielprogramme
+
+  \subsection{Wegfindungsalgorithmus für Roboterfahrzeug}
+
+  Siehe die Vortragsnotizen \file{ainf-20130117.txt},\\
+  die Beispielprogramme \file{text-parcour-\lstinline{*}.c},
+  \file{robotext.c} und \file{robotext.h}\\
+  sowie die E-Mails "`Wegfindung"' und "`Weg-Finde-Algorithmus"'
+
+\fi
+
+  \subsection{Aufwandsabschätzungen}
+
+  \subsubsection{Sortieralgorithmen}
+
+  Am Beispiel von Sortieralgorithmen soll hier aufgezeigt werden,
+  wie man die Lösung eines Problems schrittweise effizienter gestalten kann.
+
+  Als Problem wählen wir das Sortieren eines Arrays (z.\,B.\ von Namen).
+
+  \begin{itemize}
+    \item
+      Minimum/Maximum ermitteln:
+      \gitfile{hp}{script}{sort-0.c} (mit "`Schummeln"'),
+      \gitfile{hp}{script}{sort-1.c} (lineare Suche),
+      \gitfile{hp}{script}{sort-2.c} (mit Visualisierung)
+    \item
+      Selectionsort:
+      \gitfile{hp}{script}{sort-3.c} (bei Minimumsuche Anfang des Arrays überspringen),
+      \gitfile{hp}{script}{sort-4.c} (Selectionsort),
+      \gitfile{hp}{script}{sort-5.c} (100 Namen),
+      \gitfile{hp}{script}{sort-6.c} (100 Namen, ohne Visualisierung)
+    \item
+      Bubblesort:
+      \gitfile{hp}{script}{sort-7.c} (Selectionsort, Minimumsuche mit in der Hauptschleife),
+      \gitfile{hp}{script}{bsort-1.c} (Minimumsuche durch Vergleich benachbarter Strings),
+      \gitfile{hp}{script}{bsort-2.c} (Abbruch in äußerer Schleife, sobald sortiert),
+      \gitfile{hp}{script}{bsort-3.c} (Abbruch auch in innerer Schleife, sobald sortiert)
+    \item
+      Quicksort:
+      \gitfile{hp}{script}{qsort-1.c} (Array in 2 Hälften vorsortieren),
+      \gitfile{hp}{script}{qsort-2.c} (rekursiver Aufruf für linke Hälfte),
+      \gitfile{hp}{script}{qsort-3.c} (rekursiver Aufruf für beide Hälften)
+  \end{itemize}
+
+  Bei "`zufällig"' sortierten Ausgangsdaten arbeitet Quicksort schneller als Bubblesort.
+  Wenn die Ausgangsdaten bereits nahezu sortiert sind, ist es umgekehrt.
+  Im jeweils ungünstigsten Fall arbeiten beide Algorithmen gleich langsam.
+
+  \subsubsection{Landau-Symbole}
+
+  Das Landau-Symbol $\mathcal{O}(g)$ mit einer Funktion $g(n)$
+  steht für die \newterm{Ordnung\/} eines Algorithmus',
+  also die "`Geschwindigkeit"', mit der er arbeitet.
+  Die Variable $n$ bezeichnet die Menge der Eingabedaten,
+  hier also z.\,B.\ die Anzahl der Namen.
+
+  \begin{center}
+    \begin{pdfpic}
+      \psset{unit=1pt}
+      \begin{pspicture}(-20,-20)(250,200)
+        \psline[arrows=->](-10,0)(200,0)
+        \psline[arrows=->](0,-10)(0,200)
+        \psplot[plotpoints=200]{1}{125}{2 x 0.06 mul exp}
+        \put(100,190){\mbox{$g(n) \sim 2^n$}}
+        \psplot[plotpoints=200]{0}{190}{x x mul 0.005 mul}
+        \put(190,190){\mbox{$g(n) \sim n^2$}}
+        \psplot[plotpoints=200]{1}{190}{x ln x mul 0.1 mul}
+        \put(195,100){\mbox{$g(n) \sim n \log n$}}
+        \psplot[plotpoints=200]{0}{190}{x 0.4 mul}
+        \put(195,75){\mbox{$g(n) \sim n$}}
+        \psplot[plotpoints=200]{1}{190}{x ln 10 mul}
+        \put(195,50){\mbox{$g(n) \sim \log n$}}
+        \put(210,0){\makebox(0,0)[l]{$n$}}
+        \put(0,210){\makebox(0,0)[l]{$g(n)$}}
+      \end{pspicture}
+    \end{pdfpic}
+  \end{center}
+
+  \begin{itemize}
+    \item
+      $\mathcal{O}(n)$ bedeutet, daß die Rechenzeit mit der Menge der Eingabedaten linear wächst.
+      Um doppelt so viele Namen zu sortieren, benötigt das Programm doppelt so lange.
+    \item
+      $\mathcal{O}(n^2)$ bedeutet, daß die Rechenzeit mit der Menge der Eingabedaten quadratisch wächst.
+      Um doppelt so viele Namen zu sortieren, benötigt das Programm viermal so lange.
+    \item
+      $\mathcal{O}(2^n)$ bedeutet, daß die Rechenzeit mit der Menge der Eingabedaten exponentiell wächst.
+      Für jeden Namen, der dazukommt, benötigt das Programm doppelt so lange.
+
+      Ein derartiges Programm gilt normalerweise als inakzeptabel langsam.
+    \item
+      $\mathcal{O}(\log n)$ bedeutet, daß die Rechenzeit mit der Menge der Eingabedaten logarithmisch wächst.
+      Für jede Verdopplung der Namen benötigt das Programm nur einen Rechenschritt mehr.
+
+      Ein derartiges Programm gilt als "`traumhaft schnell"'.
+      Dies wird jedoch nur selten erreicht.
+    \item
+      $\mathcal{O}(1)$ bedeutet, daß die Rechenzeit von der Menge der Eingabedaten unabhängig ist:
+      1\,000\,000 Namen werden genau so schnell sortiert wie 10.
+
+      Dies ist nur in Ausnahmefällen erreichbar.
+    \item
+      $\mathcal{O}(n \log n)$ liegt zwischen $\mathcal{O}(n)$ und $\mathcal{O}(n^2)$.
+
+      Ein derartiges Programm gilt als schnell.
+      Viele Sortieralgorithmen erreichen dieses Verhalten.
+  \end{itemize}
+
+  Wie sieht man einem Programm an, wie schnell es arbeitet?
+
+  \begin{itemize}
+    \item
+      Vorfaktoren interessieren nicht.
+
+      Wenn ein Code immer -- also unabhängig von den Eingabedaten -- zweimal ausgeführt wird,
+      beeinflußt das die Ordnung des Algorithmus nicht.
+
+      Wenn ein Code immer -- also unabhängig von den Eingabedaten -- 1\,000\,000mal ausgeführt wird,
+      mag das Programm für kleine Datenmengen langsam erscheinen.
+      Für die Ordnung interessiert jedoch nur das Verhalten für große Datenmengen,
+      und dort kann dasselbe Programm durchaus schnell sein.
+    \item
+      Jede Schleife, die von $0$ bis $n$ geht,
+      multipliziert die Rechenzeit des innerhalb der Schleife befindlichen Codes mit $n$.
+
+      Eine Doppelschleife (Schleife innerhalb einer Schleife) hat demnach $\mathcal{O}(n^2)$.
+    \goodbreak
+    \item
+      Wenn sich die Grenzen einer Schleife ständig ändern, nimmt man den Durschschnitt.
+
+      Beispiel:
+      \begin{lstlisting}[gobble=8]
+        for (int i = 0; i < n; i++)
+          for (int j = 0; j < i; j++)
+            ...
+      \end{lstlisting}
+      Die äußere Schleife wird immer $n$-mal ausgeführt,
+      die innere \emph{im Durchschnitt\/} $\frac{n}{2}$-mal, was proportional zu $n$ ist.
+
+      Zusammen ergibt sich $\mathcal{O}(n^2)$.
+    \item
+      Bei Rekursionen muß man mitzählen, wie viele Schleifen hinzukommen.
+
+      Bei Quicksort wird z.\,B.\ in jeder Rekursion
+      eine Schleife von $0$ bis $n$ (aufgeteilt) ausgeführt.
+      Bei jeder Rekursion wird das Array "`normalerweise"' halbiert,
+      d.\,h.\ die Rekursionstiefe ist proportional zum Logarithmus von $n$ (zur Basis 2).
+      Daraus ergibt sich die Ordnung $\mathcal{O}(n\log n)$ für den "`Normalfall"' des Quicksort.
+      (Im ungünstigsten Fall kann sich auch $\mathcal{O}(n^2)$ ergeben.)
+  \end{itemize}
+
+  Für eine präzise Definition der Landau-Symbole siehe z.\,B.:
+  \url{http://de.wikipedia.org/wiki/Landau-Symbole}
+
+  \section{Objektorientierte Programmierung}
+
+\iffalse
+
+  In Abschnitt \ref{Strukturen} haben wir Funktionen geschrieben,
+  die eine \lstinline{struct}-Variable bearbeiten.
+
+  Das Konzept, Funktionen möglichst eng mit den Daten zu bündeln,
+  die sie bearbeiten, ist ein wichtiger Aspekt der \newterm{objektorientierten Programmierung}.
+
+  Das Beispielprogramm \file{dates-1.c} illustriert einen Satz von Funktionen
+  zur Bearbeitung von \file{date}-Objekten, sog.\ \newterm{Methoden}.
+  Methoden erwarten als "`standardisierten"' ersten Parameter das Objekt:
+  einen Zeiger \lstinline{this} auf ein C-\lstinline{struct}.
+  Wenn der Satz von Funktionen vollständig ist, ist es nicht mehr nötig,
+  direkt auf die Datenfelder des \lstinline{struct}s zuzugreifen.
+  Dies nennt man \newterm{Kapselung}.
+
+  Viele Sprachen (z.\,B.\ C++ als Weiterentwicklung von C)
+  unterstützen objektorientierte Programmierung durch Sprachelemente.
+  In diesen Sprachen ist der \lstinline{this}-Parameter i.\,d.\,R.\ nicht sichtbar,
+  sondern implizit.
+
+  Das Beispielprogramm \file{dates-2.c} geht noch einen Schritt weiter
+  und verankert im Objekt Zeiger auf Methoden -- sog.\ \newterm{virtuelle Methoden}.
+  Dieses mit den Callback-Funktionen vergleichbare Konzept ermöglicht es,
+  verschiedenen, miteinander "`verwandten"' Objekten Methoden mit gleichen Namen
+  zuzuordnen, die sich aber unterschiedlich verhalten.
+  Dies nennt man \newterm{Polymorphie}.
+
+  Wenn die o.\,a.\ "`Verwandschaft"' von Objekten darin besteht,
+  daß das eine Objekt ein anderes erweitert (zusätzliche Datenfelder und Methoden,
+  evtl.\ veränderte, \newterm{überschriebene\/} virtuelle Methoden),
+  spricht man von \newterm{Vererbung}.
+  Das Objekt, das erweitert wird, ist der \newterm{Vorfahre\/} des anderen Objekts.
+
+  In Sprachen wie C, die keine Sprachelemente für objektorientierte Programmierung
+  zur Verfügung stellen, kann dennoch Objektorientierung "`zu Fuß"' erreicht werden.
+  Die GUI-Bibliothek GTK+,
+  die ursprünglich für das Bildverarbeitungsprogramm GIMP entwickelt wurde,
+  inzwischen aber in zahlreichen Programmen (z.\,B.\ Mozilla Firefox) ihren Dienst tut,
+  funktioniert auf diese Weise.
+
+\fi
+
+  \addtocounter{subsection}{-1}
+  \subsection{Dynamische Speicherverwaltung}
+
+  Variable in C haben grundsätzlich eine feste Größe.
+  Dies gilt auch für Arrays:
+  Auch mit der Schreibweise ohne Größenangabe, z.\,B.
+  \lstinline|int a[] = { 2, 3, 5, 7 };|
+  handelt es sich \emph{nicht\/} um ein Array veränderlicher Größe.
+  Die \lstinline{[]}-Schreibweise besagt lediglich,
+  daß der Compiler die Größe des Arrays anhand des Initialisierers
+  (hier: \lstinline|{ 2, 3, 5, 7 }|) selbst berechnen soll.
+  Das Beispiel \lstinline|int a[] = { 2, 3, 5, 7 };| ist nur eine andere Schreibweise für
+  \lstinline|int a[4] = { 2, 3, 5, 7 };|.
+
+  Um \emph{tatsächlich\/} Arrays mit einer variablen Anzahl von Elementen verwenden
+  zu können, ist es in C notwendig, durch einen Funktionsaufruf explizit Speicher zu
+  reservieren:
+  \begin{lstlisting}
+    #include <stdlib.h>
+    ...
+    int *a = malloc (4 * sizeof (int));
+    ...
+    free (a);
+  \end{lstlisting}
+
+  \lstinline{malloc()} reserviert Speicher, \lstinline{free()} gibt ihn wieder frei.
+   
+  Man beachte, daß man in C auf Zeiger mit dem \lstinline{[]}-Operator
+  genau wie auf "`normale"' Arrays mit einem Index zugreifen kann:
+  \begin{lstlisting}
+    int *a = malloc (4 * sizeof (int));
+    ...
+    for (int i = 0; i < 4; i++)
+      printf ("%d\n", a[i]);
+  \end{lstlisting}
+
+  Es gibt normalerweise keine Möglichkeit, einem Zeiger (hier: \lstinline{a}) anzusehen,
+  wie groß der Speicherbereich ist, auf den er zeigt.
+  Diesen Wert muß sich das Programm selbst merken, typischerweise in einer Variablen:
+  \begin{lstlisting}
+    int n = 4;
+    int *a = malloc (n * sizeof (int));
+    ...
+    for (int i = 0; i < n; i++)
+      printf ("%d\n", a[i]);
+  \end{lstlisting}
+
+  \subsection{Konzepte und Ziele}
+
+  Für viele Anwendungen ist der o.\,a.\ Mechanismus der \newterm{dynamischen Arrays\/}
+  noch nicht flexibel genug: Auch wenn die Anzahl der Elemente nicht mehr festliegt,
+  so müssen doch alle genau dieselbe Größe haben. In vielen Situationen möchte man
+  jedoch eine vorher nicht festgelegte Anzahl von Objekten unterschiedlichen Typs in
+  einer Schleife abarbeiten -- z.\,B.\ verschiedene geometrische Objekte in einem
+  Zeichenprogramm oder verschiedene Bedienelemente (Button, Zeichenbereich,
+  Eingabefeld, \dots) in einer graphischen Benutzeroberfläche (Graphical User
+  Interface -- GUI).
+
+  Um dieses Problem zu lösen, speichert man Zeiger auf Objekte unterschiedlicher Größe
+  in einem dynamischen Array.
+  Dies funktioniert, weil alle Zeiger -- auch wenn sie auf unterschiedlich große
+  Objekte zeigen -- die gleiche Größe haben
+  und daher in demselben Array koexistieren können.
+
+  \breath
+
+  Um alle diese Objekte in einer Schleife auf gleiche Weise behandeln zu können,
+  benötigt man standardisierte Funktionen, die mit dem Objekt arbeiten.
+  Diese nennt man \newterm{Methoden}.
+
+  Eine Methode bewirkt unterschiedliche Dinge,
+  je nachdem, auf welches Objekt sie angewandt wird.
+  Dies hängt vom Typ des Objekts ab.
+  Um dies zu realisieren, kann man ein Objekt als \lstinline{struct}-Variable
+  speichern, die zusätzlich zum eigentlichen Inhalt
+  eine Kennung für den Objekttyp als Datenfeld enthält.
+  In der Methode fragt man diese Typkennung ab
+  und entscheidet auf dieser Grundlage, was die Methode bewirkt.
+
+  Dies kann über \lstinline{if}-Abfragen (oder \lstinline{switch}-Anweisungen)
+  geschehen, bei sehr vielen unterschiedlichen Objekttypen entarten derartige
+  Methoden jedoch zu sehr unübersichtlichen \lstinline{if}-Ketten.
+  Weiter unten werden elegantere Wege zur Realisierung von Methoden vorgestellt.
+
+  \breath
+
+  Objekte, die einen gemeinsamen Anteil von Eigenschaften haben
+  und sich typischerweise in demselben Array befinden,
+  bezeichnet man als \newterm{miteinander verwandt}.
+  Der "`kleinste gemeinsame Nenner"' dieser Objekte,
+  also ein Objekttyp der \emph{nur\/} den gemeinsamen Anteil enthält,
+  heißt \newterm{Basisklasse\/} oder \newterm{gemeinsamer Vorfahr\/}
+  der Objekte. Umgekehrt heißt ein Objekttyp, der eine Basisklasse um neue
+  Eigenschaften erweitert, \newterm{abgeleitete Klasse\/}
+  oder \newterm{Nachfahre} der Basisklasse.
+
+  Eigenschaften, die ein Objekttyp mit seinem Vorfahren gemeinsam hat,
+  bezeichnet man als \newterm{vom Vorfahren geerbt}.
+
+  \breath
+
+  Ein "`Array von Objekten"' wird zunächst als Array von Zeigern auf die Basisklasse
+  realisiert; die Zeiger zeigen aber in Wirklichkeit
+  auf Objekte von abgeleiteten Klassen.
+  Diese Möglichkeit, unterschiedliche Objekte gemeinsam zu verwalten,
+  bezeichnet man als \newterm{Polymorphie} (griechisch: \emph{Vielgestaltigkeit\/}).
+
+  \subsection{Beispiel: Zahlen und Buchstaben}
+
+  Als Beispiel konstruieren wir eine Struktur,
+  die Zahlen und Buchstaben (Strings) gemeinsam verwalten soll,
+  also gewissermaßen ein Array,
+  das sowohl ganze Zahlen (\lstinline{int})
+  als auch Strings (\lstinline{char *}) als Elemente haben kann.
+
+  Zu diesem Zweck definieren wir zwei \lstinline{struct}-Datentypen
+  \lstinline{t_integer} und \lstinline{t_string},
+  die als Inhalt (\lstinline{content}) eine ganze Zahl bzw.\ einen String enthalten
+  und zusätzlich eine Typ-Kennung (hier: \lstinline{int type}).
+  Weiterhin definieren wir einen gemeinsamen Vorfahren \lstinline{t_base},
+  der \emph{nur\/} die Typ-Kennung enthält.
+
+  \goodbreak
+
+  \begin{center}
+    \begin{minipage}{5cm}
+      \begin{lstlisting}[gobble=8]
+        typedef struct
+        {
+          int type;
+        } t_base;
+      \end{lstlisting}
+    \end{minipage}\\[0.5cm]
+    \begin{minipage}{5cm}
+      \begin{lstlisting}[gobble=8]
+        typedef struct
+        {
+          int type;
+          int content;
+        } t_integer;
+      \end{lstlisting}
+    \end{minipage}
+    \begin{minipage}{5cm}
+      \begin{lstlisting}[gobble=8]
+        typedef struct
+        {
+          int type;
+          char *content;
+        } t_string;
+      \end{lstlisting}
+    \end{minipage}
+  \end{center}
+
+  Man beachte, daß diese drei \lstinline{struct}-Datentypen
+  trotz der absichtlichen Gemeinsamkeiten
+  aus Sicht des C-Compilers nichts miteinander zu tun haben;
+  sie sind voneinander vollkommen unabhängige Datentypen.
+
+  Unser "`Array von Zahlen und Buchstaben"'
+  erzeugen wir nun als Array von Zeigern auf den Basistyp,
+  lassen die Zeiger aber in Wirklichkeit
+  auf Variablen der abgeleiteten Datentypen zeigen:
+
+  \begin{lstlisting}
+    #define T_INTEGER 1
+    #define T_STRING 2
+
+    t_integer i = { T_INTEGER, 42 };
+    t_string s = { T_STRING, "Hello, world!" };
+
+    t_base *object[] = { (t_base *) &i, (t_base *) &s, NULL };
+  \end{lstlisting}
+  \begin{picture}(0,0.9)(0,-0.6)
+    \color{red}
+    \put(2.975,0.75){\mbox{$\underbrace{\rule{1.45cm}{0pt}}_{\shortstack{\strut explizite\\Typumwandlung}}$}}
+  \end{picture}
+
+  Damit der Compiler dies ohne Warnung akzeptiert,
+  ist eine explizite Typumwandlung des jeweiligen Zeigers auf den abgeleiteten Typ
+  in einen Zeiger auf den Basistyp erforderlich.
+
+  Bei der Benutzung der abgeleiteten Typen
+  erfolgt wieder eine explizite Typumwandlung, nur diesmal in umgekehrter Richtung:
+
+  \begin{lstlisting}
+    void print_object (t_base *this)
+    {
+      if (this->type == T_INTEGER)
+        printf ("Integer: %d\n", ((t_integer *) this)->content);
+      else if (this->type == T_STRING)
+        printf ("String: \"%s\"\n", ((t_string *) this)->content);
+    }
+    ...
+    for (int i = 0; object[i]; i++)
+      print_object (object[i]);
+  \end{lstlisting}
+
+  (Beispiel-Programm: \gitfile{hp}{20161219}{objects-7.c})
+
+  Die expliziten Typumwandlungen sind ein gravierender Nachteil dieser
+  Vorgehensweise, denn sie schalten jegliche Überprüfung durch den Compiler aus.
+  Der Programmierer ist komplett selbst dafür verantwortlich,
+  daß die \lstinline{struct}-Datentypen gemeinsame Felder haben
+  und daß der Zeiger jeweils auf den richtigen \lstinline{struct}-Typ zeigt.
+
+  Die folgenden Abschnitte stellen Möglichkeiten vor,
+  diese Nachteile abzumildern.
+
+  \breath
+
+  Die Verwendung von Zeigern auf "`normale"' Variable ist in der Praxis unüblich.
+  Stattdessen reserviert man mit \lstinline{malloc()} Speicher für die Objekte.
+  Es hat sich bewährt, für diesen Zweck eine spezielle Funktion,
+  den sog.\ \newterm{Konstruktor\/} zu schreiben.
+  Der Konstruktor kann den reservierten Speicher auch direkt
+  mit sinnvollen Werten initialisieren, wodurch wieder eine Fehlerquelle wegfällt.
+
+  \begin{lstlisting}
+    t_integer *new_integer (int i)
+    {
+      t_integer *p = malloc (sizeof (t_integer));
+      p->type = T_INTEGER;
+      p->content = i;
+      return p;
+    }
+
+    t_string *new_string (char *s)
+    {
+      t_string *p = malloc (sizeof (t_string));
+      p->type = T_STRING;
+      p->content = s;
+      return p;
+    }
+    ...
+
+    t_base *object[] = { (t_base *) new_integer (42),
+                        (t_base *) new_string ("Hello, world!"),
+                        NULL };
+  \end{lstlisting}
+
+  (Beispiel-Programm: \gitfile{hp}{20161219}{objects-8.c})
+
+  \subsection{Unions}
+
+  Explizite Typumwandlungen sind unsicher und nach Möglichkeit zu vermeiden.
+  Eine Alternative ergibt sich durch Verwendung des Datentyps \lstinline{union}.
+
+  Eine \lstinline{union} sieht formal wie ein \lstinline{struct} aus.
+  Der Unterschied besteht darin, daß die Datenfelder eines \lstinline{struct}
+  im Speicher \emph{hintereinander\/} liegen,
+  wohingegen sich die Datenfelder einer \lstinline{union}
+  \emph{denselben Speicherbereich teilen}.
+
+  \begin{minipage}[b]{6cm}
+    \begin{lstlisting}[gobble=6]
+      #include <stdio.h>
+      #include <stdint.h>
+
+      typedef union
+      {
+        int8_t i;
+        uint8_t u;
+      } num8_t;
+    \end{lstlisting}
+  \end{minipage}%
+  \begin{minipage}[b]{6cm}
+    \begin{lstlisting}[gobble=6]
+      int main (void)
+      {
+        num8_t n;
+        n.i = -3;
+        printf ("%d\n", n.u);
+        return 0;
+      }
+    \end{lstlisting}
+  \end{minipage}
+
+  Die im o.\,a.\ Beispiel konstruierte \lstinline{union}
+  spricht dieselbe Speicherzelle einerseits als \lstinline{int8_t} an
+  und andererseits als \lstinline{uint8_t}.
+  Das Beispiel-Programm (Datei: \gitfile{hp}{20161219}{unions-1.c})
+  nutzt dies aus, um die negative Zahl \lstinline{-3}
+  als positive 8-Bit-Zahl auszugeben (Berechnung des Zweierkomplements).
+
+  \breath
+
+  In der objektorientierten Programmierung in C
+  nutzt man \lstinline{union}-Datentypen,
+  um ohne explizite Typumwandlung denselben Speicherbereich
+  als Objekte verschiedenen Typs zu interpretieren:
+
+  \begin{minipage}[t]{3.5cm}
+    \begin{lstlisting}[gobble=6]
+
+
+      typedef struct
+      {
+        int type;
+      } t_base;
+    \end{lstlisting}
+  \end{minipage}%
+  \begin{minipage}[t]{3.5cm}
+    \begin{lstlisting}[gobble=6]
+
+      typedef struct
+      {
+        int type;
+        int content;
+      } t_integer;
+    \end{lstlisting}
+  \end{minipage}%
+  \begin{minipage}[t]{3.5cm}
+    \begin{lstlisting}[gobble=6]
+
+      typedef struct
+      {
+        int type;
+        char *content;
+      } t_string;
+    \end{lstlisting}
+  \end{minipage}%
+  \begin{minipage}[t]{4.5cm}
+    \begin{lstlisting}[gobble=6]
+      typedef union
+      {
+        t_base base;
+        t_integer integer;
+        t_string string;
+      } t_object;
+    \end{lstlisting}
+  \end{minipage}
+  \begin{center}
+    \begin{minipage}{8.5cm}
+      \begin{lstlisting}[gobble=8]
+        if (this->base.type == T_INTEGER)
+          printf ("Integer: %d\n", this->integer.content);
+        else if (this->base.type == T_STRING)
+          printf ("String: \"%s\"\n", this->string.content);
+      \end{lstlisting}
+    \end{minipage}
+  \end{center}
+
+  (Beispiel-Programm: \gitfile{hp}{20161219}{objects-9.c})
+
+  Das Ansprechen falscher Speicherbereiche
+  wird hierdurch zwar nicht völlig ausgeschlossen;
+  der Compiler hat jedoch wesentlich mehr Möglichkeiten
+  als bei expliziten Typumwandlungen,
+  den Programmierer vor derartigen Fehlern zu bewahren.
+
+  Das Problem, von Hand dafür sorgen zu müssen,
+  daß die \lstinline{struct}-Datentypen zueinander passende Datenfelder enthalten,
+  bleibt weiterhin bestehen.
+
+  \breath
+
+  Ein alternativer Ansatz besteht darin,
+  nur die veränderlichen Eigenschaften der Objekte
+  in einer \lstinline{union} zu speichern --
+  siehe Aufgabe 1 (c) bis (e) in den Übungen vom 19.\,12.\,2016
+  (Datei: \gitfile{hp}{20161219}{hp-uebung-20161219.pdf}).
+
+  \goodbreak
+
+  \subsection{Beispiel: graphische Benutzeroberfläche (GUI)}
+
+  \href{http://www.gtk.org/}{GTK+} ist eine weit verbreitete Bibliothek
+  zur Erstellung graphischer Benutzeroberflächen (Graphical User Interface -- GUI).
+  Sie wurde ursprünglich
+  für das Bildverarbeitungsprogramm \href{http://www.gimp.org}{GIMP} geschrieben,
+  kommt aber u.\,a.\ auch im Web-Browser
+  \href{http://www.mozilla.org}{Mozilla Firefox} zum Einsatz.
+
+  GTK+ ist in C geschrieben und objektorientiert.
+  Die Bibliothek verwendet intern einige der hier besprochenen Vorgehensweisen
+  zur Realisierung objektorientierter Programmierung in C.
+
+  Die Beispielprogramme \href{https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/20161219}%
+  {\file{gtk-1.c} bis \file{gtk-7.c}} demonstrieren,
+  wie man mit Hilfe von GTK+ ein einfaches GUI-Programm schreibt,
+  das graphische Objekte (Rechteck, Kreis, Dreieck) auf den Bildschirm zeichnet
+  und sich nach dem Anklicken eines Buttons beendet.
+
+  Die Bedienelemente der GUI sind in GTK+ Objekte.
+  Hier ein paar Beispiele:
+  \begin{itemize}
+    \item
+      \lstinline{GtkWidget} ist die Basisklasse für alle GUI-Elemente.
+    \item
+      \lstinline{GtkContainer} ist ein Nachfahre von \lstinline{GtkWidget}.\\
+      Dieses Objekt kann, ähnlich einem Array, andere Objekte enthalten.
+    \item
+      \lstinline{GtkWindow} ist ein Fenster auf dem Bildschirm.\\
+      Es ist ein Nachfahre von \lstinline{GtkContainer}
+      und kann daher andere Objekte enthalten.
+    \item
+      \lstinline{GtkDrawingArea} ist ein rechteckiger Zeichenbereich auf dem Bildschirm.
+    \item
+      \lstinline{GtkButton} ist ein Bedienknopf.\\
+      Durch Anklicken des Knopfes kann der Benutzer Aktionen auslösen.
+  \end{itemize}
+
+  Um bei einer abgeleiteten Klasse (z.\,B.\ \lstinline{GtkWindow})
+  Eigenschaften der Basisklasse (z.\,B.\ \lstinline{GtkContainer}) nutzen zu können,
+  verwendet GTK+ explizite Typumwandlungen, die in Präprozessor-Macros gekapselt sind.
+  Um zum Beispiel ein \lstinline{GtkWindow}-Objekt \lstinline{window}
+  als \lstinline{GtkContainer} ansprechen zu können,
+  verwendet man \lstinline{GTK_CONTAINER (window)}.
+
+  Ähnlich wie in OpenGL/GLUT erfolgt auch in GTK+ das Zeichnen
+  sowie die Verarbeitung von Benutzereingaben (Tastatur, Maus)
+  über Callbacks.
+
+  In \href{https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/20161219/hp-2016ws-p4.pdf}%
+  {Praktikumsversuch 4} haben Sie selbst weitere Erfahrungen mit GTK+ gesammelt
+  und gleichzeitig eine eigene Objekt-Hierarchie
+  (für graphische Objekte: Rechteck, Kreis, Dreieck) programmiert.
+
+  \subsection{Virtuelle Methoden}
+
+  In großen Programmen wird die Anzahl der verwendeten Objekt-Datentypen
+  schnell sehr groß. Eine Methode, die per \lstinline{if} unterscheiden muß,
+  welche Art von Objekt sie gerade bearbeitet,
+  enthält dann lange \lstinline{if}-Ketten
+  und wird dadurch sehr unübersichtlich.
+
+  \begin{lstlisting}
+    void print_object (t_object *this)
+    {
+      if (this->base.type == T_INTEGER)
+        printf ("Integer: %d\n", this->integer.content);
+      else if (this->base.type == T_STRING)
+        printf ("String: \"%s\"\n", this->string.content);
+    }
+  \end{lstlisting}
+
+  Es wäre vorteilhaft, wenn alle Methoden,
+  die sich auf einen bestimmten Objekttyp beziehen,
+  auch nebeneinander im Quelltext stehen könnten,
+  anstatt sich über den gesamten Quelltext zu verteilen
+  (weil jede Funktion einen \lstinline{if}-Zweig für diesen Objekttyp hat).
+
+  \begin{lstlisting}
+    void print_integer (t_object *this)
+    {
+      printf ("Integer: %d\n", this->integer.content);
+    }
+
+    void print_string (t_object *this)
+    {
+      printf ("String: \"%s\"\n", this->string.content);
+    }
+  \end{lstlisting}
+
+  Um dies zu realisieren, verwendet man \emph{Zeiger auf Funktionen}:
+
+  \begin{lstlisting}
+    typedef struct
+    {
+      void (*print) (union t_object *this);
+    } t_base;
+
+    typedef struct
+    {
+      void (*print) (union t_object *this);
+      int content;
+    } t_integer;
+
+    typedef struct
+    {
+      void (*print) (union t_object *this);
+      char *content;
+    } t_string;
+  \end{lstlisting}
+
+  Um in C einen Zeiger auf eine Funktion zu deklarieren,
+  deklariert man eine "`normale"' Funktion,
+  deren "`Name"' die Gestalt \lstinline{(*print)} hat --
+  mit dem vorangestellten Stern und den umschließenden Klammern.
+  (Merkregel: Das, worauf \lstinline{print} zeigt -- also \lstinline{*print} --,
+  ist eine Funktion.)
+
+  Der Aufruf einer derartigen Funktion erfolgt
+  über den im Objekt gespeicherten Zeiger:
+
+  \begin{lstlisting}
+    for (int i = 0; object[i]; i++)
+      object[i]->print (object[i]);
+  \end{lstlisting}
+
+  Eine derartige Funktion, die für verschiedene Objekttypen existiert
+  und bei deren Aufruf automatisch "`die passende"' Funktion ausgewählt wird,
+  heißt \newterm{virtuelle Methode}.
+
+  \breath
+
+  Jeder Methode wird ein Zeiger \lstinline{t_object *this} auf das Objekt
+  als Parameter mitgegeben.
+
+  Bei der Deklaration der virtuellen Methode innerhalb des Objekt-Typs
+  wird daher der Union-Typ \lstinline{t_object} bereits benötigt.
+  Dieser kann jedoch erst später deklariert werden,
+  wenn die darin enthaltenen Objekt-Typen bekannt sind.
+
+  Um dieses Problem zu lösen, muß die \lstinline{union t_object}
+  "`doppelt"' deklariert werden:
+
+  \begin{lstlisting}
+    typedef union t_object
+    {
+      t_base base;
+      t_integer integer;
+      t_string string;
+    } t_object;
+  \end{lstlisting}
+
+  Dadurch daß \lstinline{t_object} auch oben,
+  hinter dem Schlüsselwort \lstinline{union} steht,
+  ist neben dem Datentyp \lstinline{t_object}
+  auch ein Datentype \lstinline{union t_object}
+  (in einem separaten Namensraum) bekannt.
+  Derartig deklarierte Typen kann man \newterm{vorwärts-deklarieren\/}:
+  Wenn man eine Zeile
+  \begin{lstlisting}
+    union t_object;
+  \end{lstlisting}
+  den anderen Deklarationen voranstellt,
+  wissen diese, daß es später eine \lstinline{union t_object} geben wird.
+  Zeiger auf diese -- noch unbekannte -- \lstinline{union}
+  dürfen dann bereits in Deklarationen -- hier: Funktionsparameter --
+  verwendet werden.
+
+  \breath
+
+  Das Beispiel-Programm \gitfile{hp}{20170109}{objects-12.c} illustriert,
+  wie man virtuelle Methoden in C realisieren kann.
+
+  In größeren Projekten ist es nicht effizient,
+  in jeder einzelnen Objektinstanz (= Variable des Objekttyps)
+  sämtliche Zeiger auf sämtliche virtuellen Methoden zu speichern.
+  Stattdessen speichert man in der Objektinstanz
+  lediglich einen Zeiger auf eine Tabelle von Zeigern auf die virtuellen Methoden,
+  die sog.\ \newterm{virtuelle Methodentabelle} --
+  siehe das Beispiel-Programm \gitfile{hp}{20170109}{objects-13.c}.
+
+  \subsection{Einführung in C++}
+
+  Objektorientierte Programmierung in C ist sehr mühselig und fehleranfällig:
+  Objekt-Datentypen müssen manuell so abgeglichen werden,
+  daß sie in ihren ersten Datenfeldern übereinstimmen,
+  Konstruktoren müssen manuell erstellt werden, usw.
+
+  Um diese Probleme zu beheben, wurden neue Computersprachen entwickelt,
+  die objektorientierte Programmierung durch neue Sprachelemente unterstützen.
+  Die objektorientierte Weiterentwicklung von C ist C++.
+  Andere bekannte objektorientierte Sprachen sind Java, Python, C\#, JavaScript,
+  PHP, verschiedene Pascal-Dialekte und viele weitere.
+
+  Das Beispiel-Programm \gitfile{hp}{20170109}{objects-14.cpp}
+  ist eine direkte Übersetzung von \gitfile{hp}{20170109}{objects-12.c} nach C++.
+  In C++ kümmert sich der Compiler um die Vererbung zwischen den Objekt-Datentypen,
+  um die Verwaltung der Zeiger auf virtuelle Methoden,
+  um korrekte Konstruktoren und um vieles mehr.
+  Auch die Übergabe des Objekt-Zeigers \lstinline{this} an Methoden
+  erfolgt in C++ automatisch: Aus \lstinline{object[i]->base.print (object[i]);}
+  wird \lstinline{object[i]->print ();}.
+
+  Dadurch daß der Compiler viele Aufgaben übernimmt,
+  die der Programmierer ansonsten manuell abarbeiten müßte,
+  wird der Quelltext kürzer und weniger fehleranfällig.
+
+  \section{Datenstrukturen}
+
+  \subsection{Stack und FIFO}
+
+  Eine häufige Situation beim Programmieren ist,
+  daß man ein Array für eine gewisse Maximalmenge von Einträgen anlegt,
+  aber nur zum Teil nutzt.
+
+  Einem derartigen Array ein Element hinzuzufügen, ist einfach:
+  Man erhöht die Variable, die die Auslastung des Arrays speichert.
+  Ebenso einfach ist das Entfernen des zuletzt eingefügten Elements:
+  Man erniedrigt die Variable, die die Auslastung des Arrays speichert.
+
+  "`Einfach"' bedeutet hier, daß die benötigte Rechenzeit gering ist.
+  Genaugenommen ist die Rechenzeit immer gleich groß,
+  egal wie viele Elemente sich bereits im Array befinden.
+  Die Komplexität (Landau-Symbol) der Operation,
+  am Ende des Arrays ein Element einzufügen oder zu entfernen,
+  ist $\mathcal{O}(1)$.
+
+  Eine derartige Struktur eignet sich gut,
+  um Elemente in der Reihenfolge des Eintreffens zu speichern,
+  sie aber in \emph{umgekehrter\/} Reihenfolge wieder abzuarbeiten.
+  Man "`stapelt"' gewissermaßen die Elemente in dem Array.
+  Aus diesem Grunde heißt diese Struktur \newterm{Stack\/} (engl.: \emph{Stapel})
+  oder \newterm{LIFO\/} für \emph{last in, first out}.
+
+  Andere Operationen -- z.\,B.\ das Einfügen oder Löschen von Elementen
+  in der Mitte -- sind aufwendiger, da man die im Array befindlichen Elemente
+  in einer Schleife beiseiteschieben muß.
+  Die Rechenzeit ist proportional zur Anzahl der Elemente,
+  die sich bereits im Array befinden: $\mathcal{O}(n)$.
+
+  Das Suchen in einem bereits sortieren Array ist hingegen in $\mathcal{O}(\log n)$
+  möglich: Man beginnt die Suche in der Mitte und prüft,
+  ob sich das gesuchte Element in der unteren oder in der oberen Hälfte befindet.
+  In der ermittelten Hälfte beginnt man die Suche wieder in der Mitte --
+  so lange, bis man nur noch ein einzelnes Element vor sich hat.
+
+  Das Beispiel-Programm \gitfile{hp}{20170116}{stack-11.c} illustriert,
+  wie man einen Stack mit den o.\,g.\ Funktionalitäten implementieren kann.
+
+  \breath
+
+  Eine weitere wichtige Situation ist,
+  daß man anfallende Daten zwischenspeichern
+  und \emph{in derselben Reihenfolge\/} wieder abarbeiten möchte.
+  Eine Struktur, die dies ermöglicht, heißt \newterm{FIFO\/}
+  für \emph{first in, first out}.
+
+  Um einen FIFO zu realisieren, verwendet man nicht eine einzelne Variable,
+  die den genutzten Teil des Arrays speichert, sondern zwei:
+  Ein Schreib-Index markiert, an welcher Stelle Platz
+  für das nächste einzufügende Element ist;
+  ein Lese-Index markiert das zuerst eingefügte Element.
+  Beide Indizes werden bei Verwendung hochgezählt.
+  Wenn sie gleich sind, ist der FIFO leer.
+
+  Der entscheidende Trick: Wenn eine der beiden Indexvariablen
+  das Ende des Arrays erreicht, wird sie wieder auf 0 gesetzt.
+  Die beiden Indexvariablen arbeiten also \emph{ringförmig\/}; 
+  der FIFO wird durch einen \newterm{Ringpuffer\/} realisiert.
+
+  Beispiel-Programm: \gitfile{hp}{20170116}{fifo-8.c}
+
+  \subsection{Verkettete Listen}
+
+  In Arrays ist das Einfügen in der Mitte sehr aufwendig ($\mathcal{O}(n)$).
+  Um das Einfügen zu vereinfachen, hat man sich die folgende Struktur überlegt:
+
+  \begin{itemize}
+    \item
+      Jeder Datensatz ist ein \lstinline{struct},
+      der zusätzlich zum eigentlichen Inhalt noch einen Zeiger
+      auf das nächste Element enthält.
+    \item
+      Beim letzten Element zeigt der Zeiger auf \lstinline{NULL}.
+    \item
+      Eine Variable (z.\,B.\ \lstinline{first}) zeigt auf das erste Element.
+    \item
+      Wenn die Liste leer ist, zeigt bereits die \lstinline{first}-Variable
+      auf \lstinline{NULL}.
+  \end{itemize}
+
+  \begin{quote}
+    \begin{tikzpicture}
+      \color{blendedblue}
+      \node(first) at (0,0.5) {first};
+      \node[shape=rectangle,draw,line width=1pt](3) at (1,2) {3};
+      \node[shape=rectangle,draw,line width=1pt](7) at (3,2) {7};
+      \node[shape=rectangle,draw,line width=1pt](137) at (5,2) {137};
+      \node(NULL) at (7,2) {NULL};
+      \draw[-latex](first)--(3);
+      \draw[-latex](3)--(7);
+      \draw[-latex](7)--(137);
+      \draw[-latex](137)--(NULL);
+    \end{tikzpicture}
+  \end{quote}
+
+  Eine derartige Struktur heißt eine \newterm{(einfach) verkettete Liste}.
+
+  Wenn nun ein zusätzliches Element in die Liste eingefügt werden soll,
+  geschieht dies durch "`Umbiegen"' der Zeiger,
+  die auf das jeweils nächste Element zeigen:
+
+  \begin{quote}
+    \begin{tikzpicture}
+      \color{blendedblue}
+      \node(first) at (0,0.5) {first};
+      \node[shape=rectangle,draw,line width=1pt](3) at (1,2) {3};
+      \node[shape=rectangle,draw,line width=1pt](5) at (2,1) {5};
+      \node[shape=rectangle,draw,line width=1pt](7) at (3,2) {7};
+      \node[shape=rectangle,draw,line width=1pt](137) at (5,2) {137};
+      \node(NULL) at (7,2) {NULL};
+      \draw[-latex](first)--(3);
+      \draw[-latex](3) to[out=0] (5);
+      \draw[-latex](5) to[in=180] (7);
+      \draw[-latex](7)--(137);
+      \draw[-latex](137)--(NULL);
+    \end{tikzpicture}
+  \end{quote}
+
+  Unabhängig von der Gesamtzahl der Elemente,
+  die sich bereits in der Liste befinden,
+  müssen für das Einfügen eines Elements genau 2 Zeiger neu gesetzt werden.
+  Der Aufwand für das Einfügen beträgt somit $\mathcal{O}(1)$.
+
+  Diesem Vorteil steht der Nachteil gegenüber,
+  daß es bei einer verketteten Liste nicht mehr möglich ist,
+  "`einfach so"' auf das Element mit einem bekannten Index zuzugreifen;
+  dies kann nun nur noch über eine Schleife geschehen.
+  Während bei einem Array der wahlfreie Zugriff in $\mathcal{O}(1)$ möglich ist,
+  geschieht dies bei einer verketteten Liste in $\mathcal{O}(n)$.
+
+  Als Konsequenz ist auch das Suchen in $\mathcal{O}(\log n)$ nicht mehr möglich;
+  auch dies erfordert nun $\mathcal{O}(n)$.
+
+  \subsection{Bäume}
+
+  Für datenintensive Anwendungen -- insbesondere Datenbanken --
+  ist es wünschenswert, \emph{sowohl\/} den wahlfreien Zugriff
+  \emph{als auch\/} das Einfügen in der Mitte \emph{als auch\/}
+  das Suchen und das sortierte Einfügen möglichst effizient zu realisieren.
+
+  Dies geschieht über rekursive Datenstrukturen, sog.\ \newterm{Bäume}.
+
+  \breath
+
+  Wie bei einer verketteten Liste sind die Elemente -- die \newterm{Knoten\/} --
+  eines Baums \lstinline{struct}-Variable.
+  Zusätzlich zum eigentlichen Inhalt speichert man darin noch Zeiger
+  auf größere bzw.\ kleinere Elemente.
+
+  Im einfachsten Fall enthält jeder Knoten genau einen Inhalt
+  und jeweils einen Zeiger auf kleinere bzw.\ größere Elemente:
+
+  \begin{lstlisting}
+    typedef struct node
+    {
+      int content;
+      struct node *left, *right;
+    } node;
+  \end{lstlisting}
+
+  Ein aus derartigen Knoten aufgebauter Baum
+  verzweigt sich an jedem Knoten in jeweils zwei Teilbäume
+  und heißt daher \newterm{binärer Baum}.
+
+  Die Struktur emöglicht es,
+  jeweils "`zwischen"' zwei bereits eingefügten Knoten noch weitere einzufügen.
+  Wenn in einen derartigen sortierten binären Baum nacheinander die Zahlen
+  7, 3, 137 und 5 eingefügt werden, ergibt sich das folgende Bild:
+
+  \begin{quote}
+    \begin{tikzpicture}
+      \color{blendedblue}
+      \node(root) at (0,0) {\lstinline{node *root;}};
+      \node[shape=rectangle,draw,line width=1pt](7) at (0,-1.5) {7};
+      \draw[-latex](root)--(7);
+      \node[shape=rectangle,draw,line width=1pt](137) at (2,-3) {137};
+      \draw[-latex](7)--(137);
+      \node(137_left) at (1,-4.5) {\lstinline{NULL}};
+      \node(137_right) at (3,-4.5) {\lstinline{NULL}};
+      \draw[-latex](137)--(137_left);
+      \draw[-latex](137)--(137_right);
+      \node[shape=rectangle,draw,line width=1pt](3) at (-2,-3) {3};
+      \draw[-latex](7)--(3);
+      \node(3_left) at (-3,-4.5) {\lstinline{NULL}};
+      \draw[-latex](3)--(3_left);
+      \node[shape=rectangle,draw,line width=1pt](5) at (-1,-4.5) {5};
+      \draw[-latex](3)--(5);
+      \node(5_left) at (-2,-6) {\lstinline{NULL}};
+      \node(5_right) at (0,-6) {\lstinline{NULL}};
+      \draw[-latex](5)--(5_left);
+      \draw[-latex](5)--(5_right);
+    \end{tikzpicture}
+  \end{quote}
+
+  Sowohl das Einfügen als auch die Ausgabe und die Suche
+  erfolgen in Bäumen \emph{rekursiv}.
+  Der Rechenaufwand hängt dabei von der Rekursionstiefe,
+  also von der "`Tiefe"' des Baums ab.
+  Da die Tiefe mit der maximal möglichen Anzahl der Knoten logarithmisch wächst,
+  ist Einfügen und Suchen in $\mathcal{O}(\log n)$ möglich.
+  Dies ist ein Kompromiß zwischen den Verhalten eines Arrays
+  (Einfügen in $\mathcal{O}(n)$, Suchen in $\mathcal{O}(\log n)$)
+  und dem einer verketteten Liste (Einfügen in $\mathcal{O}(1)$,
+  Suchen in $\mathcal{O}(n)$).
+  Ein sortiertes Einfügen in einen Baum
+  ermöglicht eine Sortierung in $\mathcal{O}(n\log n)$.
+
+  Dies funktioniert nur, wenn die Tiefe des Baums tatsächlich nur logarithmisch
+  mit der Anzahl der Knoten wächst.
+  Wenn man in dem oben beschriebenen einfachen Fall eines binären Baums
+  die Elemente in bereits sortierter Reihenfolge einfügt,
+  entartet der Baum zu einer verketteten Liste.
+  Suchen ist dann nur noch in $\mathcal{O}(n)$ möglich
+  und Sortieren in $\mathcal{O}(n^2)$.
+
+  Um dies zu vermeiden, wurden teils aufwendige Strategien entwickelt,
+  den Baum jederzeit \newterm{balanciert},
+  d.\,h.\ in logarithmischer Tiefe zu halten.
+  Derartige \newterm{balancierte Bäume\/} finden Verwendung
+  in realen Datenbank-Programmen.
+
+\end{document}
diff --git a/script/hp-slides-title-2020ws.pdf b/script/hp-slides-title-2020ws.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..5f9b06adb89e7eed1d8b163cabc6c2955153bdad
Binary files /dev/null and b/script/hp-slides-title-2020ws.pdf differ
diff --git a/script/hp-slides-title-2020ws.tex b/script/hp-slides-title-2020ws.tex
new file mode 100644
index 0000000000000000000000000000000000000000..f91e237bee502e184f9b69bb353656fea606b04e
--- /dev/null
+++ b/script/hp-slides-title-2020ws.tex
@@ -0,0 +1,75 @@
+% hp-slides-title-2020ws.pdf - Title Page for Lecture Slides on Low-Level Programming
+% Copyright (C) 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/>.
+
+\documentclass[10pt,t]{beamer}
+
+\usepackage{pgslides}
+
+\setlength{\parskip}{\medskipamount}
+
+\title{Hardwarenahe Programmierung}
+\author{Prof.\ Dr.\ rer.\ nat.\ Peter Gerwinski}
+\date{Wintersemester 2020/21}
+
+\begin{document}
+
+\maketitleframe
+
+\nosectionnonumber{Wichtiger Hinweis}
+
+\begin{frame}[plain]
+
+  \vfill
+
+  \shownosectionnonumber
+
+  \vspace*{-\medskipamount}
+
+  Diese Vortragsfolien dienen dazu, den Vortrag der/des Lehrenden zu unter-\\stützen.
+  Sie enthalten \textbf{nur einen Teil} der Lerninhalte.
+  Wie groß dieser Teil ist, hängt von den konkreten Lerninhalten ab
+  und kann von "`praktisch alles"' bis "`praktisch gar nichts"' schwanken.
+  Diese Folien alleine sind daher
+  \textbf{nicht für ein Selbststudium geeignet!}
+  Hierfür sei auf das Skript verwiesen,
+  in dem allerdings keine tagesaktuellen Änderungen enthalten sind.
+
+  Mindestens genauso wichtig wie die Vortragsfolien sind die Beispiel-Programme,
+  die vor Ihren Augen in den Vorlesungen erarbeitet werden.
+  Diese sind im Git-Repository
+  (\url{https://gitlab.cvh-server.de/pgerwinski/hp.git})
+  mit allen Zwischenschritten enthalten und befinden sich
+  in den zu den jeweiligen Kalenderdaten gehörenden Verzeichnissen
+  (z.\,B.\ für den 10.\kern0.5pt10.\,2020 unter
+  \url{https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/20201105/}\kern1pt).
+
+  Wenn Sie die Übungsaufgaben bearbeiten, nutzen Sie die Gelegenheit,
+  Ihre Lösungen in den Übungen überprüfen zu lassen.
+  Wer nach Vergleich mit der Musterlösung zu dem Schluß kommt,
+  alles richtig gelöst zu haben, erlebt sonst in der Klausur oft eine
+  unangenehme Überraschung.
+
+  \strut\hfill In jedem Fall: \emph{Viel Erfolg!}
+
+\end{frame}
+
+\end{document}
diff --git a/script/if-0.c b/script/if-0.c
new file mode 100644
index 0000000000000000000000000000000000000000..dfb4aec197bbb12584bbaceb35181fc7f0b015f2
--- /dev/null
+++ b/script/if-0.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int a, b;
+  printf ("Bitte a eingeben: ");
+  scanf ("%d", &a);
+  printf ("Bitte b eingeben: ");
+  scanf ("%d", &b);
+  printf ("a geteilt durch b ist: %d\n", a / b);
+  return 0;
+}
diff --git a/script/if-1.c b/script/if-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e3104ff36e95c10188beb787fb2a2c27457a17b2
--- /dev/null
+++ b/script/if-1.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int a, b;
+  printf ("Bitte a eingeben: ");
+  scanf ("%d", &a);
+  printf ("Bitte b eingeben: ");
+  scanf ("%d", &b);
+  if (b != 0)
+    printf ("a geteilt durch b ist: %d\n", a / b);
+  return 0;
+}
diff --git a/script/if-2.c b/script/if-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..295496a3d67ae6220d8ed49724cab55e4dc6115e
--- /dev/null
+++ b/script/if-2.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int a, b;
+  printf ("Bitte a eingeben: ");
+  scanf ("%d", &a);
+  printf ("Bitte b eingeben: ");
+  scanf ("%d", &b);
+  if (b != 0)
+    printf ("a geteilt durch b ist: %d\n", a / b);
+  else
+    printf ("Bitte nicht durch 0 teilen!\n");
+  return 0;
+}
diff --git a/script/if-3.c b/script/if-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..514672ff98b5524216ef2c14bfb2a0601c0177e9
--- /dev/null
+++ b/script/if-3.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int a, b;
+  printf ("Bitte a eingeben: ");
+  scanf ("%d", &a);
+  printf ("Bitte b eingeben: ");
+  scanf ("%d", &b);
+  if (b != 0)
+    printf ("a geteilt durch b ist: %d\n", a / b);
+  else
+    printf ("Bitte nicht durch 0 teilen!\n");
+    printf ("Das tut man nicht.\n");
+  return 0;
+}
diff --git a/script/if-4.c b/script/if-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..e82781f53b33882eef10cca825fb6ebe9b886942
--- /dev/null
+++ b/script/if-4.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int a, b;
+  printf ("Bitte a eingeben: ");
+  scanf ("%d", &a);
+  printf ("Bitte b eingeben: ");
+  scanf ("%d", &b);
+  if (b != 0)
+    printf ("a geteilt durch b ist: %d\n", a / b);
+  else
+    {
+      printf ("Bitte nicht durch 0 teilen!\n");
+      printf ("Das tut man nicht.\n");
+    }
+  return 0;
+}
diff --git a/script/if-5.c b/script/if-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..af167ac2baf8a2467e87d1ec1c6fb43cc967ed81
--- /dev/null
+++ b/script/if-5.c
@@ -0,0 +1,5 @@
+#include<stdio.h>
+int main(void){int a,b;printf("Bitte a eingeben: ");scanf("%d",&a);
+printf("Bitte b eingeben: ");scanf("%d",&b);if(b!=0)printf(
+"a geteilt durch b ist: %d\n",a/b);else{printf("Bitte nicht durch 0 teilen!\n");
+printf("Das tut man nicht.\n");}return 0;}
diff --git a/script/if-6.c b/script/if-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..aa0c257019586c9371441e379bb777e2888804bb
--- /dev/null
+++ b/script/if-6.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int b;
+  printf ("Bitte b eingeben: ");
+  scanf ("%d", &b);
+  printf ("Der Ausdruck b != 0 hat den Wert %d\n", b != 0);
+  printf ("Der Ausdruck b == 0 hat den Wert %d\n", b == 0);
+  printf ("Der Ausdruck b = 23 hat den Wert %d\n", b = 23);
+  return 0;
+}
diff --git a/script/incdate-0.c b/script/incdate-0.c
new file mode 100644
index 0000000000000000000000000000000000000000..5c54eb2087df82f7b4ddf4fb394cec6fc5899d28
--- /dev/null
+++ b/script/incdate-0.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  d->day = 31;
+  d->month = 1;
+  d->year = 2012;
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  inc_date (&today);
+  printf ("%d.%d.%d\n", today.day, today.month, today.year);
+  return 0;
+}
diff --git a/script/incdate-1.c b/script/incdate-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..df35af04eb9a60e5ce4a23e1ba696c03c43ea445
--- /dev/null
+++ b/script/incdate-1.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  d->day = 31;
+  d->month = 1;
+  d->year = 2012;
+}
+
+void inc_date (date *d)
+{
+  d->day++;  /* FIXME */
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  inc_date (&today);
+  printf ("%d.%d.%d\n", today.day, today.month, today.year);
+  return 0;
+}
diff --git a/script/incdate-2.c b/script/incdate-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..255cae70abca2e526ce4bbe487ee0f5f8fd25580
--- /dev/null
+++ b/script/incdate-2.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  d->day = 31;
+  d->month = 1;
+  d->year = 2012;
+}
+
+void inc_date (date *d)
+{
+  d->day++;
+  if (d->day > 31)  /* FIXME */
+    {
+      d->month++;  /* FIXME */
+      d->day = 1;
+    }
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  inc_date (&today);
+  printf ("%d.%d.%d\n", today.day, today.month, today.year);
+  return 0;
+}
diff --git a/script/incdate-3.c b/script/incdate-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..6ed5cd4190ebbeec448728d7b0cc6778abe63684
--- /dev/null
+++ b/script/incdate-3.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  d->day = 31;
+  d->month = 12;
+  d->year = 2012;
+}
+
+void inc_date (date *d)
+{
+  d->day++;
+  if (d->day > 31)  /* FIXME */
+    {
+      d->month++;
+      d->day = 1;
+      if (d->month > 12)
+        {
+          d->year++;
+          d->month = 1;
+        }
+    }
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  inc_date (&today);
+  printf ("%d.%d.%d\n", today.day, today.month, today.year);
+  return 0;
+}
diff --git a/script/incdate-4.c b/script/incdate-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..86c6e623c566d1cd8f67d3c3268fec016c3c7bbc
--- /dev/null
+++ b/script/incdate-4.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  d->day = 30;
+  d->month = 4;
+  d->year = 2012;
+}
+
+void inc_date (date *d)
+{
+  d->day++;
+  int days_in_month = 31;  /* FIXME */
+  if (d->day > days_in_month)
+    {
+      d->month++;
+      d->day = 1;
+      if (d->month > 12)
+        {
+          d->year++;
+          d->month = 1;
+        }
+    }
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  inc_date (&today);
+  printf ("%d.%d.%d\n", today.day, today.month, today.year);
+  return 0;
+}
diff --git a/script/incdate-5.c b/script/incdate-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..e97980c292d7d25c2a30beb74b5a390e67768720
--- /dev/null
+++ b/script/incdate-5.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  d->day = 30;
+  d->month = 4;
+  d->year = 2012;
+}
+
+void inc_date (date *d)
+{
+  d->day++;
+  int days_in_month = 31;
+  if (d->month == 2)
+    days_in_month = 28;  /* FIXME */
+  else if (d->month == 4 || d->month == 6 || d->month == 9 || d->month == 11)
+    days_in_month = 30;
+  if (d->day > days_in_month)
+    {
+      d->month++;
+      d->day = 1;
+      if (d->month > 12)
+        {
+          d->year++;
+          d->month = 1;
+        }
+    }
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  inc_date (&today);
+  printf ("%d.%d.%d\n", today.day, today.month, today.year);
+  return 0;
+}
diff --git a/script/incdate-6.c b/script/incdate-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..1ce6f6a8a6a64d5ea0d81b048a6287e901ba3ae3
--- /dev/null
+++ b/script/incdate-6.c
@@ -0,0 +1,50 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  d->day = 28;
+  d->month = 2;
+  d->year = 2012;
+}
+
+void inc_date (date *d)
+{
+  d->day++;
+  int days_in_month = 31;
+  if (d->month == 2)
+    {
+      int is_leap_year = 1;  /* FIXME */
+      if (is_leap_year)
+        days_in_month = 29;
+      else
+        days_in_month = 28;
+    }
+  else if (d->month == 4 || d->month == 6 || d->month == 9 || d->month == 11)
+    days_in_month = 30;
+  if (d->day > days_in_month)
+    {
+      d->month++;
+      d->day = 1;
+      if (d->month > 12)
+        {
+          d->year++;
+          d->month = 1;
+        }
+    }
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  inc_date (&today);
+  printf ("%d.%d.%d\n", today.day, today.month, today.year);
+  return 0;
+}
diff --git a/script/incdate-7.c b/script/incdate-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..983c0fdbe8de409f38006c1507cde49727e5102c
--- /dev/null
+++ b/script/incdate-7.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  d->day = 28;
+  d->month = 2;
+  d->year = 2012;
+}
+
+void inc_date (date *d)
+{
+  d->day++;
+  int days_in_month = 31;
+  if (d->month == 2)
+    {
+      int is_leap_year = 0;
+      if (d->year % 4 == 0)
+        is_leap_year = 1;  /* FIXME */
+      if (is_leap_year)
+        days_in_month = 29;
+      else
+        days_in_month = 28;
+    }
+  else if (d->month == 4 || d->month == 6 || d->month == 9 || d->month == 11)
+    days_in_month = 30;
+  if (d->day > days_in_month)
+    {
+      d->month++;
+      d->day = 1;
+      if (d->month > 12)
+        {
+          d->year++;
+          d->month = 1;
+        }
+    }
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  inc_date (&today);
+  printf ("%d.%d.%d\n", today.day, today.month, today.year);
+  return 0;
+}
diff --git a/script/incdate-8.c b/script/incdate-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..b8d4d5fe2b4d1766b66e4f7ec0aad0c273902f93
--- /dev/null
+++ b/script/incdate-8.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  d->day = 28;
+  d->month = 2;
+  d->year = 2100;
+}
+
+void inc_date (date *d)
+{
+  d->day++;
+  int days_in_month = 31;
+  if (d->month == 2)
+    {
+      int is_leap_year = 0;
+      if (d->year % 4 == 0)
+        is_leap_year = 1;  /* FIXME */
+      if (is_leap_year)
+        days_in_month = 29;
+      else
+        days_in_month = 28;
+    }
+  else if (d->month == 4 || d->month == 6 || d->month == 9 || d->month == 11)
+    days_in_month = 30;
+  if (d->day > days_in_month)
+    {
+      d->month++;
+      d->day = 1;
+      if (d->month > 12)
+        {
+          d->year++;
+          d->month = 1;
+        }
+    }
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  inc_date (&today);
+  printf ("%d.%d.%d\n", today.day, today.month, today.year);
+  return 0;
+}
diff --git a/script/incdate-9.c b/script/incdate-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..288491ae9feb71fc79d32c2a09c1b34469c1d173
--- /dev/null
+++ b/script/incdate-9.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  d->day = 28;
+  d->month = 2;
+  d->year = 2000;
+}
+
+void inc_date (date *d)
+{
+  d->day++;
+  int days_in_month = 31;
+  if (d->month == 2)
+    {
+      int is_leap_year = 0;
+      if (d->year % 4 == 0)
+        {
+          is_leap_year = 1;
+          if (d->year % 100 == 0)
+            {
+              is_leap_year = 0;
+              if (d->year % 400 == 0)
+                is_leap_year = 1;
+            }
+        }
+      if (is_leap_year)
+        days_in_month = 29;
+      else
+        days_in_month = 28;
+    }
+  else if (d->month == 4 || d->month == 6 || d->month == 9 || d->month == 11)
+    days_in_month = 30;
+  if (d->day > days_in_month)
+    {
+      d->month++;
+      d->day = 1;
+      if (d->month > 12)
+        {
+          d->year++;
+          d->month = 1;
+        }
+    }
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  inc_date (&today);
+  printf ("%d.%d.%d\n", today.day, today.month, today.year);
+  return 0;
+}
diff --git a/script/input-1.c b/script/input-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ed33d5ddcde9772002f639a19ffd6ce105307080
--- /dev/null
+++ b/script/input-1.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int a;
+  printf ("Bitte eine Zahl eingeben: ");
+  scanf ("%d", &a);
+  printf ("Sie haben eingegeben: %d\n", a);
+  return 0;
+}
diff --git a/script/input-2.c b/script/input-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..6b8995d3639f2f34f74ac4b309bcc7be0f895325
--- /dev/null
+++ b/script/input-2.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int a;
+  printf ("Bitte eine Zahl eingeben: ");
+  scanf ("%d", a);
+  printf ("Sie haben eingegeben: %d\n", a);
+  return 0;
+}
diff --git a/script/io-ports-and-interrupts.pdf b/script/io-ports-and-interrupts.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..bcd46f7afb35605b20bdb05637e6de0a039893ec
--- /dev/null
+++ b/script/io-ports-and-interrupts.pdf
@@ -0,0 +1 @@
+../common/io-ports-and-interrupts.pdf
\ No newline at end of file
diff --git a/script/logo-hochschule-bochum-cvh-text-v2.pdf b/script/logo-hochschule-bochum-cvh-text-v2.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..4aa99b8f81061aca6dcaf43eed2d9efef40555f8
--- /dev/null
+++ b/script/logo-hochschule-bochum-cvh-text-v2.pdf
@@ -0,0 +1 @@
+../common/logo-hochschule-bochum-cvh-text-v2.pdf
\ No newline at end of file
diff --git a/script/logo-hochschule-bochum.pdf b/script/logo-hochschule-bochum.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..b6b9491e370e499c9276918182cdb82cb311bcd1
--- /dev/null
+++ b/script/logo-hochschule-bochum.pdf
@@ -0,0 +1 @@
+../common/logo-hochschule-bochum.pdf
\ No newline at end of file
diff --git a/script/loop-1.c b/script/loop-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..8cca7d3e184272d08d3ddebe4c13a5afa7a1cd6e
--- /dev/null
+++ b/script/loop-1.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int i = 1;
+  while (i <= 10)
+    {
+      printf ("%d\n", i);
+      i = i + 1;
+    }
+  return 0;
+}
diff --git a/script/loop-2.c b/script/loop-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..1098615d2ec421e20303e52a73b96b65ec254613
--- /dev/null
+++ b/script/loop-2.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int i;
+  for (i = 1; i <= 10; i = i + 1)
+    printf ("%d\n", i);
+  return 0;
+}
diff --git a/script/loop-3.c b/script/loop-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff95622ceb9310bbc5b1d6c4b71e89ed9b83af68
--- /dev/null
+++ b/script/loop-3.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int i;
+  for (i = 1; 10; i + 1)
+    printf ("%d\n", i);
+  return 0;
+}
diff --git a/script/maerchen.c b/script/maerchen.c
new file mode 100644
index 0000000000000000000000000000000000000000..5c2716e85205136d406ad2e20285c18ddc967c07
--- /dev/null
+++ b/script/maerchen.c
@@ -0,0 +1,4 @@
+Vor langer, langer Zeit
+gab es einmal
+#include "hexe.h"
+Die lebte in einem Wald.
diff --git a/script/mathe-1.c b/script/mathe-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..6a099f1e281242f3d6892e7538dc4b140dc4b861
--- /dev/null
+++ b/script/mathe-1.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("%d\n", 23 + 19);
+  return 0;
+}
diff --git a/script/moon-texture.png b/script/moon-texture.png
new file mode 120000
index 0000000000000000000000000000000000000000..1af16e6965c37de47d65304f0a45287800177f97
--- /dev/null
+++ b/script/moon-texture.png
@@ -0,0 +1 @@
+../common/moon-texture.png
\ No newline at end of file
diff --git a/script/opengl-magic.c b/script/opengl-magic.c
new file mode 100644
index 0000000000000000000000000000000000000000..121353940b3db8bdcc6193ef110aebdd75a0de1a
--- /dev/null
+++ b/script/opengl-magic.c
@@ -0,0 +1,49 @@
+#if defined(__APPLE__) || defined(MACOSX)
+  #include <OpenGL/gl.h>
+  #include <OpenGL/glu.h>
+  #include <GLUT/glut.h>
+#else
+  #include <GL/gl.h>
+  #include <GL/glu.h>
+  #include <GL/glut.h>
+#endif
+
+#include "opengl-magic.h"
+
+void init_opengl (int *argcp, char **argv, char *window_name)
+{
+  glutInit (argcp, argv);
+  glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
+  glutInitWindowSize (1024, 768);
+  glutCreateWindow (window_name);
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  gluPerspective (20.0, -1.33333, 3.0, 7.0);
+  glMatrixMode (GL_MODELVIEW);
+  glLoadIdentity ();
+  glTranslatef (0.0, 0.0, -5.0);
+  glClearColor (0.0, 0.0, 0.0, 0.0);
+  glEnable (GL_DEPTH_TEST);
+  glEnable (GL_LIGHTING);
+  glEnable (GL_LIGHT0);
+  static GLfloat light0_position[] = { 1.0, 0.0, 1.0, 0.0 };
+  glLightfv (GL_LIGHT0, GL_POSITION, light0_position);
+}
+
+void set_material_color (float r, float g, float b)
+{
+  GLfloat color[] = { r, g, b };
+  glMaterialfv (GL_FRONT, GL_AMBIENT, color);
+  glMaterialfv (GL_FRONT, GL_DIFFUSE, color);
+}
+
+#if defined(__APPLE__) || defined(MACOSX)
+
+void glutSolidCylinder (double radius, double height, int slices, int stacks)
+{
+  GLUquadricObj *q = gluNewQuadric ();
+  gluCylinder (q, radius, radius, height, slices, stacks);
+  gluDeleteQuadric (q);
+}
+
+#endif
diff --git a/script/opengl-magic.h b/script/opengl-magic.h
new file mode 100644
index 0000000000000000000000000000000000000000..afa963a5fab8ac6ba323f724c0dcb51a995a76aa
--- /dev/null
+++ b/script/opengl-magic.h
@@ -0,0 +1,11 @@
+#ifndef OPENGL_MAGIC_H
+#define OPENGL_MAGIC_H
+
+extern void init_opengl (int *argcp, char **argv, char *window_name);
+extern void set_material_color (float r, float g, float b);
+
+#ifdef __MACOSX__
+  extern void glutSolidCylinder (double radius, double height, int slices, int stacks);
+#endif
+
+#endif /* OPENGL_MAGIC_H */
diff --git a/script/orbit-1.c b/script/orbit-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1f963cf44d937ba0627d7bc224930a7bcd39d27b
--- /dev/null
+++ b/script/orbit-1.c
@@ -0,0 +1,59 @@
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#include "opengl-magic.h"
+#include "textured-spheres.h"
+
+float t = 0.0;
+GLuint earth_texture, moon_texture;
+
+void draw_earth (void)
+{
+  glPushMatrix ();
+  glRotatef (90, 1.0, 0.0, 0.0);
+  glRotatef (100.0 * t, 0.0, 0.0, 1.0);
+  draw_textured_sphere (earth_texture, 0.25512, 63, 20);
+  glPopMatrix ();
+}
+
+void draw_moon (void)
+{
+  glPushMatrix ();
+  glRotatef (90, 1.0, 0.0, 0.0);
+  glRotatef (-90, 0.0, 0.0, 1.0);
+  draw_textured_sphere (moon_texture, 0.06952, 31, 10);
+  glPopMatrix ();
+}
+
+void draw (void)
+{
+  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  glPushMatrix ();
+  glRotatef (23.44, 1.0, 0.0, -1.0);
+  draw_earth ();
+  glRotatef (5.145, 0.0, 1.0, 1.0);
+  glRotatef (30.0 * t, 0.0, -1.0, 0.0);
+  glTranslatef (0.9, 0.0, 0.0);
+  draw_moon ();
+  glPopMatrix ();
+  glFlush ();
+  glutSwapBuffers ();
+}
+
+void timer_handler (int value)
+{
+  t += 0.05;
+  glutPostRedisplay ();
+  glutTimerFunc (50, timer_handler, 0);
+}
+
+int main (int argc, char **argv)
+{
+  init_opengl (&argc, argv, "Orbit");
+  init_texture ("earth-texture.png", &earth_texture);
+  init_texture ("moon-texture.png", &moon_texture);
+  glutDisplayFunc (draw);
+  glutTimerFunc (50, timer_handler, 0);
+  glutMainLoop ();
+  return 0;
+}
diff --git a/script/output-1.c b/script/output-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..d4f8b191d6d4491df2661046ce99c21ec2045a60
--- /dev/null
+++ b/script/output-1.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf (42);
+  return 0;
+}
diff --git a/script/output-2.c b/script/output-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..8df53c4c95e8c3ae959324a1b7fa4f058aafc7ef
--- /dev/null
+++ b/script/output-2.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Die Antwort lautet: %d\n", 42);
+  return 0;
+}
diff --git a/script/output-3.c b/script/output-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..d099c14a9d196ed21cf3bd07945b59221eccebcb
--- /dev/null
+++ b/script/output-3.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Richtige Antworten wären %d oder %d oder sonstige.\n", 1, 2);
+  return 0;
+}
diff --git a/script/output-4.c b/script/output-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..9f2674e21e43a2566d9c4f4f0548af05801c6a7b
--- /dev/null
+++ b/script/output-4.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Richtige Antworten wären %d", 1, " oder %d", 2, " oder sonstige.\n");
+  return 0;
+}
diff --git a/script/params-1.c b/script/params-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e6e64ba029e1042aff60960fc8b7c3d4d5d8e2e2
--- /dev/null
+++ b/script/params-1.c
@@ -0,0 +1,9 @@
+#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;
+}
diff --git a/script/params-2.c b/script/params-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..d4ac6da31fe8138bf4b42326445a1ea2e2684a7d
--- /dev/null
+++ b/script/params-2.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main (int argc, char **argv)
+{
+  printf ("argc = %d\n", argc);
+  for (int i = 0; argv[i] != NULL; i++)
+    printf ("argv[%d] = \"%s\"\n", i, argv[i]);
+  return 0;
+}
diff --git a/script/params-3.c b/script/params-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..412c451645508ecd8e65c695f47b8ffb822657a2
--- /dev/null
+++ b/script/params-3.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main (int argc, char **argv)
+{
+  printf ("argc = %d\n", argc);
+  for (char **p = argv; *p; p++)
+    printf ("argv[p] = \"%s\"\n", *p);
+  return 0;
+}
diff --git a/script/pgscript.sty b/script/pgscript.sty
new file mode 120000
index 0000000000000000000000000000000000000000..95c888478c99ea7fda0fd11ccf669ae91be7178b
--- /dev/null
+++ b/script/pgscript.sty
@@ -0,0 +1 @@
+../common/pgscript.sty
\ No newline at end of file
diff --git a/script/pgslides.sty b/script/pgslides.sty
new file mode 120000
index 0000000000000000000000000000000000000000..5be1416f4216f076aa268901f52a15d775e43f64
--- /dev/null
+++ b/script/pgslides.sty
@@ -0,0 +1 @@
+../common/pgslides.sty
\ No newline at end of file
diff --git a/script/philosophy.c b/script/philosophy.c
new file mode 100644
index 0000000000000000000000000000000000000000..e9f508a501d9ec66d02e0636a9f6c71f2c7a8594
--- /dev/null
+++ b/script/philosophy.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include "answer.h"
+
+int main (void)
+{
+  printf ("The answer is %d.\n", answer ());
+  return 0;
+}
diff --git a/script/pointers-1.c b/script/pointers-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..3bd2e86c08fbe05eb8eb9b42d886e30f8f0be286
--- /dev/null
+++ b/script/pointers-1.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+void calc_answer (int *a)
+{
+  *a = 42;
+}
+
+int main (void)
+{
+  int answer;
+  calc_answer (&answer);
+  printf ("The answer is %d.\n", answer);
+  return 0;
+}
diff --git a/script/qsort-1.c b/script/qsort-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..c5431b853862e62812016f4fd3a031eeb0b5c9df
--- /dev/null
+++ b/script/qsort-1.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, char *pivot, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (name[i] == pivot)
+        printf (" <==");
+      else if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, char *pivot, int left, int right)
+{
+  int result = strcmp (name[left], pivot);
+  comparisons++;
+  display (name, pivot, left, right);
+  usleep (200000);
+  return result;
+}
+
+void quicksort (char **name, int left, int right)
+{
+  int p = (left + right) / 2;
+  char *pivot = name[p];
+  int l = left;
+  int r = right;
+  while (l < r)
+    {
+      while (l < r && compare (name, pivot, l, r - 1) < 0)
+        l++;
+      while (l < r && compare (name, pivot, r - 1, l) > 0)
+        r--;
+      if (l < r)
+        {
+          char *temp = name[r - 1];
+          name[r - 1] = name[l];
+          name[l] = temp;
+          l++;
+          r--;
+        }
+    }
+}
+
+void sort (char **name)
+{
+  int r = 0;
+  while (name[r])
+    r++;
+  quicksort (name, 0, r);
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  sort (name);
+  display (name, NULL, -1, -1);
+  return 0;
+}
diff --git a/script/qsort-2.c b/script/qsort-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..cfdc2ec11a92a4292c9443e01453cce818e9e73a
--- /dev/null
+++ b/script/qsort-2.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, char *pivot, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (name[i] == pivot)
+        printf (" <==");
+      else if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, char *pivot, int left, int right)
+{
+  int result = strcmp (name[left], pivot);
+  comparisons++;
+  display (name, pivot, left, right);
+  usleep (200000);
+  return result;
+}
+
+void quicksort (char **name, int left, int right)
+{
+  int p = (left + right) / 2;
+  char *pivot = name[p];
+  int l = left;
+  int r = right;
+  while (l < r)
+    {
+      while (l < r && compare (name, pivot, l, r - 1) < 0)
+        l++;
+      while (l < r && compare (name, pivot, r - 1, l) > 0)
+        r--;
+      if (l < r)
+        {
+          char *temp = name[r - 1];
+          name[r - 1] = name[l];
+          name[l] = temp;
+          l++;
+          r--;
+        }
+    }
+  if (l < right)
+    quicksort (name, l, right);
+}
+
+void sort (char **name)
+{
+  int r = 0;
+  while (name[r])
+    r++;
+  quicksort (name, 0, r);
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  sort (name);
+  display (name, NULL, -1, -1);
+  return 0;
+}
diff --git a/script/qsort-3.c b/script/qsort-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..e6b7d9909473af6d8c13d3745dc6b07e8ea75699
--- /dev/null
+++ b/script/qsort-3.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, char *pivot, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (name[i] == pivot)
+        printf (" <==");
+      else if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, char *pivot, int left, int right)
+{
+  int result = strcmp (name[left], pivot);
+  comparisons++;
+  display (name, pivot, left, right);
+  usleep (200000);
+  return result;
+}
+
+void quicksort (char **name, int left, int right)
+{
+  int p = (left + right) / 2;
+  char *pivot = name[p];
+  int l = left;
+  int r = right;
+  while (l < r)
+    {
+      while (l < r && compare (name, pivot, l, r - 1) < 0)
+        l++;
+      while (l < r && compare (name, pivot, r - 1, l) > 0)
+        r--;
+      if (l < r)
+        {
+          char *temp = name[r - 1];
+          name[r - 1] = name[l];
+          name[l] = temp;
+          l++;
+          r--;
+        }
+    }
+  if (r > left)
+    quicksort (name, left, r);
+  if (l < right)
+    quicksort (name, l, right);
+}
+
+void sort (char **name)
+{
+  int r = 0;
+  while (name[r])
+    r++;
+  quicksort (name, 0, r);
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  sort (name);
+  display (name, NULL, -1, -1);
+  return 0;
+}
diff --git a/script/sfmath.sty b/script/sfmath.sty
new file mode 120000
index 0000000000000000000000000000000000000000..599e505416fb5a096f751581a66c53bc109e935d
--- /dev/null
+++ b/script/sfmath.sty
@@ -0,0 +1 @@
+../common/sfmath.sty
\ No newline at end of file
diff --git a/script/sort-0.c b/script/sort-0.c
new file mode 100644
index 0000000000000000000000000000000000000000..70e0e717cbfd42a27bf90f419c216fa18b0783c7
--- /dev/null
+++ b/script/sort-0.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+int find_first (char **name)
+{
+  return 2;
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  int first = find_first (name);
+  printf ("%s\n", name[first]);
+  return 0;
+}
diff --git a/script/sort-1.c b/script/sort-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..3f009d45657f84e462db48a67fa22821819216ad
--- /dev/null
+++ b/script/sort-1.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <string.h>
+
+int find_first (char **name)
+{
+  int first = 0;
+  for (int i = 1; name[i]; i++)
+    if (strcmp (name[i], name[first]) < 0)
+      first = i;
+  return first;
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  int first = find_first (name);
+  printf ("%s\n", name[first]);
+  return 0;
+}
diff --git a/script/sort-2.c b/script/sort-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..638e6e2caa670ceace0a854d0827292dfcb59ca5
--- /dev/null
+++ b/script/sort-2.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, int left, int right)
+{
+  int result = strcmp (name[left], name[right]);
+  comparisons++;
+  display (name, left, right);
+  usleep (200000);
+  return result;
+}
+
+int find_first (char **name)
+{
+  int first = 0;
+  for (int i = 1; name[i]; i++)
+    if (compare (name, i, first) < 0)
+      first = i;
+  return first;
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  int first = find_first (name);
+  display (name, first, -1);
+  return 0;
+}
diff --git a/script/sort-3.c b/script/sort-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..430a6fc0e95fcb9bc225e3572566c8d187016130
--- /dev/null
+++ b/script/sort-3.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, int left, int right)
+{
+  int result = strcmp (name[left], name[right]);
+  comparisons++;
+  display (name, left, right);
+  usleep (200000);
+  return result;
+}
+
+int find_first (char **name, int i0)
+{
+  int first = i0;
+  for (int i = i0 + 1; name[i]; i++)
+    if (compare (name, i, first) < 0)
+      first = i;
+  return first;
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  int first = find_first (name, 0);
+  display (name, first, -1);
+  return 0;
+}
diff --git a/script/sort-4.c b/script/sort-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..19d4f416a2d30c5181ad289fe1d0dcba91ee81cf
--- /dev/null
+++ b/script/sort-4.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, int left, int right)
+{
+  int result = strcmp (name[left], name[right]);
+  comparisons++;
+  display (name, left, right);
+  usleep (200000);
+  return result;
+}
+
+int find_first (char **name, int i0)
+{
+  int first = i0;
+  for (int i = i0 + 1; name[i]; i++)
+    if (compare (name, i, first) < 0)
+      first = i;
+  return first;
+}
+
+void sort (char **name)
+{
+  int sorted = 0;
+  while (name[sorted])
+    {
+      int first = find_first (name, sorted);
+      char *temp = name[sorted];
+      name[sorted] = name[first];
+      name[first] = temp;
+      sorted++;
+    }
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  sort (name);
+  display (name, -1, -1);
+  return 0;
+}
diff --git a/script/sort-5.c b/script/sort-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..f0742bc8665d0b13edf4ad4ad3fe4790c1e6b929
--- /dev/null
+++ b/script/sort-5.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, int left, int right)
+{
+  int result = strcmp (name[left], name[right]);
+  comparisons++;
+  display (name, left, right);
+  usleep (200);
+  return result;
+}
+
+int find_first (char **name, int i0)
+{
+  int first = i0;
+  for (int i = i0 + 1; name[i]; i++)
+    if (compare (name, i, first) < 0)
+      first = i;
+  return first;
+}
+
+void sort (char **name)
+{
+  int sorted = 0;
+  while (name[sorted])
+    {
+      int first = find_first (name, sorted);
+      char *temp = name[sorted];
+      name[sorted] = name[first];
+      name[first] = temp;
+      sorted++;
+    }
+}
+
+int main (void)
+{
+  char *name[] = {
+                   #include "names.h"
+                   NULL
+                 };
+  sort (name);
+  display (name, -1, -1);
+  return 0;
+}
diff --git a/script/sort-6.c b/script/sort-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..94a1a16abfacda7bb728f8d3317cd00b4cf8ccde
--- /dev/null
+++ b/script/sort-6.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, int left, int right)
+{
+  int result = strcmp (name[left], name[right]);
+  comparisons++;
+//  display (name, left, right);
+//  usleep (200);
+  return result;
+}
+
+int find_first (char **name, int i0)
+{
+  int first = i0;
+  for (int i = i0 + 1; name[i]; i++)
+    if (compare (name, i, first) < 0)
+      first = i;
+  return first;
+}
+
+void sort (char **name)
+{
+  int sorted = 0;
+  while (name[sorted])
+    {
+      int first = find_first (name, sorted);
+      char *temp = name[sorted];
+      name[sorted] = name[first];
+      name[first] = temp;
+      sorted++;
+    }
+}
+
+int main (void)
+{
+  char *name[] = {
+                   #include "names.h"
+                   NULL
+                 };
+  sort (name);
+  display (name, -1, -1);
+  return 0;
+}
diff --git a/script/sort-7.c b/script/sort-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..46132dd247a061dda0e5ebade9c5b818a1a74fcb
--- /dev/null
+++ b/script/sort-7.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int comparisons = 0;
+
+void display (char **name, int left, int right)
+{
+  printf ("\e[H\e[J");
+  for (int i = 0; name[i]; i++)
+    {
+      printf ("%s", name[i]);
+      if (i == left || i == right)
+        printf (" <--");
+      printf ("\n");
+    }
+  printf ("%d\n", comparisons);
+}
+
+int compare (char **name, int left, int right)
+{
+  int result = strcmp (name[left], name[right]);
+  comparisons++;
+  display (name, left, right);
+  usleep (200000);
+  return result;
+}
+
+void sort (char **name)
+{
+  int sorted = 0;
+  while (name[sorted])
+    {
+      int first = sorted;
+      for (int i = sorted + 1; name[i]; i++)
+        if (compare (name, i, first) < 0)
+          first = i;
+      char *temp = name[sorted];
+      name[sorted] = name[first];
+      name[first] = temp;
+      sorted++;
+    }
+}
+
+int main (void)
+{
+  char *name[] = { "Otto", "Lisa", "Anna", "Heinrich", "Siegfried", "Peter",
+                   "Dieter", "Hugo", "Berta", "Maria", "Fritz", "Box", "Hans",
+                   "Thomas", "Ulrich", "Zacharias", NULL };
+  sort (name);
+  display (name, -1, -1);
+  return 0;
+}
diff --git a/script/statements-1.c b/script/statements-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..92514b3c0bcccc1ff4eb032037407a122a2b02e8
--- /dev/null
+++ b/script/statements-1.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  2 + 2;
+  return 0;
+}
diff --git a/script/statements-2.c b/script/statements-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..475bce5c85b75e4e57d0d1fee9179daaf6647dbf
--- /dev/null
+++ b/script/statements-2.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main (void)
+{
+  int x;
+  x = printf ("%d\n", 2 + 2);
+  printf ("%d\n", x);
+  return 0;
+}
diff --git a/script/strings-1.c b/script/strings-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..d06457baea6cca1429b4c37026c8af1a8500a676
--- /dev/null
+++ b/script/strings-1.c
@@ -0,0 +1,10 @@
+#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;
+}
diff --git a/script/strings-2.c b/script/strings-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..4128aea3e056e146850c1b7ded7a7a2e16dbfcba
--- /dev/null
+++ b/script/strings-2.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+int main (void)
+{
+  char hello_world[] = "Hello, world!\n";
+  int i = 0;
+  while (hello_world[i] != 0)
+    printf ("%c", hello_world[i++]);
+  return 0;
+}
diff --git a/script/strings-3.c b/script/strings-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..a2e12ba883dc8e7f16dbc53319566c5b942bc791
--- /dev/null
+++ b/script/strings-3.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+int main (void)
+{
+  char hello_world[] = "Hello, world!\n";
+  char *p = hello_world;
+  while (*p)
+    printf ("%c", *p++);
+  return 0;
+}
diff --git a/script/strings-4.c b/script/strings-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..dc9602c6d3ea235a66f167b3db1c345aad181a2c
--- /dev/null
+++ b/script/strings-4.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int main (void)
+{
+  char *p = "Hello, world!";
+  printf ("%s\n", p);
+  return 0;
+}
diff --git a/script/structs-1.c b/script/structs-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1cc76786c7595897b141cf492d9ac747e19bb000
--- /dev/null
+++ b/script/structs-1.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+int main (void)
+{
+  date today = { 1, 11, 2016 };
+  printf ("%d.%d.%d\n", today.day, today.month, today.year);
+  return 0;
+}
diff --git a/script/structs-2.c b/script/structs-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..9bfa4cbfb321487fbeed8022de0c027ab7e468e2
--- /dev/null
+++ b/script/structs-2.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  (*d).day = 1;
+  (*d).month = 11;
+  (*d).year = 2016;
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  printf ("%d.%d.%d\n", today.day,
+          today.month, today.year);
+  return 0;
+}
diff --git a/script/structs-3.c b/script/structs-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..2abdd1fb052263976666b9a8bdf0646871936b47
--- /dev/null
+++ b/script/structs-3.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+
+typedef struct
+{
+  char day, month;
+  int year;
+}
+date;
+
+void set_date (date *d)
+{
+  d->day = 1;
+  d->month = 11;
+  d->year = 2016;
+}
+
+int main (void)
+{
+  date today;
+  set_date (&today);
+  printf ("%d.%d.%d\n", today.day,
+          today.month, today.year);
+  return 0;
+}
diff --git a/script/textured-spheres.c b/script/textured-spheres.c
new file mode 100644
index 0000000000000000000000000000000000000000..aee3dc199ab3bd0c85c63d22e5cfdc9456ca2188
--- /dev/null
+++ b/script/textured-spheres.c
@@ -0,0 +1,168 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <png.h>
+#include "textured-spheres.h"
+
+#ifndef __USE_POSIX
+  extern int fileno (FILE *stream);
+#endif
+
+static png_byte *load_png_file (char *filename, unsigned *w, unsigned *h)
+{
+  FILE *f = fopen (filename, "rb");
+  if (!f)
+    return NULL;
+
+  /* is it a PNG file? */
+  png_byte buf[8];
+  if (fread (buf, 1, 8, f) != 8)
+    {
+      fclose (f);
+      return NULL;
+    }
+  if (!png_check_sig (buf, 8))
+    {
+      fclose (f);
+      return NULL;
+    }
+
+  png_struct *png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
+                                                NULL, NULL, NULL);
+  if (!png_ptr)
+    {
+      fclose (f);
+      return NULL;
+    }
+
+  png_info *info_ptr = png_create_info_struct (png_ptr);
+  if (!info_ptr)
+    {
+      fclose (f);
+      png_destroy_read_struct (&png_ptr, NULL, NULL);
+      return NULL;
+    }
+
+  if (setjmp (png_jmpbuf (png_ptr)))
+    {
+      fclose (f);
+      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+      return NULL;
+    }
+
+  png_init_io (png_ptr, f);
+  png_set_sig_bytes (png_ptr, 8);
+  png_read_info (png_ptr, info_ptr);
+
+  png_uint_32 width;
+  png_uint_32 height;
+  int bit_depth;
+  int color_type;
+  png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth,
+                &color_type, NULL, NULL, NULL);
+
+  /* tell libpng to strip 16 bit/color files down to 8 bits/color */
+  if (bit_depth == 16)
+    png_set_strip_16 (png_ptr);
+  /* expand paletted colors into true RGB triplets */
+  if (color_type == PNG_COLOR_TYPE_PALETTE)
+    png_set_expand (png_ptr);
+  /* expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
+  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+    png_set_expand (png_ptr);
+  /* expand paletted or RGB images with transparency to full alpha channels
+     so the data will be available as RGBA quartets. */
+  if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
+    png_set_expand (png_ptr);
+  /* transform grayscale images into rgb */
+  if (color_type == PNG_COLOR_TYPE_GRAY
+      || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+    png_set_gray_to_rgb (png_ptr);
+
+  if (color_type & PNG_COLOR_MASK_ALPHA)
+    png_set_strip_alpha (png_ptr);
+
+  png_read_update_info (png_ptr, info_ptr);
+  png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth,
+		&color_type, NULL, NULL, NULL);
+  if (color_type != PNG_COLOR_TYPE_RGB
+      && color_type != PNG_COLOR_TYPE_RGB_ALPHA)
+    {
+      fclose (f);
+      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+      return NULL;
+    }
+
+  png_uint_32 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
+  if (row_bytes & 0x01)
+    row_bytes++;
+
+  png_byte *png_pixels = malloc (row_bytes * height * sizeof (png_byte));
+  if (png_pixels == NULL)
+    {
+      fclose (f);
+      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+      return NULL;
+    }
+
+  png_byte **row_pointers = malloc (height * sizeof (png_bytep));
+  if (row_pointers == NULL)
+    {
+      fclose (f);
+      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+      free (png_pixels);
+      png_pixels = NULL;
+      return NULL;
+    }
+
+  int i;
+  for (i = 0; i < height; i++)
+    row_pointers[i] = png_pixels + i * row_bytes;
+
+  png_read_image (png_ptr, row_pointers);
+
+  png_read_end (png_ptr, info_ptr);
+  png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+  fclose (f);
+
+  if (w)
+    *w = width;
+  if (h)
+    *h = height;
+  free (row_pointers);
+
+  return png_pixels;
+}
+
+void init_texture (char *image_filename, GLuint *texture)
+{
+  unsigned image_width, image_height;
+  png_byte *image = load_png_file (image_filename, &image_width, &image_height);
+  if (!image)
+    {
+      fprintf (stderr, "textured-spheres.c: cannot open texture file \"%s\"",
+               image_filename);
+      exit (1);
+    }
+  glGenTextures (1, texture);
+  glBindTexture (GL_TEXTURE_2D, *texture);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+  glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+  gluBuild2DMipmaps (GL_TEXTURE_2D, 3, image_width, image_height, GL_RGB, GL_UNSIGNED_BYTE, image);
+}
+
+void draw_textured_sphere (GLuint texture, GLdouble radius, GLint slices, GLint stacks)
+{
+  static GLfloat white_color[] = { 1.0, 1.0, 1.0 };
+  glMaterialfv (GL_FRONT, GL_AMBIENT, white_color);
+  glMaterialfv (GL_FRONT, GL_DIFFUSE, white_color);
+  glBindTexture (GL_TEXTURE_2D, texture);
+  glEnable (GL_TEXTURE_2D);
+  GLUquadric *sphere = gluNewQuadric ();
+  gluQuadricTexture (sphere, GL_TRUE);
+  gluSphere (sphere, radius, slices, stacks);
+  glDisable (GL_TEXTURE_2D);
+}
diff --git a/script/textured-spheres.h b/script/textured-spheres.h
new file mode 100644
index 0000000000000000000000000000000000000000..aa2fb4f4f6d609bbab3f524069cac8a56636c712
--- /dev/null
+++ b/script/textured-spheres.h
@@ -0,0 +1,10 @@
+#ifndef TEXTURED_SPHERES_H
+#define TEXTURED_SPHERES_H
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+extern void init_texture (char *image_filename, GLuint *texture);
+extern void draw_textured_sphere (GLuint texture, GLdouble radius, GLint slices, GLint stacks);
+
+#endif /* TEXTURED_SPHERES_H */
diff --git a/update b/update
new file mode 100755
index 0000000000000000000000000000000000000000..c7d95a3a86107178f7d2dba4d604abb538851742
--- /dev/null
+++ b/update
@@ -0,0 +1,188 @@
+#!/bin/bash
+
+sem=2020ws
+course=hp
+date_mask="20[12][0-9][01][0-9][0-3][0-9]"
+
+time_mask="[0-2][0-9][0-5][0-9][0-5][0-9]"
+base_url="https://gitlab.cvh-server.de/pgerwinski/$course/tree/master/"
+raw_base_url="https://gitlab.cvh-server.de/pgerwinski/$course/raw/master/"
+pattern="README:"
+
+if [ "$1" = "--no-slides" ]; then
+  shift
+else
+  slides_tex_file="$course-slides-$sem.tex"
+  cat > "$slides_tex_file" << EOF
+\documentclass{article}
+
+\usepackage[final]{pdfpages}
+\usepackage[paperwidth=363pt,paperheight=272pt]{geometry}
+\usepackage{hyperref}
+
+\pagestyle{empty}
+
+\begin{document}
+  \includepdf[pages=1]{script/$course-slides-title-$sem.pdf}
+  \pdfbookmark[1]{Wichtiger Hinweis}{Hinweis}
+  \includepdf[pages=2-]{script/$course-slides-title-$sem.pdf}
+EOF
+
+  for x in $date_mask/$course-$date_mask.pdf; do
+    f=$(echo $x | cut -d '/' -f 1)
+    y=$(echo $f | cut -b 1-4)
+    m=$(echo $f | cut -b 5-6)
+    d=$(echo $f | cut -b 7-8)
+    date="$d.$m.$y"
+    src=$(echo $x | sed -e 's/\.pdf$/.tex/')
+    description=$(grep -m 1 "$pattern" "$src" | sed -e "s/^.*$pattern *//")
+    echo "  \pdfbookmark[1]{$date: $description}{$f}" >> "$slides_tex_file"
+    echo "  \includepdf[pages=-]{$x}" >> "$slides_tex_file"
+  done
+
+  echo '\end{document}' >> "$slides_tex_file"
+
+  lualatex -interaction batchmode "$slides_tex_file" \
+    && echo \
+    && lualatex -interaction batchmode "$slides_tex_file" \
+    || {
+         echo
+         echo "$0: error compiling $slides_tex_file"
+         exit 1
+       }
+  echo
+fi
+
+# if pdfjam --papersize "{362.835pt,272.126pt}" -o hp-slides-$sem.pdf \
+#    $date_mask/hp-$date_mask.pdf > /dev/null 2> pdfjam.err; then
+#   rm pdfjam.err
+# else
+#   cat pdfjam.err
+#   rm pdfjam.err
+#   exit 1
+# fi
+
+readme_old=README.md
+readme=README-NEW.md
+
+collect ()
+{
+  if [ "$1" = "--with-examples" ]; then
+    with_examples=true
+    shift
+  else
+    with_examples=false
+  fi
+  if [ "$1" = "--no-date" ]; then
+    show_date=false
+    shift
+  else
+    show_date=true
+  fi
+  headline="$1"; shift
+  source_suffix="$1"; shift
+  target_suffix="$1"; shift
+  underline=$(echo "$headline" | sed -e 's/./-/g')
+  echo >> $readme
+  echo "$headline" >> $readme
+  echo "$underline" >> $readme
+  for f in "$@"; do
+    if [ -f "$f" ]; then
+      description=$(grep -m 1 "$pattern" "$f" | sed -e "s/^.*$pattern *//")
+      if $show_date; then
+        y=$(echo $f | cut -b 1-4)
+        m=$(echo $f | cut -b 5-6)
+        d=$(echo $f | cut -b 7-8)
+        date="$d.$m.$y: "
+      else
+        date=""
+      fi
+      url="$raw_base_url"$(echo $f | sed -e "s/\.$source_suffix$/.$target_suffix/")
+      if $with_examples; then
+        example_url="$base_url"$(echo $f | sed -e "s,/[^/]*$,/,")
+        echo " * [$date$description]($url) [**(Beispiele)**]($example_url)" >> $readme
+      else
+        echo " * [$date$description]($url)" >> $readme
+      fi
+    else
+      return 1
+    fi
+  done
+}
+
+cat > $readme << EOF
+Hardwarenahe Programmierung
+===========================
+
+Lehrveranstaltung im Wintersemester 2020/21  
+Hochschule Bochum, Campus Velbert/Heiligenhaus  
+Prof. Dr. rer. nat. Peter Gerwinski
+
+Copyright © 2012–2020  Peter Gerwinski
+
+**Diese Lehrmaterialien sind freie Software.**  
+Sie dürfen diese gemäß den jeweils angegebenen Lizenzen  
+([CC-BY-SA 3.0](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/CC-BY-SA-3.0),
+[GNU GPL 3+](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/GNU-GPL-3),
+[modified BSD License](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/BSD-MODIFIED))  
+studieren, kopieren, modifizieren und/oder weitergeben.  
+Für Details siehe [common/README](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/README).
+EOF
+
+collect --with-examples "Vortragsfolien und Beispiele:" tex pdf $date_mask/hp-$date_mask.tex $date_mask/verschluesselung-$date_mask.tex
+
+cat >> $readme << EOF
+ * [alle in 1 Datei](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/hp-slides-$sem.pdf)
+EOF
+
+collect "Übungsaufgaben:" tex pdf $date_mask/hp-uebung-$date_mask.tex
+collect "Musterlösungen:" tex pdf $date_mask/hp-musterloesung-$date_mask.tex || echo "(keine)" >> $readme
+collect "Tafelbilder:" txt jpg $date_mask/photo-$date_mask-$time_mask.txt || echo "(keine)" >> $readme
+collect --no-date "Praktikumsunterlagen:" tex pdf $date_mask/hp-$sem-p[1-4].tex || echo "(keine)" >> $readme
+collect --with-examples --no-date "Alte Klausuren:" tex pdf exams/$date_mask/*-klausur-$date_mask.tex >> $readme
+
+cat >> $readme << EOF
+
+Skript:
+-------
+ * [Hardwarenahe Programmierung](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/script/hp-$sem.pdf)
+
+Original-Materialien einschließlich Beispiel-Programme und LaTeX-Quelltexte:
+----------------------------------------------------------------------------
+ * [common – gemeinsame Dateien für Skript und Vortragsfolien](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/common)
+ * [script – Skript zur Lehrveranstaltung](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/script)
+ * [201????? – Vortragsfolien und Beispiele](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master)
+ * [branch 2018ws – vollständige Lehrmaterialien vom Wintersemester 2018/19](https://gitlab.cvh-server.de/pgerwinski/hp/tree/2018ws)
+
+
+Low-Level Programming
+=====================
+
+Course in winter semester 2020-21
+Bochum University of Applied Sciences, Campus Velbert/Heiligenhaus  
+Prof. Dr. rer. nat. Peter Gerwinski
+
+Copyright © 2012–2020  Peter Gerwinski
+
+**These teaching materials are Free Software.**  
+You may study, copy, modify, and/or distribute them  
+according to their respective licences  
+([CC-BY-SA 3.0](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/CC-BY-SA-3.0),
+[GNU GPL 3+](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/GNU-GPL-3),
+[modified BSD License](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/BSD-MODIFIED)).  
+See the file [common/README](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/common/README) for details.
+
+ * [common – common files for lecture notes and slides](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/common)
+ * [script – lecture notes](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master/script)
+ * [201????? – slides and examples](https://gitlab.cvh-server.de/pgerwinski/hp/tree/master)
+ * [hp-slides-2020ws.pdf – all slides in 1 file](https://gitlab.cvh-server.de/pgerwinski/hp/raw/master/hp-slides-2020ws.pdf)
+ * [branch 2018ws – complete teaching materials from winter semester 2018–19](https://gitlab.cvh-server.de/pgerwinski/hp/tree/2018ws)
+EOF
+
+if diff -wu $readme_old $readme; then
+  rm $readme
+else
+  echo -n "Press ENTER to overwrite $readme_old, ^C to abort (keeping $readme) "
+  read junk
+  mv $readme $readme_old
+fi