Rade Kutil
Lehrveranstaltungen
UV Programmiersprachen: C/C++ (WS21)

Inhalt

Einführung in C/C++ unter Voraussetzung von Programmierkenntnissen in Java.

Abhaltung

Im Hörsaal bzw. per WebEx findet der Vorlesungsteil statt, der noch im Dezember zu Ende sein wird. Achtung: Wer physisch im Höraal anwesend sein möchte, muss sich hier mit seiner vorname.nachname@stud.sbg.ac.at-Email anmelden. Der Übungsteil besteht aus den abzugebenden Programmen (siehe unten).

Skriptum

Hier gibt es das Skriptum zum herunterladen: PDF. Außerdem noch die Beispiel-Programme aus dem Skriptum.

Programmieraufgaben

Jedes bekommt eine individuelle Programmieraufgabe, die für C und C++ gilt, in einer Datei aufgabe.txt in seinem Subversion-Verzeichnis. Die erste Zeile dieser Datei ist programm article.dat citation.dat author.dat [weitere parameter]. Das heißt: Du sollst ein Programm namens programm erzeugen, das als erstes Kommando­zeilen­argument einen Dateinamen akzeptiert und als zweiten und dritten auch. Dahinter kommen möglicherweise noch weitere Parameter, wenn es die Aufgabe verlangt. Der Name des Programms ist ganz wichtig (also programm), sonst muss ich bei 60 Leuten rätseln, was für ein Programm ich nun aufrufen soll. Und bitte keines der Datei-Argumente weglassen, auch wenn die Datei nicht gebraucht wird.

Bis zum Do 9. Dez. soll das C-Programm programmiert werden. Das Programm wird von mir mit evtl. Verbesserungsvorschlägen kommentiert. Bis Ende Dez. kann das Programm dann noch verbessert werden. Alle C-Files und Header-Files sollen in einem Unterverzeichnis c/ sein. Bis zum Do 13. Jan. soll das C++-Programm programmiert werden, und zwar im Unterverzeichnis cpp/. Bis Ende Jan. kann dann noch verbessert werden. Erstelle in diesen Unterverzeichnissen auch ein Makefile. Mittels make ohne Argumente muss das Programm programm erzeugt werden. Adde nur .c-Files, .h-Files und das Makefile (und natürlich die Verzeichnisse c/ und cpp/) ins Git-Repository. Ich übersetze das Programm selbst.

Die zu erstellenden Programme sollen auf die Dateien article.dat, citation.dat und author.dat zugreifen. Der exakte Filename wird allerdings auf der Kommandozeile übergeben. Die Dateien zum Testen bitte hier herunterladen (und nicht ins Git einchecken). Die erste Datei article.dat enthält Artikel aus verschiedenen wissenschaftlichen Journals mit folgenden Angaben:

aritkelId titel journalName ausgabe jahr vonSeite bisSeite

Die Einträge sind durch ein Leerzeichen getrennt. Ein Artikel ist eindeutig durch artikelId (natürliche Zahl) identifiziert. Die zweite Datei citation.dat enthält Zitationen, d.h. die Information, welcher Artikel welchen Artikel zitiert. Eine Zeile enthält:

zitierenderArtikelId zitierterArtikelId

Die Ids beziehen sich auf die artikelId aus article.dat. Die dritte Datei author.dat gibt die Autoren der Artikel an. Eine Zeile enthält:

artikelId autorNr autorName

Beachte: Die Einträge in den Dateien sind in zufälliger Reihenfolge. Ein zitierter Artikel kann z.B. vor oder nach einem zitierenden kommen.

Benotungskriterien

