Unterrichtsmaterial
Table of Contents
- 1. Pflichtfach Informatik
- 1.1. Block 1 - Robotik / Algorithmen
- 1.2. Block 1.5 - Betriebssystem, Filesystem und Terminalarbeit
- 1.3. Block 2 - Rechnernetze
- 1.3.1. IP-Adresse (Internet Protocol Address)
- 1.3.2. MAC-Adresse (Media Access Control Address)
- 1.3.3. MAC- und IP-Adressen Cheatsheet
- 1.3.4. Binärsystem (Zweiersystem/Dualsystem)
- 1.3.5. Hexadezimalsystem (Sechzehnersystem)
- 1.3.6. Zahlensysteme Cheatsheet
- 1.3.7. LAN (Local Area Network)
- 1.3.8. WAN (Wide Area Network)
- 1.3.9. Hub (Netzwerk-Verteiler)
- 1.3.10. Switch (Netzwerk-Schalter)
- 1.3.11. Router
- 1.3.12. Heimrouter
- 1.3.13. DNS
- 1.3.14. Protokolle (Netzwerkprotokolle)
- 1.3.14.1. DHCP (Dynamic Host Configuration Protocol)
- 1.3.14.2. Telnet (Telecommunication Network)
- 1.3.14.3. SSH (Secure Shell)
- 1.3.14.4. SFTP/FTP (File Transfer Protocol)
- 1.3.14.5. HTTP/HTTPS (Hyper Text Transfer Protocoll)
- 1.3.14.6. ICMP (Internet Control Message Protocol)
- 1.3.14.7. SMTP (Simple Mail Transfer Protocol)
- 1.3.14.8. IMAP/POP3
- 1.4. Block 3A - Python
- 1.5. Block 3B - Racket
- 1.5.1. Racket? Bitte was?
- 1.5.2. Syntax ist einheitlich. Gut oder schlecht?
- 1.5.3. Variablen und einfache Datentypen
- 1.5.3.1. Was sind elementare/einfache Datentypen?
- 1.5.3.2. Variablen
- 1.5.3.3. Regeln für Bezeichner
- 1.5.3.4. Weiter geht’s mit
string-append: - 1.5.3.5. Mehr String-funktionen!
- 1.5.3.6. Zahlen
- 1.5.3.7. Kommentare
- 1.5.4. Einführung in Listen
- 1.5.5. Arbeiten mit Listen
- 2. Wahlpflichtfach Informatik
- 2.1. WPU A - Sprache: Python
- 2.2. WPU B - Sprache: Common Lisp
- 2.2.1. Lisp? Bitte was?
- 2.2.2. Kapitel 2
- 2.2.2.1. Welcome to Lisp!
- 2.2.2.2. Data
- 2.2.2.3. List Operationen
- 2.2.2.4. Wahrheit
- 2.2.2.5. Funktionen
- 2.2.2.6. Rekursion
- 2.2.2.7. Input & Output
- 2.2.2.8. Variablen
- 2.2.2.9. Assignment (Zuweisung)
- 2.2.2.10. Functional Programming
- 2.2.2.11. Iteration (Schleifen)
- 2.2.2.12. Funktionen als Objekte
- 2.2.2.13. Fragen und Antworten
- 2.2.2.14. Zusammenfassung
- 2.2.2.15. Übungen
- 2.2.2.15.1. Von Hand durchgehen:
- 2.2.2.15.2. Drei unterschiedliche
cons-Ausdrücke finden, die alle zu(A B C)auswerten. - 2.2.2.15.3. Eine Funktion schreiben, die mit
car/cdrdas vierte Element einer Liste zurückgibt. - 2.2.2.15.4. Eine Funktion mit zwei Argumenten schreiben, die den größeren Wert zurückgibt.
- 2.2.2.15.5. Herausfinden, was diese Funktionen machen, dann in Worten erklären:
- 2.2.2.15.6. Nur mit dem, was in diesem Kapitel vorkam, eine Funktion schreiben, die für eine Liste prüft, ob irgendein Element selbst eine Liste ist.
- 2.2.2.15.7. Je eine iterative und eine rekursive Version schreiben für eine Funktion, die:
- 2.3. WPU C - Sprache: C
- 2.3.1. Kapitel 1
- 2.3.1.1. Einführung in C
- 2.3.1.2. Fragen und Antworten
- 2.3.1.2.1. Wie kompiliere ich Code in C?
- 2.3.1.2.2. Wie führe ich nun mein kompiliertes Programm aus?
- 2.3.1.2.3. Was bedeutet GCC?
- 2.3.1.2.4. Was bedeutet GNU?
- 2.3.1.2.5. Was ist das Besondere an GCC?
- 2.3.1.2.6. Wie gründlich prüft GCC auf Fehler?
- 2.3.1.2.7. Warum ist C so knapp geschrieben?
- 2.3.1.2.8. Ist
exit(0)dasselbe wiereturn 0in main? - 2.3.1.2.9. Was passiert, wenn main kein return hat?
- 2.3.1.2.10. Entfernt der Compiler Kommentare vollständig?
- 2.3.1.2.11. Wie erkenne ich einen nicht geschlossenen Kommentar?
- 2.3.1.2.12. Können Kommentare verschachtelt werden?
- 2.3.2. Kapitel 2
- 2.3.3. Kapitel 3
- 2.3.3.1. Formatierte Ein-/Ausgabe
- 2.3.3.1.1. Die printf-Funktion
- 2.3.3.1.2. Umwandlungsspezifikationen (Conversion Specifications)
- 2.3.3.1.3. Escape-Sequenzen
- 2.3.3.1.4. Die scanf-Funktion
- 2.3.3.1.5. Wie scanf funktioniert
- 2.3.3.1.6. Gewöhnliche Zeichen im scanf-Formatstring
- 2.3.3.1.7. Häufige Fehler: printf vs. scanf verwechseln
- 2.3.3.1.8. Programm: Brüche addieren (addfrac.c)
- 2.3.3.2. Fragen und Antworten
- 2.3.3.2.1. Was ist der Unterschied zwischen %i und %d?
- 2.3.3.2.2. Wie gibt man das %-Zeichen mit printf aus?
- 2.3.3.2.3. Wie weit sind Tabstopps voneinander entfernt?
- 2.3.3.2.4. Was passiert, wenn scanf eine Zahl erwartet, aber ungültige Eingabe bekommt?
- 2.3.3.2.5. Wie kann scanf Zeichen “zurücklegen”?
- 2.3.3.2.6. Was passiert bei Satzzeichen zwischen Zahlen?
- 2.3.3.3. Übungen
- 2.3.3.4. Programmierprojekte
- 2.3.3.1. Formatierte Ein-/Ausgabe
- 2.3.4. Kapitel 4
- 2.3.4.1. Ausdrücke
- 2.3.4.2. Fragen und Antworten
- 2.3.4.2.1. Hat C keinen Potenzierungsoperator?
- 2.3.4.2.2. Kann ich
%auffloatanwenden? - 2.3.4.2.3. Warum sind die Regeln für
/und%mit negativen Operanden so kompliziert? - 2.3.4.2.4. Hat C neben lvalues auch rvalues?
- 2.3.4.2.5. ★ Warum ist
v += enicht dasselbe wiev = v + e, wennvNebeneffekte hat? - 2.3.4.2.6. Woher stammen
++und--? - 2.3.4.2.7. Funktionieren
++und--auch mitfloat-Variablen? - 2.3.4.2.8. ★ Wann wird bei Postfix-
++oder--tatsächlich inkrementiert? - 2.3.4.2.9. Was bedeutet “der Wert einer Ausdrucksanweisung wird verworfen”?
- 2.3.4.2.10. Aber bei
i = 1;– was wird da verworfen?
- 2.3.4.3. Übungen
- 2.3.4.3.1. Übung 1
- 2.3.4.3.2. Übung 2 ★
- 2.3.4.3.3. Übung 3
- 2.3.4.3.4. Übung 4
- 2.3.4.3.5. Übung 5
- 2.3.4.3.6. Übung 6
- 2.3.4.3.7. Übung 7
- 2.3.4.3.8. Übung 8
- 2.3.4.3.9. Übung 9 ★
- 2.3.4.3.10. Übung 10
- 2.3.4.3.11. Übung 11 ★
- 2.3.4.3.12. Übung 12
- 2.3.4.3.13. Übung 13 ★
- 2.3.4.3.14. Übung 14
- 2.3.4.3.15. Übung 15
- 2.3.4.4. Programmierprojekte
- 2.3.1. Kapitel 1
- 3. Oberstufe GA/EA
- 3.1. Block 0 - Computer-Zahlensysteme
- 3.2. Block 1 - Python und OOP
- 3.3. Block 2 - Rechnernetze
- 3.4. Informatik Allgemein
- 3.5. Block 3 EA - Haskell *
- 3.6. Muster Aufgaben
- 4. Buchempfehlung
- 5. Interessante Artikel
- 6. michmichs
- 7. Zitate
- 8. Infos
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 1.5 - Betriebssystem, Filesystem und Terminalarbeit
WORK IN PROGRESS
1.2.1. Was ist ein Betriebssystem?
Das Betriebssystem ist unsere Schnitstelle zwischen Hardware und Software. Es ist ein Software, welch die Kommunikation zwischen Hardware und weitere Software und Anwendungen ermöglicht. Linux, MacOS, Windows (und NetBSD) sind die übliche Desktop Betriebssysteme. Handys benutzen hauptsächlich iOS und Android, und neue Betriebssysteme with GrapheneOS oder eOS werden zurzeit entwickelt.
1.2.2. Hab ich ein Wahl?
Klar. Auf meisten Computer ist Windows vorinstalliert. Profi Softwareentwickler benutzen jedoch hauptsächlich Linux oder MacOS. Die zwei sind sehr teilweise hinten den Culissen sich sehr ähnlich, allerdings MacOS kann nur auf Apple Geräte installiert werden, und Linux auf alle Rechner. Fast alle Servers in der Welt benutzen Linux, und wir benutzen in dieser Schule auch Linux, genau genommen die Linux Mint Variante.
1.2.3. Was ist Terminal?
Bevor Computer eine Benutzeroberfläche hatten, hat man mit den durch Texkommandos gearbeitet. Es gab damals eine andere Computer, namens Terminal, und dies funktionierte als eine I/O-Device (mit Tastatur und Bildschirm) und so hat man mit dem Hauptcomputer gearbeitet. Heutzutage benutzt man keine Terminalcomputer mehr, sondern ein Software die die Arbeit mit Computer auf dieser Art ermöglichen. Die nennt man Terminal-Emulators. Es gibt viele (kitty, alacritty, foot) aber wir benutzen die in Linux Mint vorgegebene Terminal.
1.2.4. Was ist Shell?
Shell ist ein Software, welch in Terminal läuft und damit interagieren wir mit unseren Computer nur mit Text. Vorteile davon sind dass man extrem schnell arbeiten kann wenn man sich damit auskennt, und dass Shells auch eine Programmiersprache sind. Also man kann seine Arbeit automatisieren, z.B. konvertiere alle meine Videos damit sie kleiner sind, und dann ändere die Namen, und pack sie in bestimmte Ordner basierend auf wo ich die Videos aufgenommen hab, und lade sie auf eine Website hoch.
Es gibt viele Shell-Software. Die üblichen sind bash und zsh. Die Unterschiede sind minimal und für diese Kurs irrelevant.
1.2.5. Wie sieht das Filesystem aus?
Filesystem ist unsere Ordner (directory) und Dateien (file) struktur. In Linux ist alles ein File. Wir sehen diese Struktur mit diesen Command:
tree / -L 1
| ’/’ | Root, wo ALLES gespeichert ist | |
| ├── | bin | Normale Anwendungen sind hier |
| ├── | boot | Alles was die Rechner braucht, um hoch zu fahren |
| ├── | dev | |
| ├── | etc | viele Konfiguration-Dateien sind hier |
| ├── | home | Hier sind die Benutzerdateien, wie Schreibtisch, Downloads usw. |
| ├── | lib | Programme, die andere Programme benötigen kommen hier |
| ├── | lib64 | …und hier. |
| ├── | lost+found | |
| ├── | mnt | Wenn ich eine externe Festplatte oder USB-Stick hab, mounte ich das hier |
| ├── | opt | Hier sind einige ’optionale’ Anwendungen |
| ├── | proc | Jede Prozess auf unsere Rechner kreariert hier Dateien |
| ├── | root | wie /home, aber für der Administrator |
| ├── | run | |
| ├── | sbin | Hier sind die Anwendungen, die nur von der Administrator ausgeführt werden dürfen |
| ├── | srv | |
| ├── | sys | |
| ├── | tmp | Temporäre Dateien kommen hier |
| ├── | usr | Die Anwendungen für ’normale’ Benutzer sind hier |
| ├── | var | Hier sind einige Konfigurationen und alle Systemlogs |
| └── | version |
1.2.6. Warum brauche ich das?
Weil es nicht nur super cool ist, wenn man wie ein Zauberer mit der Rechner arbeitet, sondern die Profis machen das auch so. In Terminal zu arbeiten ist nicht nur VIEL schneller als mit GUI (Graphical User Interface), sondern es ist reproduzierbar. Man kann mit eine Zeile Befehle sachen machen, die mit GUI nur mit “Auf das X Bild klicken und dann auf Y Dropdown Z auswählen” und nur mit Screenshots möglich ist. Mit Terminal, kann man sehr komplizierte Sachen mit ein paar Zeichen machen.
1.2.7. Übliche und nützliche Programme und Befehle
1.2.7.1. pwd
pwd steht für print working directory und zeigt uns, so wir sind.
pwd
/mnt/NVME/NextCloud/Emacs/roam
1.2.7.2. ls
Wie oben auch gesehen, ls zeigt uns alles, was in ein Directory ist.
ls
1.2.7.3. cd
cd steht für “change directory”, und wechselt zu einem anderen Ordner. .. heißt ein Directory höher.
~/coding/level1dir ❯ pwd
/home/omidmash/coding/level1dir
~/coding/level1dir ❯ ls
level2dir/
~/coding/level1dir ❯ cd level2dir/
~/coding/level1dir/level2dir ❯ ls
~/coding/level1dir/level2dir ❯ pwd
/home/omidmash/coding/level1dir/level2dir
~/coding/level1dir/level2dir ❯ cd ..
~/coding/level1dir ❯ pwd
/home/omidmash/coding/level1dir
~/coding/level1dir ❯
1.2.7.4. cat
cat liest ein Datei und gibt uns der Inhalt in stdout, also als Text wieder.
cat test.txt
Hallo, das stand in test.txt!
1.2.7.5. mv
mv nimmt zwei Argumente: was muss beweget werden, und wohin. Z.B. mv meinedatei ../ nimmt meinedatei aus den jetztigen cwd (current working directory) und bewegt den eine Stufe höher.
1.2.7.6. rm
DANGER ZONE: rm löscht Sachen endgültig. Das kann man nicht rückgängig machen. rm datei löscht eine Datei, und rm -r directory/ löscht eine Directory und den kompletten Inhalt.
1.2.7.7. nano
Es gibt viele Terminal Text-Editors. Bekannt sind VIm, nano und emacs. nano ist besonders einfach: mit Ctrl-S speichert man, und mit Ctrl-X schliesst man das Program.
1.2.7.8. ip
mit ip sehe ich meine Netzwekdaten. ip nimmt einige Argumente. Ich benutze immer ip -c a. Das heisst, zeig mir meine ip a -ddress in -c olor (Farbe).
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: wlp1s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether c2:99:a9:2d:bd:a8 brd ff:ff:ff:ff:ff:ff permaddr f0:2f:4b:0b:79:71
altname wlxf02f4b0b7971
inet 172.20.10.8/28 brd 172.20.10.15 scope global dynamic noprefixroute wlp1s0f0
valid_lft 2028sec preferred_lft 2028sec
inet6 2a00:20:8010:8440:29d7:a07a:1b7f:baaa/64 scope global noprefixroute
valid_lft forever preferred_lft forever
inet6 fe80::1f45:bc99:22a9:edd3/64 scope link noprefixroute
valid_lft forever preferred_lft forever
1.2.7.9. mkdir
mit mkdir erstellen wir Directories. Ganz einfach: mkdir dirname.
1.2.7.10. rmdir
rmdir löscht leere Directories. Sehr praktisch, wenn man sicher sein will, das man aus Versehen nichts wichtiges löscht.
1.2.7.11. grep
mit grep kann man nach Text in Dateien suchen. In welche Datei habe ich was zu Thema Mitochondrium gehabt? Easy! grep "Mitochondrium" ~* sucht in dem Directory wo ich bin in alle Dateien “*” nach Inhalt mit “Mitochondrium”.
1.2.7.12. find
mit find findet man Dateien, quasi eine Suchfunktion.
find /home/omidmash/Downloads -name '*.pdf'
/home/omidmash/Downloads/Dune-Rulebook-.pdf /home/omidmash/Downloads/worksheet-on-logic-gates-2.pdf
1.3. Block 2 - Rechnernetze
1.3.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.12mit der Netzmaske255.255.255.0(auch als /24 dargestellt) wird gezeigt, dass 192.168.178 die Netzwerkadresse und12die Host-Adresse ist.
- Wird durch Netzmaske gezeigt. Bei z.B. IP-Adresse
1.3.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.3.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.3.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.3.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.3.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.3.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.3.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.3.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.3.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.3.11. Router
- Verbindet mehrere (i.d.R. 2) Netzwerke miteinander
- z.B.
10.7.254.0mit10.7.249.0 - Besitzt zwei Netzwekkarten, konfiguriert i.d.R. auf
1. - Z.B.
10.7.254.1und10.7.249.1.
1.3.12. Heimrouter
- Ein Gerät, wie z.B. Fritzbox
- Beinhaltet:
- DHCP Server
- Router (WAN/LAN Router)
- Switch
- Wireless Access Point
- Firewall
- und mehr!
1.3.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.deauflösen soll.
| Domain | IP-Adresse |
|---|---|
| youtube.com | 8.8.8.9 |
| omidmash.de | 172.173.83.18 |
1.3.14. Protokolle (Netzwerkprotokolle)
- Regelwerke für die Kommunikation zwischen Computern
- Legen fest, wie Daten ausgetauscht werden
- Verschiedene Protokolle für verschiedene Aufgaben
1.3.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.3.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.3.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.3.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.3.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.3.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.3.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.3.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.4. Block 3A - Python
1.4.1. REPL oder Code als .py Datei?
1.4.1.1. REPL
- REPL startet man im Terminal mit dem Befehl
python3. Wir benutzen allerdingsipython3, 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.4.1.2. .py-Datei
- Python-Dateien werden mit der Extension
.pygespeichert, damit sie von unserem Computer richtig erkannt werden. - Sie werden dann mit dem Programm
python3interpretiert 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.4.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.4.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.4.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.4.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.4.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.4.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
1.5. Block 3B - Racket
WORK IN PROGRESS
1.5.1. Racket? Bitte was?
- Racket ist basierend auf LISP
- LISP gibt es seit 1960!
- Hat hauptsächlich die Mathematiker interessiert.
- …und die, die sich mit KI beschäftigen wollten.
Der Erfinder,
John McCarthy, war ein KI-Forscher.
- Es gibt VIELE Versionen davon, z.B. Common Lisp, Scheme, Franz Lisp, MacLisp, Emacs Lisp
- Wir benutzen Racket, und die ist ähnlich wie Scheme.
- Es wurde hauptsächlich für Schulen/Unis entwickelt.
- Mit Zeit, ist es zu einer sehr starke Programmiersprache geworden.
- Es ist Interaktiv wie alle LISPs. (Normalerweise sind Programmiersprachen wie C und Java nicht interaktiv).
- Es kann “Language oriented programming”. Was das ist interessiert uns allerdings nicht…
- …aber wir MUSSEN unsere Dateien IMMER mit #lang racket starten.
1.5.2. Syntax ist einheitlich. Gut oder schlecht?
Viele finden das gut. Hier sind einige beispiele aus Python:
x = 3 # x ist jetzt gleich 3
name = "MZ" # und name gleich "MZ"
print(x + 4) # das wäre 7
def adder(x, y): # So wird eine Funktion definiert.
return x + y
print(adder(2, 3))
print("Hello world!") # das printed "Hello world!"
print(f"Hello {name}!") # und das "Hello MZ!"
if x < 10:
print("zap".upper()) # ZAP
else:
print("zoop".title()) # Zoop
und das gleiche in Racket:
#lang racket
(define x 3)
(define name "MZ")
(+ x 4)
(define (adder x y) (+ x y)) ; Diese Funktion addiert x und y
(adder 2 3) ; z.B. 5
(displayln "Hello world!")
(printf "Hello ~a~n" name)
(if (< x 10)
(println (string-upcase "zap"))
(println (string-titlecase "zoop")))
1.5.3. Variablen und einfache Datentypen
1.5.3.1. Was sind elementare/einfache Datentypen?
| Name | Beispiel |
| Char | c C 😎 |
| String | "hallo!" "MZ" "3" |
| Integer | 1 -12 1343208 0 |
| Float | 3.14 -12.9 -1.0 |
1.5.3.2. Variablen
Mit define gibt man einem Wert einen Namen:
#lang racket
(define message "Hello world!")
(displayln message)
Hello world!
Man kann einen Namen auch neu binden:
#lang racket
(define message "Hallo World")
(displayln message)
(set! message "Herzlich wilkommen!")
(displayln message)
Hallo World Herzlich wilkommen!
Wichtiger Unterschied: define führt eine neue Bindung ein, set!
verändert eine bestehende. In Racket bindet man meist lieber neu,
statt zu mutieren - Mutation braucht man nur, wenn sie wirklich nötig ist.
1.5.3.2.1. Aufgabe: Neu binden
Definiere eine Variable favorite-food mit deinem Lieblingsessen
und gib sie aus. Binde sie dann mit set! an ein anderes Essen und
gib sie erneut aus.
1.5.3.2.2. Lösung:
#lang racket
(define favorite-food "Pizza")
(displayln favorite-food)
(set! favorite-food "Sushi")
(displayln favorite-food)
Pizza Sushi
1.5.3.3. Regeln für Bezeichner
Variable- und Funktion-namen dürfen aus Buchstaben, Ziffern, Unterstrichen und Bindestrichen bestehen, dürfen aber nicht mit einer Ziffer beginnen und nicht mit einem reservierten Wort kollidieren. Üblich ist kebab-case.
1.5.3.3.1. Sidequest: Kebab-case?
Ja. Es gibt kebab-case, camelCase, snakecase und noch vieles mehr.
1.5.3.4. Weiter geht’s mit string-append:
#lang racket
(define student-name "Max")
(define greeting (string-append "Hallo, " student-name "!"))
(displayln greeting)
Hallo, Eric!
#lang racket
(define student-name "Max")
(define greeting (string-append "Hallo, " student-name "!"))
(displayln greeting)
(set! student-name "Mara") ; student-name hat sich verändert...
(displayln greeting) ; greeting aber nicht!
(displayln student-name)
Hallo, Max! Hallo, Max! Mara
Racket hat außerdem zwei Namenskonventionen, die man ab jetzt überall
wiedersehen wird: Funktionen, die eine Ja/Nein-Frage beantworten,
enden auf ?; Funktionen, die etwas verändern (mutieren), enden
auf !. Am Namen allein erkennt man also schon, was eine Funktion tut:
#lang racket
(displayln (even? 4)) ; gerade?
(displayln (string=? "a" "b")) ; sind die String gleich?
#t #f
1.5.3.4.1. Aufgabe: ?-Funktionen erkennen
Schreibe zwei Testausdrücke: einen mit zero? und einen mit
string=?, und gib beide mit displayln aus.
1.5.3.4.2. Lösung:
#lang racket
(displayln (zero? 0))
(displayln (string=? "racket" "racket"))
#t #t
1.5.3.5. Mehr String-funktionen!
1.5.3.5.1. Groß-/Kleinschreibung ändern
#lang racket
(define name "ada lovelace")
(displayln (string-titlecase name))
(displayln (string-upcase name))
(displayln (string-downcase name))
Ada Lovelace ADA LOVELACE ada lovelace
Definiere deinen eigenen Namen als String in Kleinbuchstaben und gib ihn in allen drei Varianten aus (titlecase, upcase, downcase).
#lang racket
(define my-name "clara schmidt")
(displayln (string-titlecase my-name))
(displayln (string-upcase my-name))
(displayln (string-downcase my-name))
Clara Schmidt CLARA SCHMIDT clara schmidt
1.5.3.5.2. Strings kombinieren / interpolieren
#lang racket
(define first-name "ada")
(define last-name "lovelace")
(define full-name (string-append first-name " " last-name))
(displayln (string-titlecase full-name))
;; formatierte Ausgabe mit printf
(printf "Hallo, ~a!~n" (string-titlecase full-name))
Ada Lovelace Hallo, Ada Lovelace!
Definiere zwei Variablen subject (“Racket”) und verb (“macht
Spaß”) und kombiniere sie mit string-append zu einem Satz. Gib den
Satz auch noch einmal mit displayln aus.
#lang racket
(define subject "Racket")
(define verb "macht Spaß")
(define sentence (string-append subject " " verb "!"))
(displayln sentence)
Racket macht Spaß!
1.5.3.5.3. Wie funktioniert printf?
printf printed sachen schön, und man kan Variablen in String benutzen.
#lang racket
(define full-name "charles babbage")
(printf "Hi ~a!~n" (string-titlecase full-name))
~a ist Platzhalter für eine Variable. ~n heißt: neue Zeile!
Definiere zwei Variablen first-name und last-name und kombiniere sie mit string-append zu einem Satz. Gib den
Satz mit printf aus, und füge “! Wie geht es dir?” am Ende zu.
#lang racket
(define first-name "Omid")
(define last-name "Mashregh Zamini")
(define full-name (string-append first-name " " last-name))
(printf "~a! Wie geht es dir?~n" full-name)
Omid Mashregh Zamini! Wie geht es dir?
1.5.3.5.4. Leerraum
#lang racket
(define favorite-language "\tRacket ")
(displayln favorite-language)
(displayln (string-trim favorite-language))
Racket Racket
Definiere messy als \" Hallo Welt \" mit führenden und
nachfolgenden Leerzeichen. Gib sie einmal roh und einmal getrimmt aus.
#lang racket
(define messy " Hallo Welt ")
(displayln messy)
(displayln (string-trim messy))
Hallo Welt Hallo Welt
1.5.3.6. Zahlen
1.5.3.6.1. Ganzzahlen und exakte Arithmetik
Ganzzahlen sind in Racket standardmäßig exakt und beliebig groß - kein Überlauf.
#lang racket
(displayln (+ 2 3))
(displayln (- 3 2))
(displayln (* 2 3))
(displayln (/ 3 2)) ; exakte rationale Zahl, nicht abgeschnitten!
(displayln (expt 3 2))
(displayln (modulo 3 2))
(displayln (modulo 4 2))
5 1 6 3/2 9 1 0
Berechne mit den Zahlen 7 und 4: Summe, Differenz, Produkt, Quotient (als exakter Bruch) und 7 hoch 2.
#lang racket
(displayln (+ 7 4))
(displayln (- 7 4))
(displayln (* 7 4))
(displayln (/ 7 4))
(displayln (expt 7 2))
11 3 28 7/4 49
1.5.3.6.2. Gleitkommazahlen
#lang racket
(displayln (+ 0.1 0.2))
(displayln (* 2 3.0))
0.30000000000000004 6.0
Addiere 0.3 und 0.6, und multipliziere 5 mit 2.5. Beobachte, ob das Ergebnis der Addition exakt aussieht.
#lang racket
(displayln (+ 0.3 0.6))
(displayln (* 5 2.5))
0.8999999999999999 12.5
1.5.3.6.3. Zahlen in Strings
#lang racket
(define age 23)
(define message (string-append "Alles Gute zum " (number->string age) ". Geburtstag!"))
(displayln message)
;; oder mit printf
(printf "Alles Gute zum ~a. Geburtstag!\n" age)
Alles Gute zum 23. Geburtstag! Alles Gute zum 23. Geburtstag!
Definiere year mit dem Wert 2026 und baue den Satz “Das Jahr ist
2026.” einmal mit string-append~/~number->string und einmal mit
printf.
#lang racket
(define year 2026)
(define message (string-append "Das Jahr ist " (number->string year) "."))
(displayln message)
(printf "Das Jahr ist ~a.\n" year)
Das Jahr ist 2026. Das Jahr ist 2026.
1.5.3.7. Kommentare
#lang racket
; einzeiliger Kommentar
;; Konvention: zwei Semikolons für eigenständige Kommentare
#| ein Blockkommentar
über mehrere Zeilen |#
(displayln "Code, kein Kommentar")
Code, kein Kommentar
1.5.4. Einführung in Listen
Der zentrale Sequenztyp in Racket ist die Liste, aufgebaut aus
cons-Zellen. Eine Liste ist entweder die leere Liste ']() oder
ein Element, vorne angehängt an eine (kürzere) Liste.
1.5.4.1. Was ist eine Liste?
Alles ist eine Liste! Listen sind alles was in () vorkommen. Das heißt in Racket sind alle Funktionen und Data tatsächlich Listen. LISP steht ja für LISt Processor!
#lang racket
(define bicycles (list "trek" "cannondale" "redline" "specialized"))
(displayln bicycles)
(trek cannondale redline specialized)
#lang racket
(define bicycles '("trek" "cannondale" "redline" "specialized"))
(displayln bicycles)
(trek cannondale redline specialized)
Das ' am Anfang von ’(“trek” …etc) sagt uns, dass diese Liste eine List-Literal ist. Das heißt, es wird nicht evaluiert. Das heißt, das ist nicht eine Funktion namens “trek” was die Argumente “cannondale” “redline” und “specialized” entgegennimmt.
list ist nur eine bequeme Schreibweise. Von Hand mit cons gebaut,
ist es dieselbe Liste:
#lang racket
(define bicycles
(cons "trek"
(cons "cannondale"
(cons "redline"
(cons "specialized"
'())))))
(displayln bicycles)
(trek cannondale redline specialized)
1.5.4.1.1. Aufgabe: Eigene Liste erstellen
Erstelle eine Liste hobbies mit drei deiner Hobbys und gib sie aus.
1.5.4.1.2. Lösung:
#lang racket
(define hobbies (list "gitarre" "programmieren" "schach"))
(displayln hobbies)
(gitarre programmieren schach)
1.5.4.2. Listen sind unveränderlich (immutable)
Eine Racket-Liste kann nach dem Erzeugen nicht verändert werden - es
gibt kein “Element x oder y überschreiben”. Stattdessen bauen alle
Listen-Funktionen (cons, append, map, filter, sort,
reverse, …) aus einer alten Liste eine neue Liste, ohne die
alte anzufassen. Ein angenehmer Nebeneffekt/Side-effect: geteilte Struktur ist
immer gefahrlos.
#lang racket
(define my-foods (list "pizza" "falafel" "carrot cake"))
(define friend-foods my-foods)
(define my-foods2 (cons "cannoli" my-foods))
(define friend-foods2 (append friend-foods (list "ice cream")))
(displayln my-foods)
(displayln friend-foods)
(displayln my-foods2)
(displayln friend-foods2)
(pizza falafel carrot cake) (pizza falafel carrot cake) (cannoli pizza falafel carrot cake) (pizza falafel carrot cake ice cream)
my-foods und friend-foods zeigen immer noch auf dieselbe,
unveränderte Liste - obwohl daraus zwei neue Listen gebaut wurden.
1.5.4.2.1. Aufgabe: Original bleibt unverändert
Erstelle colors mit drei Farben. Binde colors2 mit
(cons "gold" colors) an eine neue Liste. Gib beide Listen aus und
überzeuge dich, dass colors unverändert ist.
1.5.4.2.2. Lösung:
#lang racket
(define colors (list "rot" "grün" "blau"))
(define colors2 (cons "gold" colors))
(displayln colors)
(displayln colors2)
(rot grün blau) (gold rot grün blau)
1.5.4.3. Zugriff auf Elemente
Das erste Element holt man mit car, allgemein mit list-ref
(nullbasiert!):
#lang racket
(define bicycles (list "trek" "cannondale" "redline" "specialized"))
(displayln (car bicycles))
(displayln (list-ref bicycles 0))
(displayln (string-titlecase (car bicycles)))
trek trek Trek
Das letzte Element erreicht man mit last:
#lang racket
(define bicycles (list "trek" "cannondale" "redline" "specialized"))
(displayln (last bicycles))
specialized specialized
1.5.4.3.1. Aufgabe: Erstes und letztes Element
Definiere teams mit vier Mannschaftsnamen. Gib das erste Element
mit car und list-ref aus, sowie das dritte Element (Index 2).
Gib danach das letzte Element mit last aus.
1.5.4.3.2. Lösung:
#lang racket
(define teams (list "adler" "löwen" "falken" "wölfe"))
(displayln (car teams))
(displayln (list-ref teams 2))
(displayln (string-titlecase (car teams)))
(displayln (last teams))
adler falken Adler wölfe
1.5.4.4. Elemente verwenden
#lang racket
(define bicycles (list "trek" "cannondale" "redline" "specialized"))
(define message (string-append "Mein erstes Fahrrad war ein "
(string-titlecase (list-ref bicycles 0))
"."))
(displayln message)
Mein erstes Fahrrad war ein Trek.
1.5.4.4.1. Aufgabe: Satz aus einem Listenelement bauen
Baue mit teams und list-ref den Satz “Mein Lieblingsteam sind
die Adler.”
1.5.4.4.2. Lösung:
#lang racket
(define teams (list "adler" "löwen" "falken" "wölfe"))
(define message (string-append "Mein Lieblingsteam sind die "
(string-titlecase (list-ref teams 0))
"."))
(displayln message)
Mein Lieblingsteam sind die Adler.
1.5.4.5. Neue Listen aus alten bilden
Da Listen unveränderlich sind, “verändert” man sie nicht - man baut eine neue Liste und gibt ihr bei Bedarf einen Namen.
1.5.4.5.1. Vorne anfügen und anhängen
cons fügt vorne an (schnell, die natürliche Richtung für eine
verkettete Liste); append fügt am Ende an (langsamer, da die ganze
Liste durchlaufen wird):
#lang racket
(define motorcycles (list "honda" "yamaha" "suzuki"))
;; am Ende anhängen -> neue Liste
(define motorcycles-plus-ducati (append motorcycles "ducati"))
(displayln motorcycles-plus-ducati)
;; vorne einfügen -> neue Liste
(define motorcycles-plus-kawa (cons "kawasaki" motorcycles))
(displayln motorcycles-plus-kawa)
;; das Original bleibt unverändert
(displayln motorcycles)
(honda yamaha suzuki . ducati) <- warum ist da ein Punkt...? Erst mal unwichtig! (kawasaki honda yamaha suzuki) (honda yamaha suzuki)
Eine Liste “Schritt für Schritt” mit wiederholtem append aufzubauen
ist unnötig und langsam - meist schreibt man die Liste direkt hin,
oder baut sie mit map bzw. for/list aus einer anderen Liste. Das kommt später!
#lang racket
(define motorcycles2 (list "honda" "yamaha" "suzuki"))
(displayln motorcycles2)
(honda yamaha suzuki)
Definiere fruits mit drei Früchten. Häng “kiwi” hinten mit
append an, füg “erdbeere” vorne mit cons ein, und zeig, dass das
Original unverändert bleibt.
#lang racket
(define fruits (list "apfel" "banane" "orange"))
(define fruits-plus-kiwi (append fruits (list "kiwi")))
(displayln fruits-plus-kiwi)
(define fruits-plus-erdbeere (cons "erdbeere" fruits))
(displayln fruits-plus-erdbeere)
(displayln fruits)
(apfel banane orange kiwi) (erdbeere apfel banane orange) (apfel banane orange)
1.5.4.5.2. Elemente entfernen (ohne Index)
remove löscht das erste passende Element, filter entfernt alle
Treffer (bzw. behält alles, was eine Bedingung erfüllt):
#lang racket
(define motorcycles (list "honda" "yamaha" "suzuki"))
(displayln (remove "honda" motorcycles))
(displayln motorcycles)
;; alle Treffer entfernen (remove löscht nur den ersten)
(define more-motorcycles (list "honda" "yamaha" "honda" "suzuki"))
(displayln (filter (lambda (m) (not (string=? m "honda"))) more-motorcycles))
(yamaha suzuki) (honda yamaha suzuki) (yamaha suzuki)
Braucht man das entfernte Element noch (z. B. für eine Ausgabe),
liest man es vorher mit car aus:
#lang racket
(define motorcycles (list "honda" "yamaha" "suzuki"))
(printf "Das entfernte Motorrad war: ~a\n" (car motorcycles))
(displayln (remove (car motorcycles) motorcycles))
Das entfernte Motorrad war: honda (yamaha suzuki)
Definiere pets mit vier Tieren, wobei “hund” doppelt vorkommt.
Entferne mit remove nur den ersten Treffer, und mit filter alle
Treffer. Zeig, dass pets dabei unverändert bleibt.
#lang racket
(define pets (list "hund" "katze" "hund" "hamster"))
(displayln (remove "hund" pets))
(displayln (filter (lambda (p) (not (string=? p "hund"))) pets))
(displayln pets)
(katze hund hamster) (katze hamster) (hund katze hund hamster)
1.5.4.6. Eine Liste organisieren
1.5.4.6.1. Sortieren
sort verändert die Liste nicht, sondern gibt eine neue, sortierte
Liste zurück:
#lang racket
(define cars (list "bmw" "audi" "toyota" "subaru"))
(displayln (sort cars string<?)) ; aufsteigend
(displayln (sort cars string>?)) ; absteigend
(displayln cars) ; Original unverändert!
(audi bmw subaru toyota) (toyota subaru bmw audi) (bmw audi toyota subaru)
Definiere subjects mit vier Schulfächern. Sortiere sie aufsteigend
und absteigend, und zeig, dass das Original unverändert bleibt.
#lang racket
(define subjects (list "mathe" "informatik" "musik" "deutsch"))
(displayln (sort subjects string<?))
(displayln (sort subjects string>?))
(displayln subjects)
(deutsch informatik mathe musik) (musik mathe informatik deutsch) (mathe informatik musik deutsch)
1.5.4.6.2. Umkehren
#lang racket
(define cars (list "bmw" "audi" "toyota" "subaru"))
(displayln (reverse cars))
(displayln cars)
(subaru toyota audi bmw) (bmw audi toyota subaru)
Kehre subjects aus der vorigen Aufgabe mit reverse um und gib
danach auch das (unveränderte) Original aus.
#lang racket
(define subjects (list "mathe" "informatik" "musik" "deutsch"))
(displayln (reverse subjects))
(displayln subjects)
(deutsch musik informatik mathe) (mathe informatik musik deutsch)
1.5.4.6.3. Länge
#lang racket
(sum)
(define cars (list "bmw" "audi" "toyota" "subaru"))
(displayln (length cars))
4
Gib die Länge von subjects mit length aus.
#lang racket
(define subjects (list "mathe" "informatik" "musik" "deutsch"))
(displayln (length subjects))
4
1.5.5. Arbeiten mit Listen
1.5.5.1. Eine Liste durchlaufen
for-each durchläuft eine Liste und führt für jedes Element eine
Aktion aus (z. B. Ausgabe):
#lang racket
(define magicians (list "alice" "david" "carolina"))
(for-each displayln magicians)
alice david carolina
Für mehrere Anweisungen pro Durchlauf schreibt man einfach mehrere Ausdrücke im Lambda-Körper:
#lang racket
(define magicians (list "alice" "david" "carolina"))
(for ((magician magicians)) ; warum (())? Ist erst mal so :)
(printf "~a, das war ein toller Trick!\n" (string-titlecase magician))
(printf "Ich kann deinen nächsten Trick kaum erwarten, ~a.\n\n" (string-titlecase magician)))
Alice, das war ein toller Trick! Ich kann deinen nächsten Trick kaum erwarten, Alice. David, das war ein toller Trick! Ich kann deinen nächsten Trick kaum erwarten, David. Carolina, das war ein toller Trick! Ich kann deinen nächsten Trick kaum erwarten, Carolina.
1.5.5.1.1. Aufgabe: Bands anfeuern
Definiere bands mit drei Bandnamen. Gib mit for-each für jede
Band “\~a rockt!” aus.
1.5.5.1.2. Lösung:
#lang racket
(define bands (list "queen" "acdc" "rush"))
(for ((band bands))(printf "~a rockt!\n" (string-titlecase band)))
Queen rockt! Acdc rockt! Rush rockt!
1.5.5.2. Filtern mit filter
Will man aus einer Liste nur die Elemente behalten, die eine
Bedingung erfüllen, verwendet man filter:
#lang racket
(define numbers (range 1 11))
(displayln (filter even? numbers))
(displayln (filter odd? numbers))
(2 4 6 8 10) (1 3 5 7 9)
1.5.5.3. Numerische Listen erzeugen
1.5.5.3.1. range verwenden
range erzeugt eine Liste von Zahlen; der Endpunkt ist exklusiv,
eine Schrittweite ist optional:
#lang racket
(displayln (range 1 5))
(for ((value (range 1 5))) (displayln value))
(displayln (range 1 11 2))
(1 2 3 4) 1 2 3 4 (1 3 5 7 9)
Gib (range 0 20 5) aus, und danach (range 10 0 -2) (rückwärts,
mit negativer Schrittweite).
#lang racket
(displayln (range 0 20 5))
(displayln (range 10 0 -2))
(0 5 10 15) (10 8 6 4 2)
1.5.5.3.2. Einfache Statistik
#lang racket
(define numbers (range 1 11))
(printf "min: ~a\n" (apply min numbers)) ; warum apply? Apply wendet 'min' auf alle Elemente in numbers.
(printf "max: ~a\n" (apply max numbers))
(printf "summe (mit apply): ~a\n" (apply + numbers)) ; und was passiert hier?
(printf "summe (mit for/sum): ~a\n" (for/sum ((n numbers)) n)) ; und hier?
min: 1 max: 10 summe (mit apply): 55 summe (mit for/sum): 55
Definiere scores als Liste (1 3 5 7 11 13) und gib min, max und
Summe (mit for/sum) aus.
#lang racket
(define scores (list 1 3 5 7 11 13))
(printf "min: ~a\n" (apply min scores))
(printf "max: ~a\n" (apply max scores))
(printf "summe: ~a\n" (for/sum ((s scores)) s))
min: 1 max: 13 summe: 40
1.5.5.3.3. Listen aus Berechnungen erzeugen mit for/list und map
Beide bauen eine neue Liste aus einer Berechnung - for/list ist
eine Art List Comprehension, map wendet eine Funktion direkt auf
jedes Element an. Für einfache Fälle sind sie austauschbar:
#lang racket
(define squares (for/list ((value (in-range 1 11))) (sqr value)))
(define squares2 (map sqr (range 1 11)))
(displayln squares)
(displayln squares2)
(1 4 9 16 25 36 49 64 81 100) (1 4 9 16 25 36 49 64 81 100)
Bilde die Liste der Kubikzahlen (n * n * n) der Zahlen 1 bis 5 und das mit for/list.
#lang racket
(define cubes (for/list ((value (in-range 1 6))) (* value value value)))
(displayln cubes)
(1 8 27 64 125)
1.5.5.4. Mit einem Teil einer Liste arbeiten
1.5.5.4.1. Ausschnitte (Slicing)
take liefert die ersten n Elemente, drop überspringt die ersten n:
#lang racket
(define players (list "charles" "martina" "michael" "florence" "eli"))
(displayln (take players 3)) ; die ersten drei
(displayln (drop players 1)) ; alle außer dem ersten
(displayln (take (drop players 1) 3)) ; Elemente 2 bis 4
(charles martina michael) (martina michael florence eli) (martina michael florence)
Definiere runners mit fünf Namen. Gib die ersten zwei mit take
aus, alle außer den ersten zwei mit drop.
#lang racket
(define runners (list "amir" "beatrix" "chen" "dana" "elias"))
(displayln (take runners 2))
(displayln (drop runners 2))
(amir beatrix) (chen dana elias)
2. Wahlpflichtfach Informatik
2.1. WPU A - Sprache: Python
2.1.1. Elementare Datentypen
| Typ | Beschreibung | Beispiel |
|---|---|---|
Variabel |
Etiketten, die Werte speichern. | message = "hallo" |
| Dürfen Buchstaben, Ziffern und Unterstriche enthalten; keine Leerzeichen; werden kleingeschrieben | ||
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. WPU B - Sprache: Common Lisp
WORK IN PROGRESS
Aus dem Buch: “ANSI Common Lisp” von Paul Graham, Kapitel 2, zusammengefasst und übersetzt teilweise mit Hilfe von KI.
2.2.1. Lisp? Bitte was?
- LISP gibt es seit 1960!
- Hat hauptsächlich die Mathematiker interessiert.
- …und die, die sich mit KI beschäftigen wollten.
Der Erfinder,
John McCarthy, war ein KI-Forscher.
- Es gibt VIELE Versionen davon, z.B. Common Lisp, Scheme, Franz Lisp, MacLisp, Emacs Lisp
- Wir benutzen Common Lisp, und unser IDE (Integrated Development Environment) heisst
mine. - Es ist Interaktiv wie alle LISPs. (Normalerweise sind Programmiersprachen wie C und Java nicht interaktiv).
2.2.2. Kapitel 2
2.2.2.1. Welcome to Lisp!
2.2.2.1.1. Form
- Lisp läuft interaktiv über ein Toplevel in
REPL(Read Evaluate Print Loop): man tippt einen Ausdruck ein, bekommt sofort den Wert zurück, dann kommt der nächste Prompt (>). - Selbstauswertende Atome: eine Zahl wie
1ergibt einfach1, und ein Atom wie'aergibt'a. - Funktionsaufrufe in Präfixnotation: Operator zuerst, dann die Argumente, alles in Klammern.
(+ 2 3)statt2 + 3. - Das ist komisch, und macht Lisp ganz anderes, aber ist eins der besten Features.
Weil die Klammern den Ausdruck begrenzen und nicht die Anzahl der Argumente, kann ein Operator beliebig viele Argumente nehmen, auch keine:
(+) ;; => 0 (+ 2) ;; => 2 (+ 2 3 4 5) ;; => 14Ausdrücke lassen sich beliebig verschachteln, Argumente können selbst wieder Ausdrücke sein:
(/ (- 7 1) (- 4 2)) ;; => 3- In Lisp ist alles entweder ein Atom oder eine Liste. Eine einzige Syntax für alles, im Gegensatz zu C, wo Arithmetik, Aufrufe, Anweisungen und Blöcke jeweils eigene Syntax haben.
Das heisst, dass Lisp kaum Syntax hat, und wir können uns ziemlich schnell mit Informatik (anstatt die Sprache) beschäftigen.
Beispiel:
Program Python Lisp addiere zwei Zahlen 2 + 3(+ 2 3)Printe “Hallo” print("Hallo")(print "hallo")Schreibe “abc” gross "a b c".upper()(string-upcase "a b c")Gebe den grösseren Wert zurück if (a > b): return a else: return b(if (> a b) a b)Definiere eine Addition-Funktion def adder(a, b): return (a + b)(defun adder (a b) (+ a b))Eine Schlüsselwertpaarsammlung {key:value, key2:value2}((key value) (key value))- Ja, Lisp sieht doch einfacher aus, trotz der ganzen Klammern, weil die Syntax immer gleich bleibt. Alles ist eine Liste oder ein Atom. Listen werden evaluiert. Cool!
2.2.2.1.2. Evaluation
WICHTIG
- Auswertungsregel für Funktionsaufrufe: erst alle Argumente von links nach rechts auswerten, dann die Werte an die Funktion des Operators übergeben.
- Verschachtelte Aufrufe werden nach der gleichen Regel von innen nach außen ausgewertet.
quoteist die Ausnahme, ein Special Operator mit eigener Regel: gib das Argument einfach unverändert zurück.'xist Kurzform für(quote x).(quote (+ 3 5)) ;; => (+ 3 5) und nicht 8 '(+ 3 5) ;; => (+ 3 5), gleiche Sache (cons 'a '(b c)) ;; => '(a b c) '(cons 'a '(b c)) ;; => '(cons 'a '(b c))- Quoten schützt Daten davor, als Code gelesen zu werden.
- I.d.R. werden alle Listen als Formen interpretiert, also das erste Element wird als Funktion interpretiert, und alle andere Elemente als Argumente.
'verhindert das.
2.2.2.2. Data
- Integer und Strings werten sich selbst aus:
256,"ora et labora". - Symbole sind Wörter, werden automatisch großgeschrieben und werten
sich nicht selbst aus, sie stehen für Variablennamen. Wer das Symbol
selbst meint, muss quoten:
'artichoke => ARTICHOKE. Listen müssen ebenfalls gequotet werden, sonst liest Lisp sie als Funktionsaufruf:
'(my 3 "sons") ;; => (MY 3 "sons") und nicht die Funktion my auf 3 und "sons" '(the list (a b c) has 3 elts) ;; ein Quote schützt den ganzen Baumlistselbst ist eine Funktion, ihre Argumente werden also ganz normal ausgewertet:(list 'a (+ 2 1) "sons") ;; => (A 3 "sons")- Wichtige Konsequenz: Lisp-Programme sind selbst Listen. Gequotet oder nicht gequotet ist der einzige Unterschied zwischen “das ist Daten” und “das ist Code”, die Grundlage für Makros. Das kommt später auf uns zu und ist richtig cool.
- Leere Liste:
()undnilsind dasselbe Objekt, wird immer alsNILangezeigt.
2.2.2.3. List Operationen
consbaut ein Paar bzw. hängt vorne an eine Liste an:(cons 'a '(b c d)) => (A B C D)indem sie ein Atom und eine Liste kombiniert.listist eigentlich nur wiederholtes Consen aufnil.(cons 1 (cons 2 (cons 3 '())))) ;; '(1 2 3) (list 1 2 3) ; auch '(1 2 3)carundcdrholen erstes Element bzw. den Rest der Liste.(car '(a b c)) ; => A (cdr '(a b c)) ; => (B C)Kombinationen wie
(car (cdr (cdr lst)))gibt es als Abkürzung, z.B.thirdodercadr. Das geht vonfirstbistenth.(defun our-third (lst) (car (cdr (cdr lst)))) (our-third '(a b c d)) ;; => C
2.2.2.4. Wahrheit
tist der klassische Wahrwert,nilder einzige Falschwert. Alles andere zählt in einem Wahrheitskontext als wahr.Wichtig: Prädikate (Funktionen, die true/false zurückgeben) enden per Konvention auf
-p:listp(ist das eine Liste?),numberp(ist das eine Zahl?),null(ist das nichts?).(listp '(1 2 3))) ; => T (numberp "Hi") ; => NILifist ein Special Operator, weil eben nur ein Zweig ausgewertet werden darf:(if test then else), der else-Zweig ist optional undfällt sonst auf
nilzurück.(if (> 4 2) (+ 1 2) (+ 4 5)) ; => 3andundorsind kurzschließende Makros, keine reinen Booleschen Operatoren, sie geben den Wert des entscheidenden Arguments zurück, nicht nurtodernil.
2.2.2.5. Funktionen
defunbraucht Name, Parameterliste, Body.(defun our-third (x) (car (cdr (cdr x))))- Parameter sind einfach Variablen, die nur innerhalb des Aufrufs gebunden sind.
- Es gibt keinen Unterschied zwischen “Funktion”, “Prozedur” und “Programm”. Alles ist eine Funktion und kann direkt vom Toplevel aus aufgerufen werden, dadurch testet man ganz natürlich Stück für Stück. Das ist extrem cool!
2.2.2.6. Rekursion
Eine Funktion, die sich selbst aufruft.
(defun our-member (obj lst) (if (null lst) nil (if (eql (car lst) obj) lst (our-member obj (cdr lst)))))- Beim Lesen: Basisfall (leere Liste, also kein Mitglied), Trefferfall (erstes Element ist es), rekursiver Fall (Rest der Liste prüfen).
- Wichtig ist das richtige mentale Modell: eine Funktion nicht als Maschine denken, die Arbeit an sich selbst delegiert (das wirkt paradox), sondern als Beschreibung eines Vorgangs, der sich selbst wieder anwendet. Gleiche Idee wie “prüfe dieses Dokument, wenn es andere zitiert, prüfe die auch”.
2.2.2.7. Input & Output
formatist die allgemeine Ausgabefunktion: Ziel, Template-String, dann die Werte zum Einsetzen.~Ssetzt das nächste Argument ein,~%ist ein Zeilenumbruch.(format t "~S plus ~A equals ~S.~%" 2 3 (+ 2 3)) ;; Ausgabe: 2 plus 3 equals 5.readliest und parst (versteht) einen kompletten Lisp-Ausdruck von der Eingabe, kein roher Text, sondern ein echtes Lisp-Objekt.- Der Body einer Funktion kann mehrere Ausdrücke haben, alle außer dem letzten sind nur wegen ihrer Seiteneffekte da (ihr Wert wird verworfen).
- “Reines” Lisp heißt keine Seiteneffekte.
formatmit seiner Ausgabe ist das erste Beispiel im Buch, das welche hat.
2.2.2.8. Variablen
letführt lokale Variablen ein, eine Liste aus(var init-ausdruck)Paaren, danach der Body.(let ((x 1) (y 2)) (+ x y)) ;; => 3- Globale Variablen mit
defparameter(veränderbar) oderdefconstant(konstant). Konvention: globale Namen mit*sternchen*(nennt sich earmuffs 😀) umranden, damit sie nicht mit lokalen Variablennamen kollidieren. - Nicht so wichtig für uns:
boundpprüft, ob ein Symbol gerade eine Variable benennt.
2.2.2.9. Assignment (Zuweisung)
setfist der allgemeine Zuweisungsoperator, funktioniert für normale Variablen und für “Places” ((setf (car x) 'n)verändert das erste Cons vonx).(setf lst '(a b c)) ; => (a b c) (setf (car lst) 'd) ; => d lst ; => (d b c)
2.2.2.10. Functional Programming
- Code schreiben, der über Rückgabewerte funktioniert, statt über verändertem Zustand.
- Eingebaute Funktionen sind meist nicht destruktiv:
removegibt eine neue Liste zurück, das Original bleibt unangetastet. Wer wirklich Elemente loswerden will, bindet neu:(setf x (remove 'a x)). Das ist aber nicht besonders Funktional. - Der Gewinn: rein funktionaler Code lässt sich Stück für Stück direkt am REPL testen, sofortiges Feedback, kein versteckter Zustand, den man zwischen Tests zurücksetzen müsste.
2.2.2.11. Iteration (Schleifen)
doist das allgemeine Iterationsmakro: Variablenspezifikationen(var init update), dann eine(test ergebnis...)Klausel, dann der Body.(defun show-squares (start end) ; nimm start und end (do ((i start (+ i 1))) ; setze i auf start, und nach jedes mal mach i +1 ((> i end) 'done) ; wenn i > end, gebe DONE zurück (format t "~A ~A~%" i (* i i)))) ; währenddessen, printe i und i²
2.2.2.12. Funktionen als Objekte
- Funktionen sind ganz normale Objekte, auf einer Stufe mit Symbolen, Strings, Listen.
function(Special Operator, kein Quote nötig) gibt das Funktionsobjekt zu einem Namen zurück,#'ist die Kurzform, gleiche Beziehung wiequoteund'.applyruft eine Funktion mit einer Argumentliste auf,funcallmacht dasselbe, nimmt die Argumente aber direkt entgegen, nicht als Liste verpackt.(apply #'+ '(1 2 3)) ;; => 6 (funcall #'+ 1 2 3) ;; => 6lambda-Ausdrücke sind anonyme Funktionen, nur Parameterliste plus Body, direkt einsetzbar überall dort, wo eine Funktion erwartet wird. Mehr in Zukunft!
2.2.2.13. Fragen und Antworten
2.2.2.13.1. Was passiert, wenn Lisp einen Ausdruck nicht auswerten kann?
- Man landet in einem Break Loop, quasi ein Error-REPL innerhalb des Toplevels.
- Rauskommen je nach Implementierung, meistens mit der Taste
q, oder einem Abort-Restart (:abortin SBCL bzw. den meisten CL-REPLs oderC-c C-cund Restart-Auswahl in SLIME).
2.2.2.13.2. Warum sieht Lisp-Code nur nach Klammern aus?
- Weil man sie gar nicht zählen soll, man liest und schreibt Lisp nach Einrückung, das Zuordnen der Klammern übernimmt der Editor (Paren-Matching, structural editing).
2.2.2.13.3. Types
- Common Lisp nutzt Manifest Typing: Werte tragen Typen, Variablen nicht. Jede Variable kann jeden Typ aufnehmen, keine Deklaration nötig (optional möglich, wegen Performance, siehe Kapitel 13).
- Typen bilden eine Hierarchie, ein Objekt hat gleichzeitig mehrere
Typen, vom speziellsten zum allgemeinsten (z.B. ist
27gleichzeitigfixnum,integer,rational,real,number,atom,t). tist der Supertyp von allem.typepprüft Typzugehörigkeit:(typep 27 'integer) => T.
2.2.2.14. Zusammenfassung
- Toplevel/REPL ist interaktiv, Ausdruck rein, Wert direkt zurück.
- Ausdrücke sind Atome oder Listen, Präfixnotation, einheitliche Syntax.
Auswertungsregel: Argumente links nach rechts, dann die Funktion des Operators anwenden.
quoteist die einzige Ausnahme (gibt das Argument unverändert zurück).(+ 1 2) ; => 3 '(+ 1 2) ; => '(+ 1 2)
- Symbole und Listen sind native Lisp-Datentypen, deshalb können Lisp-Programme Lisp-Code erzeugen.
cons,car,cdrsind die drei primitiven Listenoperationen.tist wahr,nilist falsch bzw. die leere Liste, alles außer nil zählt als wahr.if,and,or,notsind die grundlegenden Bedingungen.Funktionen mit
defundefinieren, rekursive Funktionen rufen sich selbst auf.(defun adder (x y) (+ x y))- Lisp nach Einrückung lesen und schreiben, nicht nach Klammern zählen.
read(voller Parser) undformat(Template-basierte Ausgabe) sind die grundlegenden I/O-Funktionen.letfür lokale,defparameterfür globale Variablen.setfist der allgemeine Zuweisungsoperator.- Funktionale Programmierung heißt, lieber Werte zurückgeben statt Zustand zu verändern, das ist der Standardstil in Lisp.
doist die allgemeine Iterationsform.Funktionen sind normale Objekte, als Argumente übergebbar.
(car (cdr lst)) ;; car nimmt eine Liste, cdr gibt eine Liste zurück- Werte haben Typen, Variablen nicht.
2.2.2.15. Übungen
2.2.2.15.1. Von Hand durchgehen:
(+ (- 5 1) (+ 3 7))
(list 1 (+ 2 3))
(if (listp 1)
(+ 1 2)
(+ 3 4))
(list
(and (listp 3) t)
(+ 1 2))
2.2.2.15.2. Drei unterschiedliche cons-Ausdrücke finden, die alle zu (A B C) auswerten.
2.2.2.15.3. Eine Funktion schreiben, die mit car/cdr das vierte Element einer Liste zurückgibt.
2.2.2.15.4. Eine Funktion mit zwei Argumenten schreiben, die den größeren Wert zurückgibt.
2.2.2.15.5. Herausfinden, was diese Funktionen machen, dann in Worten erklären:
(defun enigma (x)
(and (not (null x))
(or (null (car x))
(enigma (cdr x)))))
(defun mystery (x y)
(if (null y)
nil
(if (eql (car y) x)
0
(let ((z (mystery x (cdr y))))
(and z (+ z 1))))))
2.2.2.15.6. Nur mit dem, was in diesem Kapitel vorkam, eine Funktion schreiben, die für eine Liste prüft, ob irgendein Element selbst eine Liste ist.
2.2.2.15.7. Je eine iterative und eine rekursive Version schreiben für eine Funktion, die:
- eine positive Zahl nimmt und entsprechend viele Punkte ausgibt
- eine Liste nimmt und zählt, wie oft das Symbol
adarin vorkommt
2.3. WPU C - Sprache: C
Aus dem Buch: “C Programming: A Modern Approach” von K.N. King, teilweise mit KI übesetzt.
2.3.1. Kapitel 1
2.3.1.1. Einführung in C
2.3.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.3.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.3.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.3.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
charzu einemintaddiert werden - Standardbibliothek: Hunderte nützliche Funktionen für I/O, Strings, Speicher, etc.
2.3.1.1.5. Schwächen
- Fehleranfällig: Viele Fehler werden erst zur Laufzeit entdeckt, nicht beim Kompilieren
- Beispiel: Ein fehlendes
&beiscanfführt zum Absturz, wird aber nicht immer erkannt
- Beispiel: Ein fehlendes
- Schwer lesbar: Sehr kompakter, knapper Stil; absichtliche Kürze aus historischen Gründen
- Beispiel:
-+iist gültiger Ausdruck (unäres Minus und Plus)
- Beispiel:
- Schwer wartbar: Großen C-Programmen fehlen Strukturierungsmittel wie Klassen oder Pakete
2.3.1.2. Fragen und Antworten
2.3.1.2.1. Wie kompiliere ich Code in C?
- Mit Hilfe von GCC!
gcc -o programmname programmcode.c
2.3.1.2.2. Wie führe ich nun mein kompiliertes Programm aus?
./programmname
2.3.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.3.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.3.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.3.1.2.6. Wie gründlich prüft GCC auf Fehler?
Nützliche Compiler-Optionen:
-Wall- Aktiviert alle Warnmeldungen
-W- Zusätzliche Warnungen über
-Wallhinaus -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.3.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}stattbegin~/~end,intstattinteger, usw.
2.3.1.2.8. Ist exit(0) dasselbe wie return 0 in main?
- Ja, innerhalb von
mainsind beide gleichwertig - Beide beenden das Programm und geben den Wert 0 an das Betriebssystem zurück
- Welche Variante man wählt, ist Geschmackssache
2.3.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.3.1.2.10. Entfernt der Compiler Kommentare vollständig?
- Nein: laut C-Standard wird jeder Kommentar durch ein einzelnes Leerzeichen ersetzt
- Alter Trick
a/**/bfunktioniert daher nicht; der Compiler siehta b(ungültig)
2.3.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
lintkönnen helfen
2.3.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.3.2. Kapitel 2
2.3.2.1. Grundlagen von C
2.3.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.3.2.1.2. Variablen und Typen
- Variablen müssen vor ihrer Verwendung deklariert werden
intspeichert ganze Zahlen (typisch bis ±2.147.483.647)floatspeichert Dezimalzahlen, aber mit möglichem Rundungsfehler- Beispiel:
0.1fkann intern als0.09999999...gespeichert sein
- Beispiel:
- 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.3.2.1.3. Ausgabe mit printf
%dfürint,%ffürfloat,%.2ffür float mit 2 Nachkommastellen\nfür Zeilenumbruch,\tfü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.3.2.1.4. Eingabe mit scanf
&vor dem Variablennamen ist (meistens) Pflicht; fehlt es, droht Absturz%dfürint,%ffürfloat- scanf überspringt Leerzeichen automatisch beim Suchen nach Zahlen
int hoehe;
printf("Hoehe eingeben: ");
scanf("%d", &hoehe); /* & nicht vergessen! */
2.3.2.1.5. Benannte Konstanten
- Mit
#definewerden 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.3.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,JOBsind drei verschiedene Bezeichner - Schlüsselwörter wie
int,float,return,if,whilesind reserviert und dürfen nicht als Namen verwendet werden - Ungültige Bezeichner:
10mal(beginnt mit Ziffer),get-next(enthält Minus)
2.3.2.2. Fragen und Antworten
2.3.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.0wird intern als1.5 × 2³gespeichert - Andere Sprachen nennen diesen Typ
real
2.3.2.2.2. Warum müssen Gleitkommakonstanten mit f enden?
- Eine Dezimalzahl ohne
fhat den Typdouble(doppelte Genauigkeit) doublekann größer sein alsfloat; daher Warnung möglich bei Zuweisung ohnef- Beispiel:
profit = 2150.48f;ist korrekt;profit = 2150.48;kann Warnung erzeugen
2.3.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.3.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.3.2.3. Übungen
2.3.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.3.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.3.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,lengthundwidthdurch Initialisierungen - (2) Entferne die Variable
weightund berechne(volume + 165) / 166direkt inprintf
2.3.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.3.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.3.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.3.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;ifwäre eines) - (c)
main→ kein Schlüsselwort (reservierter Funktionsname, aber kein Keyword) - (d)
printf→ kein Schlüsselwort (Bibliotheksfunktion) - (e)
while→ Schlüsselwort
2.3.2.4. Programmierprojekte
2.3.2.4.1. Programmierprojekt
Schreibe ein Programm, das folgendes Bild mit printf ausgibt:
*
*
*
* *
* *
*
2.3.2.4.2. Programmierprojekt
Schreibe ein Programm, das das Volumen einer Kugel mit Radius 10 berechnet.
Formel: v = 4/3 * π * r³
- Schreibe
4/3als4.0f/3.0f(sonst ganzzahlige Division → Ergebnis 1) r³alsr * r * r(kein Potenzoperator in C)
2.3.2.4.3. Programmierprojekt
Erweitere Projekt 2: Der Benutzer gibt den Radius selbst ein.
2.3.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.3.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.3.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.3.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.3.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.3.3. Kapitel 3
2.3.3.1. Formatierte Ein-/Ausgabe
2.3.3.1.1. Die printf-Funktion
printfgibt 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.3.3.1.2. Umwandlungsspezifikationen (Conversion Specifications)
- Allgemeine Form:
%m.pXoder%-m.pX(mundpsind optional) m= minimale Feldbreite: Mindestanzahl der Zeichen; Wert wird rechtsbündig ausgegeben%4dzeigt123als·123(·= Leerzeichen)- Wenn der Wert breiter ist als
m, wird das Feld automatisch erweitert %-4dergibt 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.3.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.3.3.1.4. Die scanf-Funktion
scanfliest Eingaben gemäß einem Formatstring und speichert sie in Variablen&vor dem Variablennamen ist (meistens) Pflicht; fehlt es, droht Absturz oder undefiniertes Verhaltenscanfü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.3.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,%fund%gsind beiscanfaustauschbar (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.3.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
scanfsofort ab
2.3.3.1.7. Häufige Fehler: printf vs. scanf verwechseln
&inprintfist ein Fehler:printf("%d", &i);→ gibt seltsame Zahl aus statt den Wert voni\nam Ende einesscanf-Formatstrings ist fast immer falsch:scanf("%d\n", &i);\nwirkt inscanfwie 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.3.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.3.3.2. Fragen und Antworten
2.3.3.2.1. Was ist der Unterschied zwischen %i und %d?
- Bei
printf: kein Unterschied - Bei
scanf:%derkennt nur Dezimalzahlen;%ierkennt auch Oktal- (Präfix0) und Hexadezimalzahlen (Präfix0x) - Falle: Wenn der Benutzer versehentlich eine führende
0eingibt, interpretiert%idie Zahl als oktal - Empfehlung: Bei
%dbleiben
2.3.3.2.2. Wie gibt man das %-Zeichen mit printf aus?
- Zwei aufeinanderfolgende
%-Zeichen:%% - Beispiel:
printf("Gewinn: %d%%\n", gewinn);→Gewinn: 10%
2.3.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.3.3.2.4. Was passiert, wenn scanf eine Zahl erwartet, aber ungültige Eingabe bekommt?
- Eingabe
23foobei%d:scanfliest23,foobleibt für den nächsten Aufruf - Eingabe
foobei%d: Variable bleibt undefiniert,foobleibt im Puffer - Prüfung des Rückgabewerts von
scanfermöglicht Fehlererkennung (Details in Kapitel 22)
2.3.3.2.5. Wie kann scanf Zeichen “zurücklegen”?
- Eingaben werden nicht direkt gelesen, sondern in einem versteckten Puffer gespeichert
scanfkann Zeichen zurück in den Puffer legen, damit sie beim nächsten Aufruf gelesen werden- Details zur Eingabepufferung in Kapitel 22
2.3.3.2.6. Was passiert bei Satzzeichen zwischen Zahlen?
- Eingabe
4,28beiscanf("%d%d", &i, &j);:i= 4,jwird nicht gelesen (Komma passt nicht zu einer Zahl) - Lösung: Komma im Formatstring angeben:
scanf("%d,%d", &i, &j);
2.3.3.3. Übungen
2.3.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.3.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.3.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ässtscanfauf weitere Eingabe warten) - (d)
"%f,%f"vs."%f, %f"→ gleichwertig (Leerzeichen vor%fredundant, da%fohnehin Whitespace überspringt)
2.3.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
scanfliest10für%d, stoppt am Punkt.3wird als Float gelesen (%f)5wird für das zweite%dgelesen6bleibt im Puffer
2.3.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.3wird als Float fürxgelesen45wird als Integer fürigelesen,scanfstoppt am Punkt.6wird als Float fürygelesen789bleibt im Puffer
2.3.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.3.3.4. Programmierprojekte
2.3.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.3.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.3.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.3.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.3.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.3.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.3.4. Kapitel 4
2.3.4.1. Ausdrücke
2.3.4.1.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=-3in 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.3.4.1.2. Zuweisungsoperatoren
- Einfache Zuweisung:
v = e(speichert Wert voneinv;vmuss ein lvalue sein) - Zuweisung ist selbst ein Ausdruck → Ketten möglich:
i = j = k = 0; - Zusammengesetzte Operatoren:
+=,-=,*=,/=,%=v += eistv = v + e, außer wennvNebeneffekte hat (dannvnur 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.3.4.1.3. Inkrement- und Dekrementoperatoren
++i(Präfix): erhöhti, gibt neuen Wert zurücki++(Postfix): gibt alten Wert zurück, erhöht danni--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.3.4.1.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.3.4.1.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.3.4.2. Fragen und Antworten
2.3.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.3.4.2.2. Kann ich % auf float anwenden?
- Nein,
%erfordert Integer-Operanden - Alternative:
fmod()aus<math.h>
2.3.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/7ist entweder-1oder-2; in C99 ist es immer-1
2.3.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.3.4.2.5. ★ Warum ist v += e nicht dasselbe wie v = v + e, wenn v Nebeneffekte hat?
v += e:vwird einmal ausgewertetv = v + e:vwird zweimal ausgewertet → Nebeneffekte verdoppeln sich- Beispiel:
a[i++] += 2;→ieinmal erhöht; mita[i++] = a[i++] + 2;wäre es undefiniertes Verhalten
2.3.4.2.6. Woher stammen ++ und --?
- Von Ken Thompsons früherer Sprache B geerbt; B-Compiler konnte
++ikompakter übersetzen alsi = i + 1 - Kein Geschwindigkeitsvorteil bei modernen Compilern; Beliebtheit beruht auf Kürze und Tradition
2.3.4.2.7. Funktionieren ++ und -- auch mit float-Variablen?
- Ja, aber in der Praxis selten sinnvoll
2.3.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.3.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.3.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
iwar
2.3.4.3. Übungen
2.3.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.3.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.3.4.3.3. Übung 3
Welche Werte haben folgende Ausdrücke in C89? (mehrere Werte möglich bei negativen Operanden)
- (a)
8/5→1 - (b)
-8/5→-1oder-2 - (c)
8/-5→-1oder-2 - (d)
-8/-5→1oder2
2.3.4.3.4. Übung 4
Wie Übung 3, aber in C99 (Division schneidet immer zur Null hin ab):
- (a)
8/5→1 - (b)
-8/5→-1 - (c)
8/-5→-1 - (d)
-8/-5→1
2.3.4.3.5. Übung 5
Welche Werte haben folgende Ausdrücke in C89? (mehrere Werte möglich)
- (a)
8%5→3 - (b)
-8%5→-3oder2 - (c)
8%-5→3oder-2 - (d)
-8%-5→-3oder2
2.3.4.3.6. Übung 6
Wie Übung 5, aber in C99 (Vorzeichen des Rests = Vorzeichen des Dividenden):
- (a)
8%5→3 - (b)
-8%5→-3 - (c)
8%-5→3 - (d)
-8%-5→-3
2.3.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, ergibt10 - 0 = 10— keine gültige einstellige Prüfziffer - Original erzeugt in diesem Fall korrekt
9 - 9 = 0
2.3.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✓; wenntotal % 10 == t:(10-t)%10 = 10-tfürt>0✓
2.3.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.3.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.5abgeschnitten zu2) - (d)
i=2; j=8; j=(i=6)+(j=3); printf("%d %d", i, j);→6 9
2.3.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.3.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.3.4.3.13. Übung 13 ★
Welcher der Ausdrücke ++i und i++ ist genau dasselbe wie (i += 1)?
++i— beide geben den neuen Wert vonizurücki++gibt den alten Wert zurück → nicht äquivalent
2.3.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.3.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 aufi)
2.3.4.4. Programmierprojekte
2.3.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.3.4.4.2. Programmierprojekt 2 ★
Erweitere Projekt 1 für dreistellige Zahlen:
Dreistellige Zahl eingeben: 123
Umgekehrt: 321
2.3.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.3.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.3.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.3.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 GA/EA
Die EA-Themen sind mit * gekennzeichnet.
3.1. Block 0 - Computer-Zahlensysteme
3.1.1. 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
3.1.2. 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
3.1.3. 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 |
3.2. Block 1 - Python und OOP
3.2.1. Links/Hilfe/Allgemein
3.2.2. Elementare Datentypen
| Typ | Beschreibung | Beispiel |
|---|---|---|
Variabel |
Etiketten, die Werte speichern. | message = "hallo" |
| Dürfen Buchstaben, Ziffern und Unterstriche enthalten; keine Leerzeichen; werden kleingeschrieben | ||
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} |
3.2.3. 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) |
3.2.4. 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" |
3.2.5. 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) |
3.2.6. UML Diagramme
- Link von TU Darmstadt
- UML Diagramm von Leonard
- UML Diagramme (graphisch) erstellen
Pro tip: Aus Python Code UML erstellen:
in
pylintPackage, gibt espyreverse. Damit kann man zb mitpyreverse -o png example.pyein UML Diagramm erstellen.
3.3. Block 2 - Rechnernetze
3.3.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.3.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.3.3. Vertraulichkeit
Durch die Vertraulichkeit wird sichergestellt, dass bestimmte Informationen nur den Personen zugänglich sind, die die entsprechenden Berechtigungen haben.
3.3.4. PKI (Public Key Infrastructure)
Infrastruktur zur Verwaltung digitaler Zertifikate.
3.3.4.1. CA (Certificate Authority)
- Zertifizierungsstelle zur Ausstellung digitaler Zertifikate
3.3.4.2. RA (Root Authority)
- Registrierungsstelle zur Identitätsprüfung in einer PKI
3.3.5. Web of Trust *
Dezentrales Vertrauensmodell durch gegenseitige Bestätigung
3.3.6. Verschlüsselung
3.3.6.1. Klartext
Unverschlüsselte, lesbare Nachricht
3.3.6.2. Geheimtext
Verschlüsselte Nachricht
3.3.6.3. Asymmetrisches Verfahren
- Verfahren mit öffentlichem und privatem Schlüssel
- Ein Schlüssel zum ent- und ein Schlüssel zum verschlüsseln
3.3.6.4. Symmetrisches Verfahren
Ein Schlüssel zum Ver- und Entschlüsseln.
3.3.6.5. Schlüsseltauschproblem
Problem des sicheren Schlüsselaustauschs, lösbar durch z.B:
3.3.6.5.1. Diffie-Hellman Verfahren
3.3.6.7. Monoalphabetische Verfahren
- Substitution mit festem Schlüsselalphabet
- Caesar, RSA(?)
3.3.6.8. Polyalphabetische Verfahren
- Substitution mit wechselndem Schlüssel, z.B. ein Wort
- Vigénere
3.3.6.9. Kerckhoff’s Prinzip
3.4. Informatik Allgemein
3.4.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.5. Block 3 EA - Haskell *
3.5.1. Link für Infos und Übungen:
3.5.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.5.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.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 *
3.6.6. 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)
4. Buchempfehlung
4.1. Fachbücher
4.2. Romane
5. Interessante Artikel
6. michmichs
7. Zitate
Lisp ist voll cool, Leute! ~Anonyme Schüler aus der 9. Klasse
Das ist Haskell… alles ist eine Funktion! ~Anonyme Schülerin aus der 12. Klasse
8. Infos
8.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)
8.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-Abteilung.
8.3. Irgendwas ist kaputt? Tippfehler gefunden?
Schreibe mir bitte eine E-mail an omid.mashregh-zamini@gymhum.hamburg.de.