Unterrichtsmaterial

Table of Contents

1. Pflichtfach Informatik

1.1. Block 1 - Robotik / Algorithmen

1.1.1. Algorithmus

  • Eine definierte, endliche abfolge von Anweisungen

1.1.2. Schleifen

  • Ein Werkzeug, womit man Algorithmen beliebig oft wiederholen kann.

1.1.3. If-Abfragen

  • Ein Werkzeug, womit man Algorithmen basierend auf Zustände kontrollieren kann. Z.B. wenn irgendwas, dann mach das. Wenn nicht, mach was anderes.

1.1.4. Funktionen

  • Ein von dem Benutzer selbst definierter Block, wodurch man Coderepetition vermeiden und die Übersichtlichkeit verbessern kann.

1.2. Block 2 - Rechnernetzte

1.2.1. IP-Adresse (Internet Protocol Address)

  • Eindeutige Adresse für jedes Gerät im Internet oder Netzwerk
  • Funktioniert wie eine Postanschrift/Adresse/Hausnummer für Computer
  • Besteht aus vier Zahlengruppen (Oktetten), getrennt durch Punkte (z.B. 192.168.1.1)
  • Ermöglicht den korrekten Austausch von Datenpaketen zwischen Sender und Empfänger
  • Besteht aus Netzwerk-ID und Host-ID
    • Wird durch Netzmaske gezeigt. Bei z.B. IP-Adresse 192.168.178.12 mit der Netzmaske 255.255.255.0 (auch als /24 dargestellt) wird gezeigt, dass 192.168.178 die Netzwerkadresse und 12 die Host-Adresse ist.

1.2.2. MAC-Adresse (Media Access Control Address)

  • Physikalische Adresse, die fest einem Gerät zugeordnet ist
  • Dient zur Identifizierung der Netzwerkadapter
  • Besteht aus 12 hexadezimalen Zeichen (Zahlen und Buchstaben) (6 Oktetten, Hexadezimal) (z.B. a1:b2:c3:d4:e5:f6)
  • Sie werden durch Doppelpunkte getrennt
  • Jede MAC-Adresse ist (theoretisch) weltweit einzigartig

1.2.3. MAC- und IP-Adressen Cheatsheet

IP-Adresse MAC-Adresse
4 Oktetten 6 Oktetten
Die Oktetten sind mit . voneinander getrennt Die Oktetten sind mit : voneinander getrennt
Dezimalsystem Hexadezimalsystem
Veränderbar Nicht Veränderbar
(theoretisch) nicht Einzigartig Einzigartig
Wie Adresse Wie Name
Besteht aus Netz- und Host-ID  

1.2.4. Binärsystem (Zweiersystem/Dualsystem)

  • Zahlensystem mit nur zwei Ziffern: 0 und 1
  • Computer nutzen ausschließlich das Binärsystem
  • Grundlage für fast alles in der Informatik
  • Die Stellen verdoppeln sich. Das heisst: 1111 = 1x8 + 1x4 + 1x2 + 1x1 = 15
  • Video

1.2.5. Hexadezimalsystem (Sechzehnersystem)

  • Zahlensystem mit 16 Grundziffern: 0-9 und A-F
  • Erleichtert die Lesbarkeit von langen Binärzahlen
  • Komprimiert Daten mit weniger Zeichen
  • Die Stellen werden mal 16. Das heisst: 13 = 1x16 + 3x1 = 19
  • Video

1.2.6. Zahlensysteme Cheatsheet

Dezimalsystem Binärsystem Hexadezimalsystem
10 Zeichen 2 Zeichen 16 Zeichen
0-9 0-1 0-9, A-F
“Normale Zahlen”/Grundsystem Computerzahlen Computerzahlen
321 = 3x10² + 2x10¹ + 1x10⁰ = 321 110 = 1x2² + 1x2¹ + 0x2⁰ = 6 A3 = 10x16¹ + 3x16⁰ = 163

1.2.7. LAN (Local Area Network)

  • Lokales Netzwerk in einem begrenzten Bereich
  • Verbindet Geräte wie Computer, Drucker und Server
  • Beispiele: Netzwerk zu Hause, in der Schule oder im Büro
  • Geräte sind meist durch Kabel miteinander verbunden

1.2.8. WAN (Wide Area Network)

  • WAN (Wide Area Network) deckt große geografische Gebiete ab
  • Es verbindet mehrere lokale Netzwerke (LANs) miteinander
  • Ein WAN nutzt öffentliche Übertragungswege und Telekommunikationsleitungen
  • Das Internet ist das bekannteste Beispiel für ein WAN

1.2.9. Hub (Netzwerk-Verteiler)

  • Einfaches Gerät zur Verbindung mehrerer Computer
  • Verteilt eingehende Daten an alle angeschlossenen Geräte
  • Weniger effizient als ein Switch
  • Heute kaum noch im Einsatz

1.2.10. Switch (Netzwerk-Schalter)

  • Gerät zur intelligenten Verteilung von Daten im Netzwerk
  • Verbindet mehrere Computer miteinander
  • Sendet Daten gezielt nur an den richtigen Empfänger
  • Effizienter als ein Hub

1.2.11. Router

  • Verbindet mehrere (i.d.R. 2) Netzwerke miteinander
  • z.B. 10.7.254.0 mit 10.7.249.0
  • Besitzt zwei Netzwekkarten, konfiguriert i.d.R. auf 1.
  • Z.B. 10.7.254.1 und 10.7.249.1.

1.2.12. Heimrouter

  • Ein Gerät, wie z.B. Fritzbox
  • Beinhaltet:
    • DHCP Server
    • Router (WAN/LAN Router)
    • Switch
    • Wireless Access Point
    • Firewall
    • und mehr!

1.2.13. DNS

  • Steht für Domain Name System
  • Record für alle Websites und IP-Adressen
  • Wird oft mit DHCP eingerichtet, damit ein Browser weiß, wie er z.B. youtube.de auflösen soll.
Domain IP-Adresse
youtube.com 8.8.8.9
omidmash.de 172.173.83.18

1.2.14. Protokolle (Netzwerkprotokolle)

  • Regelwerke für die Kommunikation zwischen Computern
  • Legen fest, wie Daten ausgetauscht werden
  • Verschiedene Protokolle für verschiedene Aufgaben
1.2.14.1. DHCP (Dynamic Host Configuration Protocol)
  • Protokoll zur automatischen Vergabe von IP-Adressen und Netzwekkonfigurationen
  • Weist Geräten im Netzwerk automatisch Netzwerkeinstellungen zu
  • Vereinfacht die Netzwerkverwaltung erheblich
  • Funktioniert nach dem Client-Server-Modell
1.2.14.2. Telnet (Telecommunication Network)
  • Protokoll für Fernzugriff auf andere Computer
  • Ermöglicht Bedienung eines entfernten Rechners
  • Überträgt Daten unverschlüsselt (unsicher)
  • Heute meist durch SSH ersetzt
1.2.14.3. SSH (Secure Shell)
  • Verschlüsseltes Protokoll für sichere Fernverbindungen
  • Ermöglicht sicheren Zugriff auf entfernte Computer
  • Schützt Passwörter und Daten durch Verschlüsselung
  • Sicherer als Telnet
1.2.14.4. SFTP/FTP (File Transfer Protocol)
  • Protokoll zur Übertragung von Dateien
  • Regelt den Datenaustausch zwischen Computern im Netzwerk
  • Ermöglicht Upload und Download von Dateien
  • Standard für Dateiübertragungen
1.2.14.5. HTTP/HTTPS (Hyper Text Transfer Protocoll)
  • Protokoll zur Übertragung von Hypertext / Websites
  • HTTP wird i.d.R. nicht mehr benutzt und ist durch HTTPS (secure) ersetzt.
1.2.14.6. ICMP (Internet Control Message Protocol)
  • Protokoll zum Austausch von Informations- und Fehlermeldunge
  • Wird für Netzwerkdiagnose verwendet (z.B. Ping-Befehl)
  • Meldet Probleme im Netzwerk
1.2.14.7. SMTP (Simple Mail Transfer Protocol)
  • Protokoll für den Versand von E-Mails
  • Sorgt dafür, dass E-Mails zugestellt werden
  • Überträgt Nachrichten zwischen E-Mail-Servern
  • Postausgangsserver des E-Mail-Kontos
1.2.14.8. IMAP/POP3
  • Protokoll für den Empfang von E-Mails
  • Sorgt dafür, dass E-Mails ankommen und im richtigen Ordner landen

1.3. Block 3 - Python

1.3.1. REPL oder Code als .py Datei?

1.3.1.1. REPL
  • REPL startet man im Terminal mit dem Befehl python3. Wir benutzen allerdings ipython3, damit wir Syntax-Highlighting genießen können.
  • REPL steht für Read Evaluate Print Loop. Das heißt, wir können uns die print()-Funktion sparen.
  • REPL gibt es für viele Sprachen, und es ist gut, wenn man schnell was ausprobieren will.
1.3.1.2. .py-Datei
  • Python-Dateien werden mit der Extension .py gespeichert, damit sie von unserem Computer richtig erkannt werden.
  • Sie werden dann mit dem Programm python3 interpretiert und ausgeführt.
  • Das ist gut, wenn wir unseren Code behalten wollen, oder ihn weitergeben wollen, oder wenn wir an größeren Projekten arbeiten.


