Warum ist es wichtig, die Tastenkürzel zu beherrschen?
Um Zeit zu sparen, flüssiges arbeiten
Warum wird eine Deklaration einer Funktion benötigt, die im Quelltext unterhalb einer Aufrufstelle definiert ist?
Damit der Compiler weiß dass eine Funktion unter dem Aufruf steht. Die Deklaration kann auch als "Inhaltsverzeichnis" gesehen werden. Zur Übersichtlichkeit trägt es auch bei.
Schreiben Sie kurze Glossar-Einträge für alle an der Übersetzung/Erstellung eines Programms beteiligten Komponenten bzw. Phasen.
Präprozessor: Dieser arbeitet den Quellcode auf. Er entfernt Kommentare und trägt #define-Werte im Code ein. Er inkludiert auch die Dateien, die mit #include gekennzeichnet wurden. Kurz: Er bereitet den Quelltext für den Compiler vor.
Compiler: Er analysiert den Quelltext und übersetzt ihn in Maschinensprache. Wenn keine Fehler auftreten, erzeugt er eine Objektdatei.
Assembler: Übersetzt Assemblersprache, die wir lesen können, in die PC-lesbare Maschinensprache.
Linker: Er bindet mehrere Objektdateien zu einem Programm zusammen und löst externe Referenzen zwischen den Objektdateien auf.
Loader: Lädt Programme in den RAM-Speicher.
Ist es möglich, von einer Quelldatei aus eine Funktion aufzurufen, welche in einer anderen Quelldatei definiert ist? Begründung!
Ja, es ist möglich, da der Linker externe Referenzen zwischen Objektdateien auflöst. Durch Deklaration der Funktion in der aufrufenden Datei und Definition in einer anderen Datei kann der Linker die Referenzen korrekt auflösen.
Welche Art von Fehler von welchem Werkzeug ergibt sich, wenn #include "polynom1.h" in main.c vorhanden ist und int polynom1(int) in polynom1.h deklariert ist, aber polynom1.c keine Definition zu dieser Deklaration enthält?
Der Fehler würde vom Linker stammen und wäre ein "undefined reference" Fehler für die Funktion polynom1(int) beim Versuch, das Programm zu verlinken.
polynom1(int)
Welche Teile der Toolchain sind beteiligt bei clang -c main.c und welche Datei entsteht?
Präprozessor
Compiler
Assembler
Welche Vorteile hat es, eine Anweisungssequenz in einer Funktion zu bündeln?
Verbesserte Wiederverwendbarkeit und Modularität.
Einfachere Wartung und Fehlerbehebung.
Bessere Abstraktion und Kapselung.
Welche Vorteile hat es, eine Problemstellung rekursiv zu implementieren?
Eleganz und Klarheit der Lösung.
Natürliche Passung zu problematischen Strukturen wie Baumstrukturen.
Weniger iterative Logik, reduzierte Komplexität.
Welche Nachteile hat es, eine Problemstellung rekursiv zu implementieren?
Potenziell hoher Speicherverbrauch durch Stapelrahmen.
Schwierigeres Debuggen bei tiefen Rekursionen.
Nicht immer die effizienteste Lösung.
Was macht die Schwierigkeit bei der Programmierung des FizzBuzz-Spieles aus?
Korrekte Bedingungslogik für Teilbarkeitsprüfungen.
Effiziente und klare Schleifensteuerung.
Berücksichtigung von Randfällen wie der Zahl 0 oder negativen Zahlen.
Welche Ausgabe erzeugt dieser Code?
int k;
void foo() {
printf(k);
} int main() {
int k = 7;
foo();
return 0;
}
Der Code führt zu einem undefinierten Verhalten, da die Funktion printf einen Formatstring benötigt, aber k als Integer übergeben wird. Es kann zu einer Ausgabe von Mülldaten oder einem Absturz führen.
Welches i wird geändert?
void foo(int i)
{
i = i + 1;
int main() {
int i = 7;
foo(i);
Die Funktion foo(int i) ändert das lokale i, das in der main-Funktion deklariert wurde (also das i in main). Die Änderung ist jedoch nur innerhalb der Funktion foo sichtbar und betrifft nicht das i in main direkt.
Erläutern Sie auf welchen Arten bool-Werte entstehen können.
Direkte Zuweisung wie bool b = true; oder bool b = false;.
Rückgabewerte von Vergleichsoperationen wie a < b.
Verwendung von logischen Ausdrücken wie a && b oder a || b.
Implizite Konvertierung von Ganzzahlen wie bool b = 1; (true) oder bool b = 0; (false).
Was ist die genaue Ursache für Probleme mit dem Vergleich isalpha('a') == true?
Der direkte Vergleich isalpha('a') == true könnte fehlschlagen, da isalpha('a') nicht genau 1 (true) zurückgibt, sondern einen Wert, der als true interpretiert wird. Besser ist es, einfach isalpha('a') zu verwenden, ohne expliziten Vergleich mit true.
Vergleichen Sie die beiden Arten, Zeichenketten zu speichern, wie sie von Pascal und C verwendet werden. Welche Vor- und Nachteile existieren jeweils?
Pascal: Zeichenketten werden als nullterminierte Arrays von Zeichen gespeichert. Vorteil: Einfache Verwaltung durch festgelegte Länge. Nachteil: Mögliche Probleme mit Speicherallokation und Pufferüberläufen.
C: Zeichenketten werden ebenfalls als nullterminierte Arrays von Zeichen gespeichert. Vorteil: Flexibilität bei der Speicherung unterschiedlicher Längen. Nachteil: Erfordert sorgfältige Handhabung, um Pufferüberläufe zu vermeiden.
Welches Bitmuster (Zahlendarstellung im 2er-System) ergibt sich am Ende des folgenden Codes?
int controlRegister = 128; // Bitmuster: 0000 0000 1000 0000
controlRegister |= 64 + 32;
controlRegister ^= 16;
controlRegister &= 128 + 64;
controlRegister <<= 1;
Das Bitmuster ist: 1100 0000 (in binär).
Welchen Typ haben die unten angegebenen Ausdrücke?
1
1.0
"1.0"
1 + 1.0
'1'
1: Ganzzahl (int).
1.0: Gleitkommazahl (double).
"1.0": Zeichenkette (char array).
1 + 1.0: Gleitkommazahl (double) aufgrund der impliziten Typumwandlung.
'1': Zeichen (char).
Wie unterscheiden sich die Werte "1234" und 1234 hinsichtlich der Darstellung im Speicher?
"1234": Eine Zeichenkette, die als nullterminiertes Array von Zeichen im Speicher gespeichert wird.
1234: Eine Ganzzahl, die in binärer Form im Speicher gespeichert wird, üblicherweise als 2-Byte (bei int) oder 4-Byte (bei long int) Wert, je nach Plattform und Datentyp.
Welchen Zweck haben benutzerdefinierte Datentypen? Beziehungsweise:
warum begnügt man sich bei der Implementierung von Programmierproblem nicht mit den in C++ eingebauten Datentypen?
Spezialisierung für spezifische Anforderungen.
Abstraktion und Kapselung von Daten und Verhalten.
Erleichterung der Wartbarkeit und Erweiterbarkeit von Code.
Bereitstellung semantischer Bedeutung für bestimmte Datentypen, die über eingebaute Typen hinausgeht.
Welche Aussagen können Sie bezüglich des Ausdrucks a = b + c machen?
b + c führt eine Addition der Werte von b und c durch.
Das Ergebnis wird dann der Variablen a zugewiesen.
Die genaue Semantik hängt von den Datentypen und möglichen Überladungen der Operatoren + und = ab.
Welchen Nutzen hat typedef?
Ermöglicht das Definieren von Aliasnamen für bestehende Datentypen.
Verbessert die Lesbarkeit und Verständlichkeit des Codes.
Vereinfacht komplexe Typdeklarationen.
Unterstützt die Portabilität und Wartung von Code, indem es die Typen an einer zentralen Stelle definiert.
Warum sollten Konstruktoren, die genau einen Parameter erwarten, mit explicit markiert werden?
Verhindert ungewollte implizite Konvertierungen
Welchen Vorteil hat die Verwendung der Member Initializer List bei der Konstruktion von Werten?
Effizientere Initialisierung, besondrs für konstante oder Referenzmitglieder
Analysieren Sie die nachfolgenden Zeilen. Was macht der Compiler und was passiert zur Laufzeit? Nehmen Sie an, dass der Quelltext Fehlerfrei compiliert.
RgbColor c1;
RgbColor c2(2);
RgbColorc1= Standardkonstruktor wird aufgerufen
RgbColorc2(c2)= Konstuktor mit int-Parameter wird aufgerufen
RgbColor c1; // siehe oben
RgbColor c2(2); // siehe oben
RgbColor c3 = 3;
c3 = 4;
RgbColor c5 = c3;
RgbColor carr[7];
carr[0] = c5;
FancyColor f; // derived from RgbColor
RgbColor c6 = f;
RgbColor c3 = 3;: Konstruktor mit int-Parameter wird für c3 aufgerufen.
c3 = 4;: Zuweisungsoperator wird aufgerufen.
RgbColor c5 = c3;: Kopierkonstruktor wird aufgerufen.
RgbColor carr[7];: Standardkonstruktor wird für jedes Arrayelement aufgerufen.
carr[0] = c5;: Zuweisungsoperator wird aufgerufen.
FancyColor f;: Standardkonstruktor von FancyColor wird aufgerufen.
RgbColor c6 = f;: Konvertierungs- oder Kopierkonstruktor von RgbColor wird aufgerufen für c6.
Zu welchem Zeitpunkt wird entschieden, welche Methodenimplementierung aufgerufen werden soll, bei a) virtual-Methoden und b) nicht-virtual- Methoden.
Virtual-Methoden: Zur Laufzeit, Nicht-virtual-Methoiden: Zur Kompilerzeit
Was passiert beim Aufruf der Funktion void foo(Base*) mit einem Zeiger auf ein Objekt der Klasse Derived? (Klasse Derived ist abgeleitet von Base)
Die Funktion wird aufgerufen, als ob der Zeiger auf eine Base-Objekt zeigt
Was passiert beim Aufruf der Funktion void foo(Derived*) mit einem Zeiger auf ein Objekt der Klasse Base? (Klasse Derived ist abgeleitet von Base)
Compilerfehler, da eine Base-Zeiger nicht implizit in einem Derived-Zeiger konvertiert werden kann
Welche Aufgaben hat ein Konstruktor?
Initialisieren der Objekte, ressource allokieren, Datenmitglieder initialisieren
Welche Vorteile hat es, Code gegen eine Basisklasse (z.B. Shape) zu schreiben, statt gegen konkrete Klassen (z.B. Rectangle, Circle)?
Erhöht die Flexibilität, einfacheres erweitern des codes, unterstützung von polymorphismus
In welcher Reihenfolge werden die Konstruktoren entlang einer Vererbungslinie ausgeführt?
Basisklasse vor abgeleiteter Klasse.
In welcher Reihenfolge werden die Destruktoren entlang einer Vererbungslinie ausgeführt?
Abgeleitete Klasse vor Basisklasse.
Welchen Zweck hat die member initializer list?
Initialisiert Datenmitglieder vor dem Konstruktor
Welchen Zweck hat die base initializer list?
Initialisiert Basisklassen und Mitgliedsobjekte
Sollte der Destruktor eines Objekttypen virtual deklariert werden? Warum Ja/Nein?
Ja, bei polymorphen Klassen, um den korrekten Destruktor der abgeleiteten Klasse aufzurufen.
Werden die Konstruktoren von Felder einer Klasse X vor X::X() aufgerufen? Warum Ja/Nein?
Ja, weil Felder vor dem Ausführungskörper des Konstruktors initialisiert werden.
Wozu wird das statische Binden des Aufrufs einer virtuellen Methode zwingend benötigt?
Statisches Binden wird nicht für virtuelle Methoden benötigt, da diese dynamisches Binden zur Laufzeit verwenden.
Zu welchem Zeitpunkt wird festgelegt, aus welcher Klasse die Implementierung einer virtuellen Methode stammt, die aufgerufen wird?
Zur Laufzeit.
Zu welchem Zeitpunkt wird festgelegt, welche Methodensignatur verwendet wird, um einen Aufruf einer überladenen Methode zu generieren?
Zur Kompilierzeit
Muss für einen upcast static_cast oder dynamic_cast verwendet werden? Warum ja/nein?
Nein, Upcast erfolgt implizit
Muss für einen downcast static_cast oder dynamic_cast verwendet werden? Warum ja/nein?
"dynamic_cast" sollte verwendet werden für Sicherheit;" static_cast" ist riskant ohne Typüberprüfung.
Kann der Compiler einen downcast implizit vornehmen? Begründung angeben.
Nein, Downcast erfordert explizite Typkonvertierung.
Kann über den Zeiger auf ein Objekt einer abgeleiteten Klasse die Basisklassenimplementierung einer virtuellen Methode aufgerufen werden (z.B. this in einer überschriebenen Methode)? Wenn ja: wie?
Ja, duch expliziten Aufruf: "Base:Methode()"
Zuletzt geändertvor 6 Monaten