20 Questions: Inf-Einf-B-Edition (überarbeitet)

Bearbeiten Sie die folgenden 20 Aufgaben alleine oder im Team (30–120 Sekunden pro Aufgabe) auf Ihrem Zettel. Geben Sie ein Signal, wenn Sie glauben, eine Lösung zu haben. Notieren Sie sich nach der Auflösung, ob Sie richtig lagen. Machen Sie dann ein Kreuz (☑︎). die Zettel sammeln wir am Ende anonym ein.

Lösen Sie zusätzlich die Bonus-Fragen, falls Sie Zeit übrig haben (irrelevant für das Korrekt-Kreuz).

Ziel: Individuelles Feedback zu eigenen Fähigkeiten: "was weiß ich, was muss ich mir noch einmal ansehen?" Zusätzlich: Rückmeldung für uns ("Was wissen sie?")

Navigation mit Pfeiltasten (links/rechts, zur Lösung: nach unten, Esc für Übersicht).

Compiler

Ergänzen Sie:

Ein Compiler wandelt in mehreren Schritten Code um. Im ersten Schritt, dem _______, werden Header-Dateien in das Programm eingefügt. Im zweiten Schritt wird der Code in _______ umgewandelt.

Bonus: Was passiert im letzten Schritt (Linking) genau?

Fertig? Bitte 3x auf den Tisch klopfen.

Erste Lücke: Preprocessing

Zweite Lücke: Assemblercode

Bonus: Beim Linking wird der Maschinencode aus den eingebundenen Bibliotheken mit dem eigenen Code kombiniert.

Hi

Wie oft wird "Hi" ausgegeben?

int i = 0;
do {
    printf("Hi\n");
    i++;
} while (i < 0);

Bonus: Was würde sich ändern, wenn man statt do-while eine while-Schleife verwendet?

Fertig? Bitte 3x auf den Tisch klopfen.

Lösung

"Hi" wird einmal ausgegeben, da do-while immer mindestens einmal ausführt.

Bonus: Bei einer while-Schleife würde nichts ausgegeben, da die Bedingung von Anfang an false ist.

1 bis 10

Schreiben Sie im Kopf den Code, der prüft, ob eine Zahl zwischen 1 und 10 (inklusive) liegt.

Fertig? Bitte 3x auf den Tisch klopfen.

Lösung

if (x >= 1 && x <= 10)
{
    printf("Gültig\n");
}

Syntaxfehler

Wie viele Syntaxfehler enthält dieser Code?

// benötigte #includes

int main(void)
{
    int x = get_int("x: ")
    if (x = 5);
    {
        printf("x ist fünf");
    }
    return 0
}

Bonus: Welcher dieser Fehler ist besonders tückisch?

Fertig? Bitte kurz aufstehen und wieder hinsetzen.

Lösung

Der Code enthält 4 Syntaxfehler:

  • Fehlendes Semikolon nach get_int("x: ")
  • = statt == im if-Statement
  • Semikolon nach if (x == 5); beendet die Bedingung frühzeitig
  • Fehlendes Semikolon nach return 0

Bonus: Das Semikolon nach dem if ist besonders tückisch, da es syntaktisch korrekt ist, aber den nachfolgenden Block immer ausführt.

Datentypen

Ein char benötigt ___ Byte Speicher und kann Werte von ___ bis ___ speichern, ein int belegt hingegen üblicherweise ___ Byte.

Fertig? Bitte kurz aufstehen und wieder hinsetzen.

Lösung

Ein char benötigt [ 1 ] Byte Speicher und kann Werte von [ -128 ] bis [ 127 ] speichern, ein int belegt hingegen üblicherweise [ 4 ] Byte.

Markieren Sie die Aufgabe nur dann als richtig, wenn Sie alle Felder richtig hatten.

Schleife

Schreiben Sie (wirklich: schreiben!) eine Schleife, die die ersten drei geraden Zahlen ausgibt, also 2, 4 und 6).

Bonus: Schreiben Sie eine Schleife, die nur die geraden Zahlen aus dem Array arr (Länge 5) ausgibt.

Fertig? Bitte kurz aufstehen und wieder hinsetzen.

Lösung

for (int i = 1; i <= 3; i++)
{
    printf("%i\n", i * 2);
}
Bonus:
for (int i = 0; i < 5; i++)
{
    if (arr[i] % 2 == 0)
    {
        printf("%i\n", arr[i]);
    }
}

Strings

Vervollständigen Sie:

Ein String "Hi!" belegt im Speicher ____ Bytes, weil _______.

Bonus: Was würde printf("%i", strlen("Hi!")); ausgeben und warum?

Fertig? Bitte 3x auf den Boden stampfen.

Lösung

Der String belegt 4 Bytes, weil jedes Zeichen 1 Byte benötigt und ein zusätzliches Byte für den '\0'-Terminator verwendet wird.

Bonus: Die Ausgabe wäre 3, da strlen den Terminator nicht mitzählt.