1.3.2. Elementare Datentypen

Typ Beschreibung Beispiel
Integers Ganze Zahlen 3, -12, 0
Floats Zahlen mit Kommastellen 3.14, -12.00, 0.0000
Strings Geordnete Zeichenketten "hallo!" oder 'hallo'
Listen Veränderliche Sammlung von Elementen; 0-indiziert [1, 2, 3, "4", "hallo"]


1.3.3. Gebräuchliche Funktionen

Funktion Beschreibung Beispiel
print() Gibt Objekte auf Standardausgabe aus print("Hallo")
type() Gibt den Typ eines Objekts zurück type(42) → <class 'int'>
str(), int(), float() Konvertiert Werte in den entsprechenden Typ str(123) → "123"
sorted() Gibt eine sortierte Liste zurück sorted([3,1,2]) → [1,2,3]
len() Gibt Länge eines Objekts zurück len([1,2,3]) → 3


1.3.4. Operatoren

Typ Beschreibung Beispiel Ausgabe
+ Addition 2 + 2 4
- Subtraktion 3 - 2 1
* Multiplikation 4 * 2 8
/ Division 16 / 2 8
** Exponent 3 ** 2 9
% Modulo (was nach Division übrig bleibt) 5 % 2 1


1.3.5. Gebräuchliche Methoden

Typ Methode Beschreibung Beispiel
String-Methoden .strip() Entfernt Leerzeichen am Anfang und Ende " a ".strip() → "a"
  .upper(), .lower(), .title() Wandelt in Groß-/Kleinschreibung um "a".upper() → "A"
Liste .append(x) Fügt Element am Ende hinzu lst.append(4)
  .remove(x) Entfernt erstes Vorkommen von x lst.remove(2)
  .sort() Sortiert Liste in-place lst.sort()
  .pop(i) Entfernt und gibt Element an Index i zurück x = lst.pop(0)
  .sort() Sortiert Liste in-place lst.sort(), lst.sort(reverse=true)


1.3.6. F-Strings

F-Strings sind gut, wenn man in eine String referenzen zu Variablen geben will, wie z.B. eine Nachricht an jemanden mit der Name name schreiben.

name = "mashregh-zamini"
print(f"Hallo, {name.title()}. Wie geht es dir?")

# einfacher zu lesen als:
print("Hallo, " + name.title() + ". Wie geht es dir?")


Output:

Hallo, Mashregh-Zamini. Wie geht es dir?
Hallo, Mashregh-Zamini. Wie geht es dir?


Oder:

num_1 = 13
num_2 = 23
print(f"num_1 plus num_2 wäre: {num_1 + num_2}")


Output:

num_1 plus num_2 wäre: 36


1.3.7. Listen

Listen sind null-indexed. Das heißt, dass unser erstes Element mit 0 anfängt. Angenommen:

l = [1, 2, 3, 'foo']
print(l[0])     #1
print(l[1])     #2
print(l[3])     #foo
print(l[-1])    #foo

Wir können aber jederzeit die Elemente auch ändern:

l = [1, 2, 3, 'foo']
print(l)    #[1, 2, 3, 'foo']
l[0] = 'bar'
print(l)    #['bar', 2, 3, 'foo']

Wir sortieren temporär mit sorted() und permanent mit .sort().

cars = ['bmw', 'audi', 'toyota', 'subaru']
print(cars.sort())              #['audi', 'bmw', 'subaru', 'toyota']
print(cars.sort(reverse=True))     #['toyota', 'subaru', 'bmw', 'audi']
print(cars.reverse)             #['audi', 'bmw', 'subaru', 'toyota']
sorted(cars)                    #['audi', 'bmw', 'subaru', 'toyota']
print(cars)                     #['audi', 'bmw', 'subaru', 'toyota']
len(cars)                       #4


2. Wahlpflichtfach Informatik

2.1. Sprache: Python

2.1.1. Elementare Datentypen

Typ Beschreibung Beispiel
Variabel Etiketten, die Werte speichern; dürfen Buchstaben, Ziffern und Unterstriche enthalten; keine Leerzeichen; werden kleingeschrieben message = "hallo"
Integers Ganze Zahlen 3, -12, 0
Floats Zahlen mit Kommastellen 3.14, -12.00, 0.0000
Char Einzelne Unicode-Zeichen 'a', '!', '🐏'
Strings Geordnete Zeichenketten "hallo!"
Listen Geordnete, veränderliche Sammlung von Elementen; 0-indiziert [1, 2, 3, "4", "hallo"]
Tuples Geordnete, unveränderliche Sammlung von Elementen (1, 2, 3)
Dictionaries Sammlung von Schlüssel-Wert-Paaren {"name": "MZ", "email": "xyz@gymhum.de", "Alter": 32}

2.1.2. Gebräuchliche Funktionen

Funktion Beschreibung Beispiel
print() Gibt Objekte auf Standardausgabe aus print("Hallo")
len() Gibt Länge eines Objekts zurück len([1,2,3]) → 3
type() Gibt den Typ eines Objekts zurück type(42) → <class 'int'>
str(), int(), float() Konvertiert Werte in den entsprechenden Typ str(123) → "123"
range() Erzeugt eine Sequenz von Zahlen range(0,5) → 0,1,2,3,4
sorted() Gibt eine sortierte Liste zurück sorted([3,1,2]) → [1,2,3]
sum() Summiert Elemente einer iterierbaren Sequenz sum([1,2,3]) → 6
max(), min() Gibt größten/kleinsten Wert zurück max([1,2,3]) → 3
input() Liest Benutzereingabe von der Konsole name = input("Name? ")
help() Zeigt Hilfedokumentation an help(len)

2.1.3. Gebräuchliche Methoden

Typ Methode Beschreibung Beispiel
Liste .append(x) Fügt Element am Ende hinzu lst.append(4)
  .remove(x) Entfernt erstes Vorkommen von x lst.remove(2)
  .sort() Sortiert Liste in-place lst.sort()
  .pop(i) Entfernt und gibt Element an Index i zurück x = lst.pop(0)
Dict .keys() Gibt Schlüssel des Dictionary zurück d.keys()
  .values() Gibt Werte des Dictionary zurück d.values()
  .items() Gibt Schlüssel-Wert-Paare zurück d.items()
  .get(k, d) Gibt Wert für Schlüssel k zurück d.get("name", "n/a")
String .split(s) Trennt String an Trennzeichen s "a,b".split(",") → ["a","b"]
  .join(list) Verbindet Liste von Strings " ".join(["a","b"]) → "a b"
  .strip() Entfernt Leerzeichen am Anfang und Ende " a ".strip() → "a"
  .upper(), .lower() Wandelt in Groß-/Kleinschreibung um "a".upper() → "A"

2.1.4. Wichtige Konzepte

Konzept Beschreibung Beispiel
Klasse Bauplan für Objekte, definiert Attribute und Methoden class Person:
Instanz Konkretes Objekt einer Klasse p = Person()
Attribute Daten, die zu einer Instanz gehören (Instanz- oder Klassenattribute) self.name = "MZ"
__init__() Konstruktor: Initialisiert neue Instanz def __init__(self, name): self.name = name
Vererbung Kindklasse erbt von Elternklasse; ermöglicht Wiederverwendung class Student(Person):
super() Greift auf Methoden der Elternklasse zu super().__init__(name)
__str__() Gibt lesbare String-Repräsentation des Objekts zurück def __str__(self): return f"{self.name}"
__repr__() Gibt unverwechselbare String-Repräsentation für Entwicklung zurück def __repr__(self): return f"Person('{self.name}')"
__len__(), __getitem__() Ermöglicht Integration in Python-Syntax (z.B. len(), Indexzugriff) def __len__(self): return len(self.items)

2.2. Sprache: C

2.2.1. Kapitel 1

2.2.1.1. Einführung in C
2.2.1.1.1. Entstehungsgeschichte
  • In den frühen 1970er Jahren bei Bell Labs als Nebenprodukt von UNIX entwickelt
  • Ken Thompson schrieb UNIX zunächst in Assembler; wollte eine höhere Programmiersprache
  • Entwicklungskette: BCPL → B → NB → C
  • 1973 wurde UNIX komplett in C umgeschrieben, was die Portierbarkeit stark verbesserte


2.2.1.1.2. Standardisierung
  • 1978: K&R-Buch (“The C Programming Language”) wurde zum inoffiziellen Standard
  • 1989/1990: Erster offizieller ANSI/ISO-Standard → C89/C90
  • 1999: Neuer Standard mit zusätzlichen Features → C99
  • Vor C89 gab es viele inkompatible Dialekte, was die Portierbarkeit gefährdete


2.2.1.1.3. C-basierte Sprachen
  • C++ erweitert C um objektorientierte Programmierung (Klassen, etc.)
  • Java und C# basieren auf C++ und erben viele C-Eigenschaften
  • Perl übernahm im Laufe der Zeit viele C-Features
  • Wer C lernt, versteht die Grundlagen all dieser Sprachen besser