Grundsätzlich muss das Programm funktionieren, damit es eine positive Note gibt. Das heißt, es muss compilierbar sein und das gewünschte Ergebnis liefern. Davon abgesehen, sollten folgende Kriterien beachtet werden:

  1. Nicht alles in ein .c-File geben, das Hauptprogramm programm.c soll nur die Funktion main enthalten, in C++ am besten für jede Klasse ein Header-File und (falls notwendig) ein .cc-File. Die Aufteilung der Code-Files sollte nach Problem-orientierten Kriterien organisiert sein (z.B. article.c, author.c), nicht Implementierungs-orientiert (z.B. io.c, algo.c, ...).

  2. Bitte keinen monolithischen Code, und schon gar nicht in main(). Funktionen, die sehr lang sind, können immer sinnvoll aufgeteilt werden, das Programm wird dadurch lesbarer und wartbarer.

  3. Zusammengehörige Daten als Typ oder Klasse kapseln. Insbesondere beim Einlesen der Dateien am besten für jede Zeile ein struct-Objekt bzw. in C++ ein Klassenobjekt erzeugen.

  4. Bufferüberläufe verhindern. Wenn in C ein Array mit fixer Größe angelegt wird, dann muss bei jedem Einfügen überprüft werden, ob die Größe überschritten wird. Besser noch verwendet man dynamisch wachsende Arrays (siehe Beispielprogramme) bzw. STL-Container. Das trifft auch auf Strings zu: beim Einlesen in C immer %100s o.ä. verwenden statt nur %s. Bufferüberläufe können entdeckt werden, indem man das Compiler-Flag -fsanitize=address verwendet.

  5. Keine globalen Variablen verwenden. Das ist schlechte Programmier­praxis, erweiterungsfeindlich und auch nicht thread-safe.

  6. In C liegt das Augenmerk noch nicht auf Performance, Suchen und Sortieren in Arrays kann durch lineares Iterieren und Bubble-Sort o.ä. implementiert werden, es ist allerdings geschickt, die Id-Referenzen nach dem Einlesen in Pointer umzuwandeln, um ständiges Suchen zu vermeiden. In C++ müssen aber passende STL-Container oder Algorithmen verwendet werden, die logarithmische Komplexität für das Suchen haben.

  7. Allozierten Speicher wieder freigeben. Wer malloc oder new verwendet, muss die Daten immer mit free oder delete wieder freigeben. In C/C++ gibt es keine Garbage-Collection. Auch solche Memory-Leaks können entdeckt werden, indem man das Compiler-Flag -fsanitize=address verwendet.

  8. In C++ Member-Variablen private machen. Zugriff nur über get- und set-Methoden, oder noch besser größere Zugriffsmuster in Methoden auslagern.

  9. Das Makefile muss so aufgebaut sein, dass bei Veränderung eines .c-Files nicht das gesamte Projekt übersetzt wird sondern nur das eine .c-File, die Objektfiles werden dann zusammengelinkt. In C müssen dazu die Abhängigkeiten von den .o-Files richtig angegeben werden. In C++ müssen auch die Abhängigkeiten von den .h-Files angegeben sein (am besten mit der cc -MMD-Methode).

  10. Aussagekräftige Variablen- und Typnamen. Z.B. articleList statt myData.

  11. Das Kopieren ganzer Arrays und Container ist zu vermeiden. Man beachte, dass eine Funktion vector<Article> removeArticle (vector<Article> articles, int articleId) sowohl beim Übergeben der Argumente als auch beim zurückgeben des Ergebnisses das ganze Array kopiert. Und ein Aufruf wie articles = removeArticle (articles, 123) produziert dann vollkommen unnötigen Rechenaufwand. Sowas ist dann besser mit Pointern oder References zu lösen, etwa so: void removeArticle (vector<Article> &articles, int articleId).

Anmeldung per Git

Zur Programmabgabe und Anmeldung wird Git verwendet. Die persönliche Repository-URL kommt noch per Email. Die URL stellt eine Art Passwort für das Repository dar, diese also besser nicht an andere weitergeben. Zur Anmeldung bis spätestens 14.10. mit dieser URL git clone machen und dann eine Datei anmeldung.txt mit dem Namen (Vor- und Nachnamen) erstellen, adden und pushen. Z.B. so:

git clone <URL> ccpp
cd ccpp
echo Blasius Sacklmeier >anmeldung.txt
git add anmeldung.txt
git commit -m "Anmeldung"
git push

2021-12-08 22:09