Game Over

Was gibt dieser Code aus?

int score = 0;
if (score == 0);
{
    printf("Game Over\n");
}
else
{
    printf("Next Level\n");
}

Fertig? Bitte 3x auf den Boden stampfen..

Lösung

(Lösung wurde nachträglich korrigiert und erweitert.)

Der Code kann nicht kompiliert werden. Das Hauptproblem ist, dass direkt hinter der if-Bedingung ein Strichpunkt steht. Dies führt bei der von uns verwendeten, sehr konservativen Konfiguration von clang (siehe Umgebungsvariable CFLAGS) zu einem Fehler während des Kompilierens.

if-Anweisungen ohne geschweifte Klammern beziehen sich immer auf die erste Anweisung, die direkt darauffolgt, in diesem Fall also die leere Anweisung.

Details folgen weiter unten.

Details: Leere if-Anweisung

Wäre der Compiler weniger streng konfiguriert, würde er das leere Statement nach der if-Anweisung zwar akzeptieren; es käme aber immer noch zu einem Compile-Fehler, da dann ein anderer Syntaxfehler vorliegt: Der else-Block kann nicht ohne if-Block existieren.

Der if-Block ist durch die leere Anweisung (der Strichpunkt direkt nach if) bereits zu Ende.

Der Block, in dem printf "Game Over" ausgibt, ist dann ein weiterer, unabhängiger Codeblock, der nichts mit der if-Anweisung zu tun hat, also unabhängig vom booleschen Ausdruck immer ausgeführt wird.

Weiter!

Was gibt folgender Code aus?

const int N = 6;
for (int i = 0; i < N; i++) {
    for (int j = 0; j < N; j++) {
        if (i == j) {
            printf("  ");
            continue;
        }
        printf("# ");
    }
    printf("\n");
}

Bonus: Was wäre bei break statt continue?

Fertig? Bitte 3x auf den Tisch klopfen.

Lösung

continue bricht Durchlauf ab, setzt beim nächsten fort:

  # # # # # 
#   # # # # 
# #   # # # 
# # #   # # 
# # # #   # 
# # # # #   

Bonus: Nur das untere Dreieck wird ausgegeben:

  
#   
# #   
# # #   
# # # #   
# # # # #   

Details: s. Short zu Schleifen

Odd Exit

Wie viele Syntaxfehler enthält dieser Code und welchen Exit-Code würde er bei korrekter Syntax liefern, wenn die Zahl 10 eingegeben wird? (nachträglich korrigiert)

// benötigte #includes

int main(void)
{
    int num = get_num("Number: ")
    if (num % 2 == 0)
        return 1
    printf("You entered %i\n", num)
    return 0
}

Bonus: Wie wirken sich Syntaxfehler aus, wie logische Fehler?

Fertig? Bitte 3x auf den Tisch klopfen.

Lösung