2.2.1.1.4. Stärken
  • Effizienz: C-Programme laufen schnell und benötigen wenig Speicher
  • Portierbarkeit: Derselbe Code läuft auf PCs bis hin zu Supercomputern
  • Mächtigkeit: Viele Datentypen und Operatoren; viel mit wenig Code erreichbar
  • Flexibilität: Kaum Einschränkungen; z.B. kann ein char zu einem int addiert werden
  • Standardbibliothek: Hunderte nützliche Funktionen für I/O, Strings, Speicher, etc.


2.2.1.1.5. Schwächen
  • Fehleranfällig: Viele Fehler werden erst zur Laufzeit entdeckt, nicht beim Kompilieren
    • Beispiel: Ein fehlendes & bei scanf führt zum Absturz, wird aber nicht immer erkannt
  • Schwer lesbar: Sehr kompakter, knapper Stil; absichtliche Kürze aus historischen Gründen
    • Beispiel: -+i ist gültiger Ausdruck (unäres Minus und Plus)
  • Schwer wartbar: Großen C-Programmen fehlen Strukturierungsmittel wie Klassen oder Pakete


2.2.1.2. Fragen und Antworten
2.2.1.2.1. Wie kompiliere ich Code in C?
  • Mit Hilfe von GCC!
  • gcc -o programmname programmcode.c


2.2.1.2.2. Wie führe ich nun mein kompiliertes Programm aus?
  • ./programmname


2.2.1.2.3. Was bedeutet GCC?
  • Ursprünglich “GNU C Compiler”, heute “GNU Compiler Collection”
  • Kompiliert viele Sprachen: C, C++, Java, Fortran, Ada, Objective-C


2.2.1.2.4. Was bedeutet GNU?
  • “GNU’s Not UNIX!” (rekursives Akronym), ausgesprochen “guh-NEW”
  • Projekt der Free Software Foundation von Richard M. Stallman
  • Protest gegen Einschränkungen lizenzierter UNIX-Software
  • GNU-Software (inkl. GCC) ist ein wesentlicher Bestandteil von Linux


2.2.1.2.5. Was ist das Besondere an GCC?
  • Kostenlos, hochwertig und auf vielen Plattformen verfügbar
  • Erzeugt Code für viele verschiedene CPUs
  • Unterstützt viele Programmiersprachen


2.2.1.2.6. Wie gründlich prüft GCC auf Fehler?

Nützliche Compiler-Optionen:

-Wall
Aktiviert alle Warnmeldungen
-W
Zusätzliche Warnungen über -Wall hinaus
-pedantic
Alle vom C-Standard geforderten Warnungen; lehnt nicht-standardkonforme Features ab
-ansi
Deaktiviert GCC-spezifische Features; aktiviert Standard-Features
-std=c89 / -std=c99
Legt die zu verwendende C-Version fest

Typische Kombination:

gcc -O -Wall -W -pedantic -ansi -std=c99 -o programm programm.c


2.2.1.2.7. Warum ist C so knapp geschrieben?
  • Historischer Grund: Entwicklung auf einem PDP-11 mit Fernschreiber (10 Zeichen/Sekunde)
  • Möglichst wenige Zeichen zu tippen war damals ein echter Vorteil
  • Daher { und } statt begin~/~end, int statt integer, usw.


2.2.1.2.8. Ist exit(0) dasselbe wie return 0 in main?
  • Ja, innerhalb von main sind beide gleichwertig
  • Beide beenden das Programm und geben den Wert 0 an das Betriebssystem zurück
  • Welche Variante man wählt, ist Geschmackssache


2.2.1.2.9. Was passiert, wenn main kein return hat?
  • Das Programm wird trotzdem beendet
  • In C99 wird implizit 0 zurückgegeben
  • In C89 wird ein unbestimmter Wert zurückgegeben
  • Viele Compiler erzeugen eine Warnung


2.2.1.2.10. Entfernt der Compiler Kommentare vollständig?
  • Nein: laut C-Standard wird jeder Kommentar durch ein einzelnes Leerzeichen ersetzt
  • Alter Trick a/**/b funktioniert daher nicht; der Compiler sieht a b (ungültig)


2.2.1.2.11. Wie erkenne ich einen nicht geschlossenen Kommentar?
  • Oft führt er zu einem Kompilierfehler, weil er Code “verschluckt”
  • IDEs färben Kommentare oft farblich ein; falsch gefärbter Code zeigt das Problem
  • Debugger (zeilenweises Durchgehen) oder lint können helfen


2.2.1.2.12. Können Kommentare verschachtelt werden?
  • Nein: /* ... */ Kommentare können nicht verschachtelt werden
  • Das erste */ schließt den Kommentar, egal wie viele /* davor standen
  • C99-Kommentare (//) können jedoch innerhalb von /* */ verwendet werden
  • Das ist ein weiterer Vorteil von //-Kommentaren


2.2.2. Kapitel 2

2.2.2.1. Grundlagen von C
2.2.2.1.1. Programmstruktur
  • Direktiven beginnen mit # und werden vor der Kompilierung verarbeitet
  • #include <stdio.h> bindet die Standard-I/O-Bibliothek ein (nötig für printf/scanf)
  • main() ist die einzige Pflichtfunktion; sie wird automatisch beim Programmstart aufgerufen
  • Rückgabewert return 0; signalisiert dem Betriebssystem: Programm erfolgreich beendet
  • Anweisungen enden mit Semikolon; Direktiven nicht


Beispiel: minimales C-Programm

#include <stdio.h>
int main(void)
{
    printf("Hallo, Welt!\n");
    return 0;
}


2.2.2.1.2. Variablen und Typen
  • Variablen müssen vor ihrer Verwendung deklariert werden
  • int speichert ganze Zahlen (typisch bis ±2.147.483.647)
  • float speichert Dezimalzahlen, aber mit möglichem Rundungsfehler
    • Beispiel: 0.1f kann intern als 0.09999999... gespeichert sein
  • Mehrere Variablen gleichen Typs können zusammen deklariert werden
int hoehe = 8, laenge = 12, breite = 10;
float gewinn = 2150.48f;  /* f am Ende wichtig bei float-Zuweisung */


2.2.2.1.3. Ausgabe mit printf
  • %d für int, %f für float, %.2f für float mit 2 Nachkommastellen
  • \n für Zeilenumbruch, \t für Tabulator
  • Feldbreite und Ausrichtung steuerbar: %5d (rechtsbündig), %-5d (linksbündig)
int volumen = 960;
float preis = 13.5f;
printf("Volumen: %d Kubikzoll\n", volumen);
printf("Preis: %8.2f Euro\n", preis);  /* rechtsbündig, 2 Nachkommastellen */


2.2.2.1.4. Eingabe mit scanf
  • & vor dem Variablennamen ist (meistens) Pflicht; fehlt es, droht Absturz
  • %d für int, %f für float
  • scanf überspringt Leerzeichen automatisch beim Suchen nach Zahlen
int hoehe;
printf("Hoehe eingeben: ");
scanf("%d", &hoehe);  /* & nicht vergessen! */


2.2.2.1.5. Benannte Konstanten
  • Mit #define werden Konstanten definiert; der Präprozessor ersetzt den Namen vor der Kompilierung
  • Konvention: Großbuchstaben für Konstantennamen
  • Ausdrücke in Klammern setzen, um Vorrangfehler zu vermeiden
#define GEFRIERPUNKT 32.0f
#define UMRECHNUNGSFAKTOR (5.0f / 9.0f)  /* Klammern wichtig! */
/* ohne Klammern: 5.0f / 9.0f * (fahrenheit - 32.0f) → falsches Ergebnis */

celsius = (fahrenheit - GEFRIERPUNKT) * UMRECHNUNGSFAKTOR;


2.2.2.1.6. Bezeichner und Schlüsselwörter
  • Bezeichner dürfen Buchstaben, Ziffern und Unterstriche enthalten; müssen mit Buchstabe oder Unterstrich beginnen
  • C unterscheidet Groß- und Kleinschreibung: job, Job, JOB sind drei verschiedene Bezeichner
  • Schlüsselwörter wie int, float, return, if, while sind reserviert und dürfen nicht als Namen verwendet werden
  • Ungültige Bezeichner: 10mal (beginnt mit Ziffer), get-next (enthält Minus)


2.2.2.2. Fragen und Antworten
2.2.2.2.1. Woher kommt der Name float?
  • Kurzform für “floating-point” (Gleitkomma)
  • Zahl wird in zwei Teilen gespeichert: Mantisse und Exponent
  • Beispiel: 12.0 wird intern als 1.5 × 2³ gespeichert
  • Andere Sprachen nennen diesen Typ real


2.2.2.2.2. Warum müssen Gleitkommakonstanten mit f enden?
  • Eine Dezimalzahl ohne f hat den Typ double (doppelte Genauigkeit)
  • double kann größer sein als float; daher Warnung möglich bei Zuweisung ohne f
  • Beispiel: profit = 2150.48f; ist korrekt; profit = 2150.48; kann Warnung erzeugen


2.2.2.2.3. Gibt es wirklich keine Längenbegrenzung für Bezeichner?
  • Technisch nein, aber Compiler müssen nur eine bestimmte Anzahl Zeichen merken
  • C89: erste 31 Zeichen signifikant (63 in C99)
  • Bei externer Verlinkung (z.B. Funktionsnamen): in C89 nur 6 Zeichen, Groß-/Kleinschreibung ggf. egal
  • In der Praxis sind moderne Compiler großzügiger; sehr kurze Namen sind das eigentliche Problem


