Einführung in C/C++ unter Voraussetzung von Programmierkenntnissen in Java.
Hier gibt es das Skriptum zum herunterladen: PDF, 536KiB. Außerdem noch die Beispiel-Programme aus dem Skriptum.
Jeder 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 stadt.dat gebiet.dat strasse.dat [weitere parameter]
.
Das heißt: Du sollst ein Programm namens programm
erzeugen, das als erstes Kommandozeilenargument 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 50 Leuten rätseln, was für ein Programm ich nun aufrufen soll.
Und bitte keines der Datei-Argumente weglassen, auch wenn du die Datei nicht brauchst.
Bis zum Di 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 Di 14. Jan. soll das C++-Programm programmiert werden, und zwar im Unterverzeichnis cpp/
.
Bis zum Di 28. 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 Subversion-Repository.
Ich übersetze das Programm selbst.
Die zu erstellenden Programme sollen auf die Dateien stadt.dat
, gebiet.dat
und strasse.dat
zugreifen.
Der exakte Filename wird allerdings auf der Kommandozeile übergeben.
Die Dateien zum Testen bitte hier herunterladen (und nicht ins Subversion einchecken).
Die erste Datei stadt.dat
enthält Städte mit folgenden
Angaben:
stadtId name einwohner gebietId meereshöhe
Die Einträge sind durch ein Leerzeichen getrennt.
Eine Stadt ist eindeutig durch stadtId (natürliche Zahl) identifiziert.
Die zweite Datei gebiet.dat
enthält Regionen (R), Länder (L) und Kontinente (K), in denen die Städte angesiedelt sind.
Eine Zeile enthält:
gebietId name obergebietId typ
gebietId ist eine eindeutige Id (natürliche Zahl), die in stadt.dat
referenziert wird.
name
ist der Name des Gebiets.
obergebiet
ist z.B. die Id eines Landes von dem das Gebiet Teil ist.
Der typ
kann R
, L
oder K
sein (siehe oben).
R kann Obergebiet L oder R haben, L kann Obergebiet K haben.
Die dritte Datei strasse.dat
definiert Straßen zwischen den Städten.
Eine Zeile enthält:
vonStadtId nachStadtId entfernung
Straßen sind natürlich in beide Richtungen benutzbar, jedoch nur in einer Richtung (von vonStadt
nach nachStadt
) eingetragen.
entfernung
gibt die Länge der Straße in km an.
Beachte: Die Einträge in den Dateien sind in zufälliger Reihenfolge. Ein Obergebiet kann z.B. vor oder nach einem Untergebiet kommen.
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:
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. stadt.c, strasse.c), nicht Implementierungs-orientiert (z.B. io.c, algo.c, ...).
Bitte keinen Spaghetticode, und schon gar nicht in main()
.
Funktionen, die sehr lang sind, können immer sinnvoll aufgeteilt werden, das Programm wird dadurch lesbarer und wartbarer.
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.
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
.
Keine globalen Variablen verwenden. Das ist schlechte Programmierpraxis, erweiterungsfeindlich und auch nicht thread-safe.
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.
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.
In C++ Member-Variablen private machen. Zugriff nur über get- und set-Methoden, oder noch besser größere Zugriffsmuster in Methoden auslagern.
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 -MM
-Methode).
Aussagekräftige Variablen- und Typnamen.
Z.B. stadtListe
statt myData
.
Das Kopieren ganzer Arrays und Container ist zu vermeiden.
Man beachte, dass eine Funktion vector<Stadt> removeStadt (vector<Stadt> staedte, int stadtId)
sowohl beim Übergeben der Argumente als auch beim zurückgeben des Ergebnisses das ganze Array kopiert.
Und ein Aufruf wie stadte = removeStadt (staedte, 123)
produziert dann vollkommen unnötigen Rechenaufwand.
Sowas ist dann besser mit Pointern oder References zu lösen, etwa so: void removeStadt (vector<Stadt> &staedte, int stadtId)
.
Zur Programmabgabe und daher zur effektiven Anmeldung wird Subversion verwendet. Anmelden bis spätestens 14.10.. Folgende Schritte sind zu tun:
Ein Verzeichnis mit dem Usernamen im Repository anlegen:
svn mkdir https://svn.cosy.sbg.ac.at/lv/ccpp/abcdefg -m Anmeldung
Das Verzeichnis auschecken:
svn checkout https://svn.cosy.sbg.ac.at/lv/ccpp/abcdefg
Anmeldungsdaten (Nachname, Vorname) in die Datei
anmeldung.txt
im Verzeichnis abcdefg
eintragen:
Bcdefg
Arnold
Anmeldungsdaten commiten:
svn add anmeldung.txt
svn commit -m Anmeldung
Statt abcdefg
natürlich den eigenen Usernamen verwenden.