Der Code enthält 5 Syntaxfehler:

  • Fehlendes Semikolon nach get_int("Number: ")
  • Falscher Funktionsname get_num statt get_int
  • Fehlendes Semikolon nach return 1
  • Fehlendes Semikolon nach printf("You entered %i\n", num
  • Fehlendes Semikolon nach return 0

Bei Eingabe von 10 würde der Exit-Code 1 sein.

Bonus: Syntaxfehler verhindern das Kompilieren, während logische Fehler zu unerwartetem Verhalten zur Laufzeit führen.

Nimm Zwei!

Schreiben Sie eine for-Schleife, die jede zweite Zahl eines Arrays ausgibt (also 4, 7, 3).

Array: int zahlen[] = {4, 2, 7, 1, 3};

Bonus: Wie würden Sie die Zahlen in umgekehrter Reihenfolge ausgeben?

Signalisiert, wenn ihr bereit seid, indem ihr 1x kurz aufsteht.

Lösung

Code:
for (int i = 0; i < 5; i += 2) {
    printf("%i ", zahlen[i]);
}

Ausgabe: 4 7 3

Bonus: Um die Zahlen in umgekehrter Reihenfolge auszugeben:

for (int i = 4; i >= 0; i--) {
    printf("%i ", zahlen[i]);
}

Vertippt

Sie haben versehentlich eine Datei namens "Hello.c" (mit großem H) erstellt. Welche Befehle führen Sie nacheinander aus um:

  • zu überprüfen ob die Datei existiert
  • sie in "hello.c" umzubenennen
  • zu prüfen ob es geklappt hat

Bonus: Wie können Sie sich den Inhalt der Datei anzeigen lassen?

Signalisiert, wenn ihr bereit seid, indem ihr 1x kurz aufsteht.

Lösung

Konsole:
$ ls
$ mv Hello.c hello.c
$ ls

Bonus: cat hello.c

The Smiths

In der Datei names.txt steht:

1: Alice Smith 
2: Bob Smith
3: Alice Brown

Welche Variante ermittelt, welcher Nachname am häufigsten vorkommt?

Variante A:
cat names.txt | cut -d' ' -f3 | sort | uniq -c | sort -n
Variante B:
cat names.txt | cut -d':' -f2 | cut -d' ' -f3 | sort | uniq -c

Signalisiert, wenn ihr bereit seid, indem ihr 1x kurz aufsteht.

Lösung

Richtig ist:
cat names.txt | cut -d' ' -f3 | sort | uniq -c | sort -n

Details: siehe Short zu Kommandozeile.

Probleme

Finden Sie ALLE Probleme in diesem Code:

// benötigte #includes

int main(void)
{
    float score = get_int("Score: ");
    printf("Percent: %i\n", score);
    if (score == 100.0)
        printf("Perfect!\n");
    return score;
}

Signalisiert, wenn ihr bereit seid, indem ihr 1x kurz aufsteht.

Lösung (korrigiert)

Probleme im Code:

  • Typkonflikt: get_int gibt einen int zurück, aber wird in eine float-Variable gespeichert.
  • Falscher Format-String: printf("Percent: %i\n", score); sollte %f verwenden für float.
  • Vergleich von float mit exaktem Wert: if (score == 100.0) kann zu Problemen führen (Details folgen weiter unten)
  • Rückgabewert: return score; sollte einen int zurückgeben, nicht einen float.

Details: Rundungsfehler bei Floats

(Diese Details sind nicht relevant für Inf-Einf-B.)

// benötigte #includes

      int main() {
          float x = 16777216.0; // = 2^24
          float y = 16777217.0; // = 2^24 + 1
          if (x == y) {
              printf("x and y are considered equal (32-bit floats).\n");
          }
      }

Schrittweise

Ordnen Sie die Compiler-Schritte in die richtige Reihenfolge:

  • Assembling
  • Preprocessing
  • Linking
  • Compiling

Bonus: Welche dieser Schritte werden von clang durchgeführt?

Fertig? Bitte 3x auf den Tisch klopfen.

Lösung

Die richtige Reihenfolge ist:

  1. Preprocessing
  2. Compiling
  3. Assembling
  4. Linking

Bonus: Alle Schritte.

I'll be back!

Was bedeutet das '\0' am Ende eines Strings und welche Aussage ist FALSCH?

  • A) Es markiert das String-Ende
  • B) Es belegt 1 Byte
  • C) Es wird bei strlen mitgezählt
  • D) Es wird automatisch vom Compiler eingefügt, wenn man einen String initialisiert

Bonus: Wie viele Bytes belegt "Hello"?

Fertig? Bitte 3x auf den Tisch klopfen.

Lösung

Die falsche Aussage ist C) Es wird bei strlen mitgezählt.

Bonus: "Hello" belegt 6 Bytes (5 Buchstaben + 1 für '\0').

Rekursion

Welchen Exit-Code gibt dieser Code zurück?

int mystery(int x)
{
    if (x <= 0)
        return 0;
    return x + mystery(x - 1);
}

int main(void)
{
    return mystery(3);
}

Bonus: Wie kann man das gleiche Ergebnis deutlich effizienter berechnen?

Signalisiert, wenn ihr bereit seid, indem ihr 4x auf den Boden stampft.

Lösung

Der Code gibt den Wert 6 zurück.

Bonus: int sum = x * (x+1) / 2 .

ASCII

Was macht dieser Code?

char c = 'a';
while (c <= 'z') {
    printf("%c: %i\n", c, c);
    c++;
}

Signalisiert, wenn ihr bereit seid, indem ihr 1x kurz aufsteht.

Lösung

Der Code gibt alle Kleinbuchstaben von 'a' bis 'z' zusammen mit ihren ASCII-Werten aus.

Beispielausgabe:

a: 97
b: 98
...
z: 122

Dreiertausch

Schreiben Sie Code, der die ersten beiden Zeichen eines Strings s (Länge: 10) vertauscht.

Beispiel: Aus "CS" wird "SC".

Fertig? Bitte 3x auf den Tisch klopfen.

Lösung

Code:
char temp = s[0];
    s[0] = s[1];
    s[1] = temp;

Dieser Code tauscht die ersten beiden Zeichen des Strings s.

arg-was?

Was ist der Wert von argc in diesem Fall?

./programm hello

Bonus: Was enthält argv[2] beim Aufruf von ./programm hello "hello world" hi?

Fertig? Bitte 3x auf den Tisch klopfen.

Lösung

Der Wert von argc ist 2.

Bonus: argv[2] enthält den String "hello world"

Die Argumente sind:

  • argv[0]: "./programm"
  • argv[1]: "hello"
  • argv[2]: "hello world"
  • argv[3]: "hi"

Vielen Dank fürs Mitmachen!

Bitte zählen Sie nun, wie viele Aufgaben Sie korrekt gelöst haben.

Geben Sie dann die Zettel nach außen; wir möchten die Zettel gerne anonym statistisch auswerten.