2.2.2.2.4. Wie viele Leerzeichen zur Einrückung?
  • Zu wenig: Einrückung kaum erkennbar
  • Zu viel: Zeilen laufen aus dem Bild
  • Studien: optimale Einrückung sind 3 Leerzeichen
  • Im Buch werden 2 Leerzeichen verwendet, damit der Code in die Seitenränder passt


2.2.2.3. Übungen
2.2.2.3.1. Übung 1

Erstelle und starte das “hello, world”-Programm. Gibt es Compiler-Warnungen?

#include <stdio.h>
int main(void)
{
    printf("hello, world\n");
}


2.2.2.3.2. Übung 2

Gegeben folgendes Programm:

#include <stdio.h>
int main(void)
{
    printf("Parkinson's Law:\nWork expands so as to ");
    printf("fill the time\n");
    printf("available for its completion.\n");
    return 0;
}
  • (a) Identifiziere die Direktiven und Anweisungen im Programm
  • (b) Welche Ausgabe erzeugt das Programm?


2.2.2.3.3. Übung 3

Vereinfache das dweight.c-Programm:

/* Computes the dimensional weight of a 12" x 10" x 8" box */

#include <stdio.h>

int main(void) {
    int height, length, width, volume, weight;

    height = 8;
    length = 12;
    width = 10;
    volume = height * length * width;
    weight = (volume + 165) / 166;

    printf("Dimensions: %dx%dx%dx\n", length, width, height);
    printf("Volume (cubic inches): %d\n", volume);
    printf("Dimensional weight (pounds): %d\n", weight);

    return 0;
}
  • (1) Ersetze die Zuweisungen an height, length und width durch Initialisierungen
  • (2) Entferne die Variable weight und berechne (volume + 165) / 166 direkt in printf


2.2.2.3.4. Übung 4

Schreibe ein Programm, das mehrere int- und float-Variablen deklariert, ohne sie zu initialisieren, und dann ihre Werte ausgibt. Gibt es ein Muster bei den Werten?


2.2.2.3.5. Übung 5

Welche der folgenden sind keine gültigen C-Bezeichner?

  • (a) 100_bottles → ungültig (beginnt mit Ziffer)
  • (b) _100_bottles → gültig
  • (c) one__hundred__bottles → gültig
  • (d) bottles_by_the_hundred_ → gültig


2.2.2.3.6. Übung 6

Warum ist es keine gute Idee, mehrere aufeinanderfolgende Unterstriche in einem Bezeichner zu verwenden (z.B. current___balance)?

  • Solche Namen sind für die Implementierung (Compiler/Bibliotheken) reserviert
  • Kann zu Konflikten mit internen Compiler-Bezeichnern führen


2.2.2.3.7. Übung 7

Welche der folgenden sind Schlüsselwörter in C?

  • (a) for → Schlüsselwort
  • (b) If → kein Schlüsselwort (C unterscheidet Groß-/Kleinschreibung; if wäre eines)
  • (c) main → kein Schlüsselwort (reservierter Funktionsname, aber kein Keyword)
  • (d) printf → kein Schlüsselwort (Bibliotheksfunktion)
  • (e) while → Schlüsselwort


2.2.2.4. Programmierprojekte
2.2.2.4.1. Programmierprojekt

Schreibe ein Programm, das folgendes Bild mit printf ausgibt:

          *
         *
        *
 *     *
  *   *
    *


2.2.2.4.2. Programmierprojekt

Schreibe ein Programm, das das Volumen einer Kugel mit Radius 10 berechnet. Formel: v = 4/3 * π * r³

  • Schreibe 4/3 als 4.0f/3.0f (sonst ganzzahlige Division → Ergebnis 1)
  • als r * r * r (kein Potenzoperator in C)


2.2.2.4.3. Programmierprojekt

Erweitere Projekt 2: Der Benutzer gibt den Radius selbst ein.


2.2.2.4.4. Programmierprojekt

Schreibe ein Programm, das einen Betrag einliest und ihn mit 5% Mehrwertsteuer ausgibt:

Betrag eingeben: 100.00
Mit Steuer: $105.00


2.2.2.4.5. Programmierprojekt

Schreibe ein Programm, das x einliest und folgenden Ausdruck berechnet: 3x⁵ + 2x⁴ - 5x³ - x² + 7x - 6 Hinweis: Potenzen durch wiederholte Multiplikation berechnen (x*x*x für x³)


2.2.2.4.6. Programmierprojekt

Wie Projekt 5, aber mit Horner-Schema: ((((3x + 2)x - 5)x - 1)x + 7)x - 6 Vorteil: weniger Multiplikationen nötig


2.2.2.4.7. Programmierprojekt

Schreibe ein Programm, das einen Dollar-Betrag einliest und mit möglichst wenigen Scheinen ($20, $10, $5, $1) herausgibt:

Betrag eingeben: 93
$20-Scheine: 4
$10-Scheine: 1
 $5-Scheine: 0
 $1-Scheine: 3

Hinweis: Nur ganzzahlige Arithmetik verwenden


2.2.2.4.8. Programmierprojekt

Schreibe ein Programm, das den Restbetrag eines Darlehens nach den ersten drei monatlichen Zahlungen berechnet und anzeigt:

Darlehensbetrag eingeben: 20000.00
Zinssatz eingeben: 6.0
Monatliche Rate eingeben: 386.66
Restbetrag nach 1. Zahlung: $19713.34
Restbetrag nach 2. Zahlung: $19425.25
Restbetrag nach 3. Zahlung: $19135.71

Hinweis: Monatszins = Jahreszins / 12 / 100; Restbetrag = Restbetrag - Rate + Restbetrag * Monatszins


2.2.3. Kapitel 3

2.2.3.1. Formatierte Ein-/Ausgabe
2.2.3.1.1. Die printf-Funktion
  • printf gibt den Inhalt eines Formatstrings aus, wobei Werte an bestimmten Stellen eingefügt werden
  • Syntax: printf(formatstring, ausdruck1, ausdruck2, ...);
  • Keine Begrenzung der Anzahl an Werten in einem einzelnen printf-Aufruf
  • Der Compiler prüft nicht, ob Umwandlungsspezifikation und Datentyp zusammenpassen


2.2.3.1.2. Umwandlungsspezifikationen (Conversion Specifications)
  • Allgemeine Form: %m.pX oder %-m.pX (m und p sind optional)
  • m = minimale Feldbreite: Mindestanzahl der Zeichen; Wert wird rechtsbündig ausgegeben
    • %4d zeigt 123 als ·123 (·= Leerzeichen)
    • Wenn der Wert breiter ist als m, wird das Feld automatisch erweitert
    • %-4d ergibt linksbündige Ausgabe: 123·
  • p = Genauigkeit: Bedeutung hängt vom Umwandlungsspezifizierer ab


Spezifizierer Beschreibung Beispiel
%d Ganzzahl in Dezimalform; p = Mindestanzahl Ziffern (Standard: 1) printf("%4d", 123)·123
%e Gleitkommazahl in Exponentialform; p = Nachkommastellen (Standard: 6) printf("%10.3e", 3.14)·3.140e+00
%f Gleitkommazahl in Dezimalform ohne Exponent; p = Nachkommastellen (Standard: 6) printf("%.2f", 3.14159)3.14
%g Zeigt Gleitkommazahl in %e oder %f, je nachdem was kürzer ist; p = signifikante Stellen (Standard: 6) printf("%.4g", 123456.0)1.235e+05


2.2.3.1.3. Escape-Sequenzen
Sequenz Beschreibung Beispiel
\n Zeilenumbruch printf("Hallo\nWelt")
\t Tabulator (Abstand abhängig vom Betriebssystem) printf("Item\tPreis")
\\ Gibt ein einzelnes \ aus printf("\\")
\" Gibt ein Anführungszeichen innerhalb eines Strings printf("\"Hallo!\"")"Hallo!"
\a Akustisches Signal (Piep) printf("\a")
\b Cursor ein Zeichen zurück printf("ab\bc")ac
%% Gibt ein einzelnes %-Zeichen aus printf("100%%")100%


Beispiel: mehrzeiliger Header mit Tabs

printf("Item\tUnit\tPurchase\n\tPrice\tDate\n");

Ausgabe:

Item    Unit    Purchase
        Price   Date


2.2.3.1.4. Die scanf-Funktion
  • scanf liest Eingaben gemäß einem Formatstring und speichert sie in Variablen
  • & vor dem Variablennamen ist (meistens) Pflicht; fehlt es, droht Absturz oder undefiniertes Verhalten
  • scanf überspringt Whitespace (Leerzeichen, Tabs, Zeilenumbrüche) beim Suchen nach Zahlen
int i, j;
float x, y;
scanf("%d%d%f%f", &i, &j, &x, &y);
/* Eingabe: 1 -20 .3 -4.0e3
   → i=1, j=-20, x=0.3, y=-4000.0 */


