- C++ 89.1%
- Makefile 10.9%
| .github | ||
| .vscode | ||
| data | ||
| doctest@1da23a3e81 | ||
| src | ||
| tests | ||
| .gitignore | ||
| .gitmodules | ||
| Makefile | ||
| readme.md | ||
Programmiertechnik II SS26, Übung 1
Pro Übung gibt es 20 Punkte. Für die Zulassung zur Prüfung müssen in allen Übungen insgesamt mindestens 50 % der Punkte sowie in jeder einzelnen Übung mindestens 25 % erzielt werden.
Der Code für diese Aufgabe kann als Repository geklont und lokal kompiliert werden. Dafür ist es nötig, die Git-Submodule zu initialisieren und zu aktualisieren (wichtig‼️):
git submodule update --init
Anschließend kann
make tests
im Projektordner ausgeführt werden, um die Tests zu kompilieren. (Der Code kann auch unabhängig von den Tests mit make main kompiliert und z. B. mit ./out/main a data/grading_results.db manuell gestartet werden.)
Dev Environment (siehe PT1 im letzten Semester, Übung 1)
- GitHub Codespaces
- geht am schnellsten: einfach aus GitHub Classroom öffnen und loslegen. Kann auch in VS Code Desktop geöffnet werden.
- macOS
- Visual Studio Code mit C/C++ Extension
- git
- clang
- lldb (should be installed after following the previous steps)
- Linux
- Visual Studio Code mit C/C++ Extension
- git
- clang
- gdb (should be installed after following the previous steps)
- Windows
- Visual Studio Code & WSL
- git
- clang
- gdb (should be installed after following the previous steps)
Debugging in VS Code/Codespaces
Im .vscode-Ordner finden Sie zwei Launchfiles/Setups, um den Debugger je nach Programmierumgebung zu starten:
- Visual Studio Code auf macOS
.vscode/launch.jsonmuss entfernt oder umbenannt werden.vscode/launch_macos.jsonmuss zu.vscode/launch.jsonumbenannt werden- Installieren Sie die CodeLLDB Extension in Visual Studio Code
- GitHub Codespaces
- (lokales Linux/WSL2 sollte mit diesem Setup auch funktionieren, wurde aber nicht getestet)
- Installieren Sie die C/C++ Extension
Aufgabenstellung
In dieser Übung implementieren Sie eine kleine Auswertungs-Pipeline für Übungsergebnisse:
- GradingTable liest eine Binärdatei ein und speichert alle Einträge in einer einfach verketteten Liste.
- TaskAgents iterieren/reduzieren über diese Liste und geben Ergebnisse aus.
Projektstruktur:
src/grading_table.h/.cpp– Einlesen der Datenbanksrc/grading_tasks.h/.cpp– Basisklassen & konkrete Tasks (A–E)src/main.cpp– Vorgegeben (CLI-Auswahl des Tasks)data/grading_results.db- Testdatentests/tests.cpp– Tests
Datenformat: data/grading_results.db
Binärdatei mit einer unbekannten Anzahl an Einträgen ohne Trennzeichen. Jeder Eintrag besteht exakt aus drei Werten (insgesamt 64 Bit):
- mat_no (Matrikelnummer) als
std::uint32_t - series (Veranstaltungs-/Übungsnummer) als
std::uint16_t - points (Punkte) als
std::uint16_t
Aufgabe 1 - GradingTable (10 Punkte)
Zu modifizierende Dateien: src/grading_table.h, src/grading_table.cpp
A1.1 Einlesen & Liste aufbauen
Implementieren Sie den Konstruktor GradingTable::GradingTable(std::ifstream& fp) so, dass:
- nur gelesen wird, wenn die Datei geöffnet ist (fp.is_open()).
- Einträge vollständig gelesen werden (alle drei Felder); ansonsten wird sauber abgebrochen.
- für jeden Eintrag ein neues GradingTableEntry erzeugt und in eine einfach verkettete Liste eingehängt wird.
- GradingTable sowohl Kopf als auch Ende der Liste speichert (g_head, g_tail).
Hinweis 1: Eine Spezifikation des ifstream-Interfaces (C++-Filestream) ist verfügbar unter: cplusplus.com/reference/fstream/ifstream/
Hinweis 2: fp.read(...) erwartet char* → benutzen Sie reinterpret_cast<char*>(&feld)
A1.2 Speicher freigeben (Destruktor)
Implementieren Sie GradingTable::~GradingTable() so, dass alle Listenelemente mit delete freigegeben werden.
A1.3 Iterator-Interface (Range-based for)
Ergänzen Sie GradingTable::Iterator und die Methoden begin()/end(), sodass GradingTable das Iterator-Interface implementiert und folgender Code funktioniert:
for (auto& el : table) {
// ...
}
Dafür erforderlich sind:
- operator* liefert Referenz auf aktuelles GradingTableEntry
- operator-> liefert Pointer auf aktuelles GradingTableEntry
- operator++ Prefix, geht zum nächsten Element und liefert Iterator&
- operator++(int) Postfix, liefert alten Iterator-Zustand und geht dann zum nächsten Element
- operator==, operator!= geben an, ob zwei Iteratoren auf dasselbe Element zeigen
- begin() gibt Iterator auf g_head
- end() gibt Iterator, der das Listenende markiert (typisch: nullptr)
Aufgabe 2 - TaskAgents (10 Punkte)
Zu modifizierende Dateien: src/grading_tasks.h, src/grading_tasks.cpp
Sie implementieren eine kleine Klassenhierarchie aus Agents, die alle über performTask() gestartet werden:
IteratingTaskAgent: besucht jedes Element einzeln (visit)ReducingTaskAgent: aggregiert einen Integer-Wert über alle Elemente (reduce)
A2.1 Vererbung & virtuelle Methoden
In src/grading_tasks.h fehlen an mehreren Stellen Schlüsselwörter, damit Polymorphie korrekt funktioniert:
- TaskAgent ist die Basisklasse und besitzt performTask() als "pure virtual function".
- IteratingTaskAgent und ReducingTaskAgent sind abstrakt:
- visit(...) ist pure virtual
- reduce(...) ist pure virtual
- Setzen Sie
overrideüberall dort, wo eine Methode eine Basismethode überschreibt.
A2.2 IteratingTaskAgent: performTask() und visitAll()
Implementieren Sie:
-
int* IteratingTaskAgent::visitAll()
- Initialisiert ein Array der Länge CONST_MAX_EXPECTED_RESULTS mit Nullen.
- Iteriert über *table (Range-based for).
- Ruft für jedes Element visit(&el) auf.
- Nur wenn visit(...) != 0, wird der Wert in das Array geschrieben (fortlaufend).
- Gibt den Pointer auf das Array zurück.
-
void IteratingTaskAgent::performTask()
- Ruft visitAll() auf. Die Ergebnisse für jeden Eintrag im Array müssen jeweils in einer separaten Zeile auf std::cout ausgegeben werden.
A2.3 ReducingTaskAgent: performTask() und reduceAll()
-
int ReducingTaskAgent::reduceAll()
- Legt eine Integer-Variable als Akkumulator an (Startwert 0).
- Iteriert über *table (Range-based for).
- Aktualisiert den Akkumulator mit acc = reduce(&el, acc).
- Gibt den finalen Akkumulator zurück.
-
void ReducingTaskAgent::performTask()
- Ruft reduceAll() auf und gibt das Ergebnis auf std::cout aus.
A2.4 Konkrete Tasks (A–E)
Es müssen folgende 5 Agents existieren (CLI-Auswahl über main.cpp):
Task A (a) - alle Einträge ausgeben
visit(...)gibtpointszurück
Task B (b) - alle Einträge, die < 10 Punkte haben, ausgeben
visit(...)gibtmat_nozurück oder 0, damit visitAll() ignorieren kann
Task C (c) – Anzahl der Elemente
- Ergebnis: Anzahl der Einträge in der Tabelle
Task D (d) – Maximum der Punkte
- Ergebnis: höchste Punktzahl in allen Einträgen
Task E (e) – Summe der Punkte in Series 3
- Ergebnis: Summe aller points in
series3
Abgabehinweise
- Bearbeiten Sie die mit
// TODOmarkierten Stellen im Code. - Die verkettete Liste mit dem Iterator-Interface soll selbst implementiert werden. Davon abgesehen darf die STL verwendet werden.
- Korrekte Speicherverwaltung (new/delete, new[]/delete[] oder ggf. Initialisierung im Stack) gehört zur Aufgabenstellung :)
- Die Tests sollen alle grün sein (
make tests), sind aber in erster Linie eine Hilfestellung, keine Garantie für volle Punktzahl - dafür gibt es die Testatgespräche.