2.2.3.1.5. Wie scanf funktioniert
  • scanf liest die Eingabe als durchgehenden Zeichenstrom
  • Bei %d: sucht Ziffer, Plus- oder Minuszeichen; liest Ziffern bis ein Nicht-Ziffern-Zeichen kommt
  • Bei %f~/~%e~/~%g: sucht optionales Vorzeichen, Ziffern (evtl. mit Dezimalpunkt), optionalen Exponenten
  • Nicht passende Zeichen werden “zurückgelegt” für den nächsten scanf-Aufruf
  • %e, %f und %g sind bei scanf austauschbar (alle folgen denselben Regeln)


Beispiel für Zurücklegen:

scanf("%d%d%f%f", &i, &j, &x, &y);
/* Eingabe: 1-20.3-4.0e3
   → i=1, j=-20, x=0.3, y=-4000.0
   scanf legt '-', '.' usw. zurück, wenn sie nicht zum aktuellen Typ passen */


2.2.3.1.6. Gewöhnliche Zeichen im scanf-Formatstring
  • Leerzeichen im Formatstring: überspringt beliebig viele Whitespace-Zeichen der Eingabe
  • Andere Zeichen (z.B. /, ,): müssen exakt in der Eingabe vorkommen
scanf("%d/%d", &monat, &tag);       /* erwartet z.B. 2/17 */
scanf("%d,%d", &i, &j);             /* erwartet z.B. 4,28 */
  • Wenn das Zeichen nicht passt, bricht scanf sofort ab


2.2.3.1.7. Häufige Fehler: printf vs. scanf verwechseln
  • & in printf ist ein Fehler: printf("%d", &i); → gibt seltsame Zahl aus statt den Wert von i
  • \n am Ende eines scanf-Formatstrings ist fast immer falsch: scanf("%d\n", &i);
    • \n wirkt in scanf wie ein Leerzeichen; Programm hängt, bis Benutzer ein nicht-leeres Zeichen eingibt
  • Gewöhnliche Zeichen im scanf-Format müssen in der Eingabe übereinstimmen:
    • scanf("%d, %d", &i, &j); erwartet ein Komma zwischen den Zahlen


2.2.3.1.8. Programm: Brüche addieren (addfrac.c)
/* addfrac.c */
/* Addiert zwei Brüche */
#include <stdio.h>

int main(void)
{
    int num1, denom1, num2, denom2, result_num, result_denom;

    printf("Ersten Bruch eingeben: ");
    scanf("%d/%d", &num1, &denom1);

    printf("Zweiten Bruch eingeben: ");
    scanf("%d/%d", &num2, &denom2);

    result_num = num1 * denom2 + num2 * denom1;
    result_denom = denom1 * denom2;

    printf("Die Summe ist %d/%d\n", result_num, result_denom);

    return 0;
}

Beispielausgabe:

Ersten Bruch eingeben: 5/6
Zweiten Bruch eingeben: 3/4
Die Summe ist 38/24

Hinweis: Das Ergebnis wird nicht gekürzt.


2.2.3.2. Fragen und Antworten
2.2.3.2.1. Was ist der Unterschied zwischen %i und %d?
  • Bei printf: kein Unterschied
  • Bei scanf: %d erkennt nur Dezimalzahlen; %i erkennt auch Oktal- (Präfix 0) und Hexadezimalzahlen (Präfix 0x)
  • Falle: Wenn der Benutzer versehentlich eine führende 0 eingibt, interpretiert %i die Zahl als oktal
  • Empfehlung: Bei %d bleiben


2.2.3.2.2. Wie gibt man das %-Zeichen mit printf aus?
  • Zwei aufeinanderfolgende %-Zeichen: %%
  • Beispiel: printf("Gewinn: %d%%\n", gewinn);Gewinn: 10%


2.2.3.2.3. Wie weit sind Tabstopps voneinander entfernt?
  • In C nicht definiert; hängt vom Betriebssystem ab
  • Typisch: 8 Zeichen Abstand, aber keine Garantie


2.2.3.2.4. Was passiert, wenn scanf eine Zahl erwartet, aber ungültige Eingabe bekommt?
  • Eingabe 23foo bei %d: scanf liest 23, foo bleibt für den nächsten Aufruf
  • Eingabe foo bei %d: Variable bleibt undefiniert, foo bleibt im Puffer
  • Prüfung des Rückgabewerts von scanf ermöglicht Fehlererkennung (Details in Kapitel 22)


2.2.3.2.5. Wie kann scanf Zeichen “zurücklegen”?
  • Eingaben werden nicht direkt gelesen, sondern in einem versteckten Puffer gespeichert
  • scanf kann Zeichen zurück in den Puffer legen, damit sie beim nächsten Aufruf gelesen werden
  • Details zur Eingabepufferung in Kapitel 22


2.2.3.2.6. Was passiert bei Satzzeichen zwischen Zahlen?
  • Eingabe 4,28 bei scanf("%d%d", &i, &j);: i = 4, j wird nicht gelesen (Komma passt nicht zu einer Zahl)
  • Lösung: Komma im Formatstring angeben: scanf("%d,%d", &i, &j);


2.2.3.3. Übungen
2.2.3.3.1. Übung 1

Welche Ausgabe erzeugen die folgenden printf-Aufrufe?

  • (a) printf("%6d,%4d", 86, 1040);····86,1040
  • (b) printf("%12.5e", 30.253);·3.02530e+01
  • (c) printf("%.4f", 83.162);83.1620
  • (d) printf("%-6.2g", .0000009979);1e-06·


2.2.3.3.2. Übung 2

Schreibe printf-Aufrufe, die eine float-Variable x in folgenden Formaten anzeigen:

  • (a) Exponentialform; linksbündig in Feld der Breite 8; eine Nachkommastelle
  • (b) Exponentialform; rechtsbündig in Feld der Breite 10; sechs Nachkommastellen
  • (c) Dezimalform; linksbündig in Feld der Breite 8; drei Nachkommastellen
  • (d) Dezimalform; rechtsbündig in Feld der Breite 6; keine Nachkommastellen


2.2.3.3.3. Übung 3

Sind die folgenden scanf-Formatstring-Paare gleichwertig? Falls nein, zeige den Unterschied.

  • (a) "%d" vs. " %d" → gleichwertig (%d überspringt Whitespace automatisch)
  • (b) "%d-%d-%d" vs. "%d -%d -%d" → nicht gleichwertig (Leerzeichen im Format überspringt beliebig viele Whitespace-Zeichen)
  • (c) "%f" vs. "%f " → nicht gleichwertig (nachstehendes Leerzeichen lässt scanf auf weitere Eingabe warten)
  • (d) "%f,%f" vs. "%f, %f" → gleichwertig (Leerzeichen vor %f redundant, da %f ohnehin Whitespace überspringt)


2.2.3.3.4. Übung 4

Angenommen, wir rufen auf:

scanf("%d%f%d", &i, &x, &j);

und der Benutzer gibt ein: 10.3 5 6

Ergebnis: i = 10, x = 0.3, j = 5

  • scanf liest 10 für %d, stoppt am Punkt
  • .3 wird als Float gelesen (%f)
  • 5 wird für das zweite %d gelesen
  • 6 bleibt im Puffer


2.2.3.3.5. Übung 5

Angenommen, wir rufen auf:

scanf("%f%d%f", &x, &i, &y);

und der Benutzer gibt ein: 12.3 45.6 789

Ergebnis: x = 12.3, i = 45, y = 0.6

  • 12.3 wird als Float für x gelesen
  • 45 wird als Integer für i gelesen, scanf stoppt am Punkt
  • .6 wird als Float für y gelesen
  • 789 bleibt im Puffer


2.2.3.3.6. Übung 6

Wie kann das addfrac.c-Programm geändert werden, damit der Benutzer Leerzeichen vor und nach dem /-Zeichen eingeben darf?

Lösung: Leerzeichen im Formatstring einfügen:

scanf("%d / %d", &num, &denom);


2.2.3.4. Programmierprojekte
2.2.3.4.1. Programmierprojekt 1

Schreibe ein Programm, das ein Datum im Format mm/dd/yyyy einliest und als yyyymmdd ausgibt:

Datum eingeben (mm/dd/yyyy): 2/17/2011
Eingegebenes Datum: 20110217


2.2.3.4.2. Programmierprojekt 2

Schreibe ein Programm, das Produktinformationen vom Benutzer einliest und formatiert ausgibt:

Artikelnummer eingeben: 583
Stückpreis eingeben: 13.5
Kaufdatum eingeben (mm/dd/yyyy): 10/24/2010

Item            Unit            Purchase
                Price           Date
583             $  13.50        10/24/2010
  • Artikelnummer und Datum linksbündig; Preis rechtsbündig
  • Beträge bis $9999.99 zulassen
  • Hinweis: Tabs (\t) für Spaltenausrichtung verwenden


2.2.3.4.3. Programmierprojekt 3

Schreibe ein Programm, das eine ISBN-13 einliest und in ihre Bestandteile zerlegt:

ISBN eingeben: 978-0-393-97950-3
GS1-Präfix: 978
Gruppenkennung: 0
Verlagscode: 393
Titelnummer: 97950
Prüfziffer: 3

Hinweis: Die Gruppengrößen können variieren; nicht von festen Längen ausgehen. scanf mit /-Trennzeichen verwenden: scanf("%d-%d-%d-%d-%d", ...)


2.2.3.4.4. Programmierprojekt 4

Schreibe ein Programm, das eine Telefonnummer im Format (xxx) xxx-xxxx einliest und als xxx.xxx.xxxx ausgibt:

Telefonnummer eingeben [(xxx) xxx-xxxx]: (404) 817-6900
Eingegeben: 404.817.6900


2.2.3.4.5. Programmierprojekt 5

Schreibe ein Programm, das die Zahlen 1 bis 16 (in beliebiger Reihenfolge) einliest und als 4×4-Feld anzeigt, gefolgt von Zeilen-, Spalten- und Diagonalsummen:

Zahlen 1 bis 16 eingeben:
16 3 2 13 5 10 11 8 9 6 7 12 4 15 14 1

16  3  2 13
 5 10 11  8
 9  6  7 12
 4 15 14  1

Zeilensummen:     34 34 34 34
Spaltensummen:    34 34 34 34
Diagonalsummen:   34 34

Wenn alle Summen gleich sind, bilden die Zahlen ein magisches Quadrat.


2.2.3.4.6. Programmierprojekt 6

Erweitere addfrac.c, sodass der Benutzer beide Brüche auf einmal eingibt, getrennt durch ein Pluszeichen:

Zwei Brüche mit Pluszeichen eingeben: 5/6+3/4
Die Summe ist 38/24


2.2.4. Kapitel 4

2.2.4.1. Ausdrücke
2.2.4.1.1. 4.1 Arithmetische Operatoren
  • Binäre Operatoren: +, -, *, /, %
  • Unäre Operatoren: + (Vorzeichen plus), - (Vorzeichen minus)
  • / bei Ganzzahlen: Ergebnis wird zur Null hin abgeschnitten (7/2 = 3, -7/2 = -3 in C99)
  • % erfordert Integer-Operanden; Vorzeichen des Ergebnisses = Vorzeichen des Dividenden (C99)
  • Gilt immer: (a/b) * b + a % b == a


Priorität Operatoren Assoziativität
höher * / % links
tiefer + - (binär) links
unär + - (Vorzeichen) rechts


Beispiel: UPC-Prüfziffer (upc.c)

#include <stdio.h>
int main(void)
{
    int d, i1, i2, i3, i4, i5, j1, j2, j3, j4, j5, total;
    printf("Erste Ziffer:         "); scanf("%1d", &d);
    printf("Erste Fünfergruppe:   "); scanf("%1d%1d%1d%1d%1d", &i1,&i2,&i3,&i4,&i5);
    printf("Zweite Fünfergruppe:  "); scanf("%1d%1d%1d%1d%1d", &j1,&j2,&j3,&j4,&j5);
    total = 3*d + i1 + 3*i2 + i3 + 3*i4 + i5 +
            3*j1 + j2 + 3*j3 + j4 + 3*j5;
    printf("Prüfziffer: %d\n", 9 - ((total - 1) % 10));
    return 0;
}


2.2.4.1.2. 4.2 Zuweisungsoperatoren
  • Einfache Zuweisung: v = e (speichert Wert von e in v; v muss ein lvalue sein)
  • Zuweisung ist selbst ein Ausdruck → Ketten möglich: i = j = k = 0;
  • Zusammengesetzte Operatoren: +=, -=, *=, /=, %=
    • v += e ist v = v + e, außer wenn v Nebeneffekte hat (dann v nur einmal ausgewertet)


Operator Beispiel Bedeutung
+= i += 5 i = i + 5
-= i -= 5 i = i - 5
*= i *= 5 i = i * 5
/= i /= 5 i = i / 5
%= i %= 5 i = i % 5


2.2.4.1.3. 4.3 Inkrement- und Dekrementoperatoren
  • ++i (Präfix): erhöht i, gibt neuen Wert zurück
  • i++ (Postfix): gibt alten Wert zurück, erhöht dann i
  • --i / i--: analog für Dekrement
int i = 5;
printf("%d\n", ++i);  /* gibt 6 aus; i ist 6 */
printf("%d\n", i++);  /* gibt 6 aus; i ist 7 */
printf("%d\n", i);    /* gibt 7 aus */


2.2.4.1.4. 4.4 Auswertung von Ausdrücken
  • Priorität und Assoziativität legen die Struktur fest (wo Klammern stehen würden)
  • Die Reihenfolge der Teilauswertungen ist meist undefiniert (außer bei &&, ||, ?:, ,)
  • Ausdrücke, die eine Variable gleichzeitig lesen und schreiben → undefiniertes Verhalten


Priorität Name Operatoren Assoziativität
1 (hoch) Postfix ++ -- links
2 Präfix / Unär ++ -- + - rechts
3 Multiplikativ * / % links
4 Additiv + - links
5 (tief) Zuweisung = *= /= %= += -= rechts


/* SCHLECHT – undefiniertes Verhalten */
a = 5;
c = (b = a + 2) - (a = 1);   /* Ergebnis nicht vorhersagbar */

/* GUT – in getrennte Anweisungen aufteilen */
a = 5;  b = a + 2;  a = 1;  c = b - a;  /* c ist immer 6 */


2.2.4.1.5. 4.5 Ausdrucksanweisungen
  • Jeder Ausdruck + ; = gültige Anweisung; sinnvoll nur mit Nebeneffekt
i = 1;       /* sinnvoll: Zuweisung            */
i--;         /* sinnvoll: Dekrement             */
i * j - 1;  /* sinnlos:  kein Nebeneffekt      */
i + j;       /* Tippfehler! gemeint war i = j;  */


2.2.4.2. Fragen und Antworten
2.2.4.2.1. Hat C keinen Potenzierungsoperator?
  • Kein **; für kleine Potenzen wiederholte Multiplikation (i * i * i = i³)
  • Für nichtganzzahlige Potenzen: pow() aus <math.h>


2.2.4.2.2. Kann ich % auf float anwenden?
  • Nein, % erfordert Integer-Operanden
  • Alternative: fmod() aus <math.h>


2.2.4.2.3. Warum sind die Regeln für / und % mit negativen Operanden so kompliziert?
  • C89: Ergebnis ist implementierungsabhängig (Compiler durfte runden oder abschneiden)
  • C99: Division schneidet immer zur Null hin ab; dadurch gilt stets (a/b)*b + a%b == a
  • Beispiel C89: -9/7 ist entweder -1 oder -2; in C99 ist es immer -1


2.2.4.2.4. Hat C neben lvalues auch rvalues?
  • Ja: Ein lvalue ist ein Ausdruck, der links von = stehen kann (eine Speicherstelle)
  • Ein rvalue ist ein Ausdruck auf der rechten Seite (Variable, Konstante oder komplexer Ausdruck)
  • Der C-Standard verwendet stattdessen den Begriff “expression” statt “rvalue”


2.2.4.2.5. ★ Warum ist v += e nicht dasselbe wie v = v + e, wenn v Nebeneffekte hat?
  • v += e: v wird einmal ausgewertet
  • v = v + e: v wird zweimal ausgewertet → Nebeneffekte verdoppeln sich
  • Beispiel: a[i++] += 2;i einmal erhöht; mit a[i++] = a[i++] + 2; wäre es undefiniertes Verhalten


2.2.4.2.6. Woher stammen ++ und --?
  • Von Ken Thompsons früherer Sprache B geerbt; B-Compiler konnte ++i kompakter übersetzen als i = i + 1
  • Kein Geschwindigkeitsvorteil bei modernen Compilern; Beliebtheit beruht auf Kürze und Tradition


2.2.4.2.7. Funktionieren ++ und -- auch mit float-Variablen?
  • Ja, aber in der Praxis selten sinnvoll


2.2.4.2.8. ★ Wann wird bei Postfix-++ oder -- tatsächlich inkrementiert?
  • Spätestens am Ende der Ausdrucksanweisung (Sequenzpunkt)
  • Auch Funktionsaufrufe sind Sequenzpunkte: Argumente sind vollständig ausgewertet (inkl. ++~/–~) bevor die Funktion aufgerufen wird
  • Innerhalb desselben Ausdrucks ist die genaue Reihenfolge undefiniert


2.2.4.2.9. Was bedeutet “der Wert einer Ausdrucksanweisung wird verworfen”?
  • Ein Ausdruck hat immer einen Wert; wird er nicht gespeichert, geht er verloren
  • i + 1; berechnet den Wert, speichert ihn aber nirgends → verloren


2.2.4.2.10. Aber bei i = 1; – was wird da verworfen?
  • = ist ein Operator und erzeugt wie jeder Operator einen Wert (hier: 1)
  • Dieser Wert wird verworfen; das ist kein Problem, da der Zweck der Anweisung die Änderung von i war


2.2.4.3. Übungen
2.2.4.3.1. Übung 1

Welche Ausgabe erzeugen folgende Fragmente? (i, j, k sind int)

  • (a) i=5; j=3; printf("%d %d", i/j, i%j);1 2
  • (b) i=2; j=3; printf("%d", (i+10)%j);0 (12%3=0)
  • (c) i=7; j=8; k=9; printf("%d", (i+10)%k/j);1 (17%9=8, 8/8=1)
  • (d) i=1; j=2; k=3; printf("%d", (i+5)%(j+2)/k);0 (6%4=2, 2/3=0)


2.2.4.3.2. Übung 2 ★

Haben bei positiven Ganzzahlen i, j die Ausdrücke (-i)/j und -(i/j) immer denselben Wert?

  • In C99: Ja. Division schneidet beide zur Null hin ab, Vorzeichen ist identisch.


2.2.4.3.3. Übung 3

Welche Werte haben folgende Ausdrücke in C89? (mehrere Werte möglich bei negativen Operanden)

  • (a) 8/51
  • (b) -8/5-1 oder -2
  • (c) 8/-5-1 oder -2
  • (d) -8/-51 oder 2


2.2.4.3.4. Übung 4

Wie Übung 3, aber in C99 (Division schneidet immer zur Null hin ab):

  • (a) 8/51
  • (b) -8/5-1
  • (c) 8/-5-1
  • (d) -8/-51


2.2.4.3.5. Übung 5

Welche Werte haben folgende Ausdrücke in C89? (mehrere Werte möglich)

  • (a) 8%53
  • (b) -8%5-3 oder 2
  • (c) 8%-53 oder -2
  • (d) -8%-5-3 oder 2


2.2.4.3.6. Übung 6

Wie Übung 5, aber in C99 (Vorzeichen des Rests = Vorzeichen des Dividenden):

  • (a) 8%53
  • (b) -8%5-3
  • (c) 8%-53
  • (d) -8%-5-3


2.2.4.3.7. Übung 7

Warum funktioniert die vereinfachte UPC-Variante nicht?

  • Original: 9 - ((total - 1) % 10)
  • Vereinfacht: berechne total % 10, subtrahiere von 10
  • Problem: Wenn total % 10 == 0, ergibt 10 - 0 = 10 — keine gültige einstellige Prüfziffer
  • Original erzeugt in diesem Fall korrekt 9 - 9 = 0


2.2.4.3.8. Übung 8

Würde upc.c noch funktionieren, wenn 9 - ((total-1) % 10) durch (10 - (total % 10)) % 10 ersetzt wird?

  • Ja. Wenn total % 10 == 0: (10-0)%10 = 0 ✓; wenn total % 10 == t: (10-t)%10 = 10-t für t>0


2.2.4.3.9. Übung 9 ★

Welche Ausgabe erzeugen folgende Fragmente? (i, j, k sind int)

  • (a) i=7; j=8; i*=j+1; printf("%d %d", i, j);63 8
  • (b) i=j=k=1; i+=j+=k; printf("%d %d %d", i, j, k);3 2 1
  • (c) i=1; j=2; k=3; i-=j-=k; printf("%d %d %d", i, j, k);2 -1 3
  • (d) i=2; j=1; k=0; i*=j*=k; printf("%d %d %d", i, j, k);0 0 0


2.2.4.3.10. Übung 10

Welche Ausgabe erzeugen folgende Fragmente? (i, j sind int)

  • (a) i=6; j=i+=i; printf("%d %d", i, j);12 12
  • (b) i=5; j=(i-=2)+1; printf("%d %d", i, j);3 4
  • (c) i=7; j=6+(i=2.5); printf("%d %d", i, j);2 8 (2.5 abgeschnitten zu 2)
  • (d) i=2; j=8; j=(i=6)+(j=3); printf("%d %d", i, j);6 9


2.2.4.3.11. Übung 11 ★

Welche Ausgabe erzeugen folgende Fragmente? (i, j, k sind int; ★ = Auswertungsreihenfolge kann implementierungsabhängig sein)

  • (a) i=1; printf("%d ", i++-1); printf("%d", i);0 2
  • (b) i=10; j=5; printf("%d ", i++-++j); printf("%d %d", i, j);4 11 6
  • (c) i=7; j=8; printf("%d ", i++---j); printf("%d %d", i, j);0 8 7
  • (d) ★ i=3; j=4; k=5; printf("%d ", i++-j+++--k); printf("%d %d %d", i, j, k); → implementierungsabhängig (links→rechts: 3 4 5 4)


2.2.4.3.12. Übung 12

Welche Ausgabe erzeugen folgende Fragmente? (i, j sind int)

  • (a) i=5; j=++i*3-2; printf("%d %d", i, j);6 16
  • (b) i=5; j=3-2*i++; printf("%d %d", i, j);6 -7
  • (c) i=7; j=3*i--+2; printf("%d %d", i, j);6 23
  • (d) i=7; j=3+--i*2; printf("%d %d", i, j);6 15


2.2.4.3.13. Übung 13 ★

Welcher der Ausdrücke ++i und i++ ist genau dasselbe wie (i += 1)?

  • ++i — beide geben den neuen Wert von i zurück
  • i++ gibt den alten Wert zurück → nicht äquivalent


2.2.4.3.14. Übung 14

Klammern setzen, um zu zeigen, wie der Compiler den Ausdruck liest:

  • (a) a*b-c*d+e((a*b)-(c*d))+e
  • (b) a/b%c/d((a/b)%c)/d
  • (c) -a-b+c-+d((-a)-b)+(c-(+d))
  • (d) a*-b/c-d((a*(-b))/c)-d


2.2.4.3.15. Übung 15

Werte von i und j nach jeder Anweisung? (i=1, j=2 zu Beginn)

  • (a) i += j;i=3, j=2
  • (b) i--;i=0, j=2
  • (c) i * j / i;i=1, j=2 (kein Nebeneffekt)
  • (d) i % ++j;i=1, j=3 (kein Nebeneffekt auf i)


2.2.4.4. Programmierprojekte
2.2.4.4.1. Programmierprojekt 1

Schreibe ein Programm, das eine zweistellige Zahl einliest und mit vertauschten Ziffern ausgibt:

Zweistellige Zahl eingeben: 28
Umgekehrt: 82

Hinweis: letzte Ziffer n%10, erste n/10; Ausgabe mit printf("%d%d\n", n%10, n/10)


2.2.4.4.2. Programmierprojekt 2 ★

Erweitere Projekt 1 für dreistellige Zahlen:

Dreistellige Zahl eingeben: 123
Umgekehrt: 321


2.2.4.4.3. Programmierprojekt 3

Wie Projekt 2, aber ohne Arithmetik zum Zerlegen — stattdessen %1d in scanf verwenden (wie upc.c):

int d1, d2, d3;
scanf("%1d%1d%1d", &d1, &d2, &d3);
printf("%d%d%d\n", d3, d2, d1);


2.2.4.4.4. Programmierprojekt 4

Schreibe ein Programm, das eine ganze Zahl (0–32767) einliest und in Oktal (Basis 8) ausgibt:

Zahl zwischen 0 und 32767 eingeben: 1953
In Oktal: 03641

Hinweis: letzte Oktalziffer n%8, dann n/8 wiederholen; printf kann auch %o für Oktal (Kapitel 7)


2.2.4.4.5. Programmierprojekt 5

Erweitere upc.c, sodass der Benutzer alle 11 Ziffern auf einmal eingibt:

Erste 11 Stellen des UPC eingeben: 01380015173
Prüfziffer: 5

Hinweis: scanf("%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d", &d, &i1, ...)


2.2.4.4.6. Programmierprojekt 6

Schreibe ein Programm, das die EAN-Prüfziffer (European Article Number, 13 Stellen) berechnet. Algorithmus ähnlich wie UPC:

  • Summe 1: gerade Positionen (2., 4., 6., 8., 10., 12.)
  • Summe 2: ungerade Positionen (1., 3., 5., 7., 9., 11.)
  • Gesamtsumme: Summe1 × 3 + Summe2; dann 9 - ((gesamt - 1) % 10)
Erste 12 Stellen der EAN eingeben: 869148426000
Prüfziffer: 8


3. Oberstufe Profil

3.1. Rechnernetze

3.1.1. Authentizität

Die Authentizität bezieht sich darauf, dass die Identität von Benutzern, Geräten oder Informationen verifiziert werden kann. Es geht darum sicherzustellen, dass diejenigen, mit denen man interagiert, tatsächlich diejenigen sind, für die sie sich ausgeben.

3.1.2. Integrität

Mit der Integrität der Daten soll sichergestellt werden, dass keine Veränderung an den Daten unerkannt bleibt. Hier geht es also darum nachvollziehen zu können, welche Änderungen an den Daten vorgenommen wurden.

3.1.3. Vertraulichkeit

Durch die Vertraulichkeit wird sichergestellt, dass bestimmte Informationen nur den Personen zugänglich sind, die die entsprechenden Berechtigungen haben.

3.1.4. PKI (Public Key Infrastructure)

Infrastruktur zur Verwaltung digitaler Zertifikate.

3.1.4.1. CA (Certificate Authority)
  • Zertifizierungsstelle zur Ausstellung digitaler Zertifikate
3.1.4.2. RA (Root Authority)
  • Registrierungsstelle zur Identitätsprüfung in einer PKI

3.1.5. Web of Trust

Dezentrales Vertrauensmodell durch gegenseitige Bestätigung

3.2. Verschlüsselung

3.2.1. Klartext

Unverschlüsselte, lesbare Nachricht

3.2.2. Geheimtext

Verschlüsselte Nachricht

3.2.3. Asymmetrisches Verfahren

  • Verfahren mit öffentlichem und privatem Schlüssel
  • Ein Schlüssel zum ent- und ein Schlüssel zum verschlüsseln

3.2.4. Symmetrisches Verfahren

Ein Schlüssel zum Ver- und Entschlüsseln.

3.2.5. Schlüsseltauschproblem

Problem des sicheren Schlüsselaustauschs, lösbar durch z.B:

3.2.5.1. Diffie-Hellman Verfahren

3.2.6. RSA Verfahren

Weit verbreitetes asymmetrisches Verschlüsselungsverfahren

3.2.7. Monoalphabetische Verfahren

  • Substitution mit festem Schlüsselalphabet
  • Caesar, RSA(?)

3.2.8. Polyalphabetische Verfahren

  • Substitution mit wechselndem Schlüssel, z.B. ein Wort
  • Vigénere

3.3. Programmierung Allgemein (CompSci)

3.3.1. Rekursive Funktionen

Funktionen, die sich selbst aufrufen.

In Python:

def fib(n):
    if n in [0,1]:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)

In Haskell:

fib 0 = 0
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)

3.4. Haskell

3.4.1. Link für Infos und Übungen:

3.4.2. Mit Listen arbeiten

l = [1, 3..10]

l      -- [1,3,5,7,9]
tail l -- [3,5,7,9]
head l -- 1
init l -- [1,3,5,7]
take 2 l -- [1,3]
drop 2 l --[5,7,9]

3.4.3. Implementation von Caesar

import Data.Char (isLower, isUpper, ord, chr)

shift :: Int -> Char -> Char
shift n c
| isLower c = chr $ (ord c - ord 'a' + n) `mod` 26 + ord 'a'
| isUpper c = chr $ (ord c - ord 'A' + n) `mod` 26 + ord 'A'
| otherwise = c

caesarRec :: Int -> String -> String
caesarRec _ []          = []
caesarRec n (c:cs)      = shift n c : caesarRec n cs

3.5. Python und OOP

3.5.2. UML Diagramme

3.5.3. Code Snippets für UML-Übungen

class Restaurant:
    def __init__(self, restaurant_name, cuisine_type):
        self.restaurant_name = restaurant_name
        self.cuisine_type = cuisine_type
    def describe_restaurant(self):
        print(f"Restaurant Name: {self.restaurant_name.title()}\nArt der Cuisine: {self.cuisine_type.title()}")
    def open_restaurant(self):
        print("Das Restaurant hat jetzt auf!")
class IceCreamStand(Restaurant):
    def __init__(self, restaurant_name, cuisine_type):
        super().__init__(restaurant_name, cuisine_type)
        self.flavour = ['vanilla', 'strawberry', 'chocolate']
    def describe_flavour(self):
        print("These flavors are available!")
        for flavour in self.flavour:
            print(flavour.title())
class User:
    def __init__(self, first_name, last_name, date_of_birth, username, login_attempts = 0):
        self.first_name = first_name
        self.last_name = last_name
        self.date_of_birth = date_of_birth
        self.username = username
        self.login_attempts = login_attempts

    def describe_user(self):
        print(
            f"First Name: {self.first_name.title()}\n"
            f"Last Name: {self.last_name.title()}\n"
            f"Date of Birth: {self.date_of_birth.title()}\n"
            f"Username: {self.username}"
        )

    def greet_user(self):
        print(
            f"Hallo {self.first_name.title()} {self.last_name.title()}. "
            "Herzlich Willkommen!"
        )

    def increment_login_attempts(self):
        self.login_attempts += 1

    def reset_login_attempts(self):
        self.login_attempts = 0

class Admin(User):
    def __init__(self, first_name, last_name, date_of_birth, username, login_attempts = 0):
        super().__init__(first_name, last_name, date_of_birth, username, login_attempts = 0)
        self.privileges = Privileges(['can add post', 'can delete post', 'can ban user'])
        

class Privileges():
    def __init__(self, privileges):
        self.privileges = privileges
    def show_privileges(self):
        for privilege in self.privileges:
            print(privilege)

3.6. Muster Aufgaben

3.6.1. Users erstellen

3.6.1.1. Aufgabe

Du hast die Aufgabe bekommen, für IServ ein Login-System zu implementieren. Es gibt viele Benutzer, die sich einloggen wollen, und sie sollten unterschiedliche Rechte haben. Insgesamt gibt es drei Gruppen: Administrator, Lehrer und SuS. Der Auftraggeber will, dass die drei Gruppen von einem Hauptobjekt class User erben. Jeder User sollte Felder für Vorname, Nachname, Geburtsdatum, Benutzername und E-Mail-Adresse haben. Die Lehrer sollten zusätzlich noch Felder für Telefonnummer und Adresse haben. Bei der Admin-Gruppe sollte es auch noch eine Variable is_admin = True geben. Die Benutzernamen werden automatisch durch das Muster <vorname>.<nachname> erstellt, und die E-Mail-Adressen sollten durch das Muster <benutzername>@gymhum.de automatisch erstellt werden.

  • Erstelle ein grafisches Diagramm dafür, wie das Programm und die Objekte funktionieren sollen.
  • Implementiere das Programm in Python.

3.6.2. Ackermannfunktion

3.6.2.1. Aufgabe

Angenommen, dass eine Funktion namens ack so definiert ist, rechne ack 1 10, ack 2 4 und ack 3 3.

ack :: Integer -> Integer -> Integer
ack 0 n = n + 1
ack m 0 = ack (m - 1) 1
ack m n = ack (m - 1) (ack m (n - 1))

Implementiere diese Funktion in Python.

3.6.3. Pascalschs Dreieck

3.6.3.1. Aufgabe

Das folgende Zahlenmuster wird Pascalsches Dreieck genannt.

        1
      1   1
    1   2   1
  1   3   3   1
1   4   6   4   1
       ...

Die Zahlen am Rand des Dreiecks sind alle 1, und jede Zahl im Inneren des Dreiecks ist die Summe der beiden Zahlen darüber.

  • Schreibe eine Prozedur in Haskell, die die Elemente des Pascalschen Dreiecks mittels eines rekursiven Prozesses berechnet.
  • Schreibe deinen Algorithmus in Python um.
3.6.3.2. Lösung
pascal :: Int -> Int -> Int
pascal row col
  | col < 0 || col > row = 0
  | col == 0 || col == row = 1
  | otherwise = pascal (row - 1) (col - 1) + pascal (row - 1) col

3.6.4. Diffie-Hellman Schlüsselaustausch

3.6.4.1. Aufgabe
3.6.4.1.1. Teil 1: Haskell

Schreibe eine Funktion diffieHellman, die die Parameter p, g, a und b entgegennimmt und K1 und K2 berechnet.

3.6.4.1.2. Teil 2: Python

Implementiere dasselbe Verfahren in Python.

3.6.4.1.3. Beispielwerte
  • Primzahl: p = 23
  • Basis: g = 5
  • Alice privat: a = 6
  • Bob privat: b = 15

3.6.5. Haskell Sammlung an Lektüre

4. Buchempfehlung

5. Interessante Artikel

6. michmichs

7. Infos

7.1. Wie mache ich eigentlich so schnell eine Website?

Diese Website ist eigentlich eine org-mode-Datei. Es gibt noch ein paar Tricks mit HTML-Embedding und Binding sowie eine #SETUPFILE. Das heißt, dass ich durch Ausführen von SPC-p-u alles in HTML übersetze und auf meinen Webserver zuhause hochlade. Die elisp-Funktion sieht so aus:

(defun my/publish-unterrichtsmaterial ()
  (interactive)
  (when my/is-desktop
    (let ((org-file "/mnt/NVME/NextCloud/Emacs/roam/20260105114329-unterrichtsmaterial.org")
          (html-file "/mnt/NVME/NextCloud/Emacs/roam/20260105114329-unterrichtsmaterial.html"))
      (with-current-buffer (find-file-noselect org-file)
        (org-html-export-to-html))
      (shell-command
       (format "scp %s matrix:/var/www/html/portfolio/unterricht.html" html-file))
      (message "Unterrichtsmaterial aktualisiert.")))
  
  (when (or my/is-laptop my/is-work)
    (let ((org-file "/home/omidmash/Nextcloud/Emacs/roam/20260105114329-unterrichtsmaterial.org")
          (html-file "/home/omidmash/Nextcloud/Emacs/roam/20260105114329-unterrichtsmaterial.html"))
      (with-current-buffer (find-file-noselect org-file)
        (org-html-export-to-html))
      (shell-command
       (format "scp %s matrix:/var/www/html/portfolio/unterricht.html" html-file))
      (message "Unterrichtsmaterial aktualisiert.")))

(map! :leader
      :desc "Update Unterrichtsmaterial" "p u" #'my/publish-unterrichtsmaterial)


7.2. Ich will auch eine Website!

Eine Website kann auch auf einem Einplatinencomputer (wie einem Raspberry Pi) laufen. Wenn du Lust hast, so etwas einzurichten, melde dich bei der IT-

7.3. Irgendwas ist kaputt? Tippfehler gefunden?

Schreibe mir bitte eine E-mail an omid.mashregh-zamini@gymhum.hamburg.de.

Author: Omid Mashregh-Zamini

Created: 2026-05-17 So 19:00