Weihnachtsvorlesung

Peter Ulbrich

🚀 by Decker

Testfrage

GlĂŒhwein mit oder ohne Alkohol?

  • Mit
  • Ohne

Quiz 1

Zum AufwĂ€rmen: Ist eine Variable vom Typ int immer 4 Byte (32 Bits) groß?

  • Ja
  • Nein

ErlÀuterung

Die genaue GrĂ¶ĂŸe eines Integers hĂ€ngt von der Wortbreite der Prozessorarchitektur ab.

Quiz 2

Zum AufwĂ€rmen: Welches sind gĂŒltige Bezeichner fĂŒr Variablen?

  • geht_so!
  • cr7
  • Tach
  • double

ErlÀuterung

B und C

Siehe Kapitel 2, Folien zum Thema Bezeichner.

Erlaubte Zeichen: a-z, A-Z, 0-9 und _

Quiz 3

Frage: Welches ist kein SchlĂŒsselwort in C?

  • char
  • bool
  • if
  • ifdef

ErlÀuterung

bool ist mittlerweile Teil des C-Standards. In Àlteren Versionen muss aber noch stdbool.h inkludiert werden.

ifdef ist nicht Teil der C-Sprache an sich, sondern gehört zum PrÀprozessor

Quiz 4

Frage: Was ist der Wert der Variable i?

int i = 4712 % 1200;
}
  • 1112

Quiz 5

Frage: Und wie ist das Ergebnis von -4712 % 1200?

  • -1112
  • 1112
  • 88
  • -88

ErlÀuterung

  • Im mathematischen Sinne ist die Modulo-Operation die Euklidsche Teilung:
    • \(-4712 \mod 1200 = -4712 + 4 \cdot 1200 = 88\)
    • Teilweise wird dies genau so in anderen Programmiersprachen (z.B. Python) umgesetzt!
  • In C wird hingegen der Rest (Remainder) genommen
    • \(-4712 \quad\%\quad 1200 = 3 \cdot (-1200) - 1112 \Rightarrow\) Rest ist \((-1112)\)

Quiz 6

Welchen Wert hat die Variable b?

uint32_t a = 4294967296; // 2^32
uint32_t b = a + 3;
  • 3

 

ErlÀuterung

  • Variable a ist bereits grĂ¶ĂŸer als der maximale Wert eines vorzeichenlosen Integers
    • Überlauf wird erzeugt, und der Ausdruck a + 3 entspricht 0 + 3
  • Jeder weitere Addition um 1 fĂŒhrt zu weiterem Überlauf in der BinĂ€rdarstellung

Quiz 7

Welchen Wert hat die Variable b?

int a = 2147483648; // 2^31
int b = a + 1;
  • -2147483647
  • 2147483649
  • CompilerabhĂ€ngig
  • Undefiniertes Verhalten

Quiz 7 – ErlĂ€uterung

ErlÀuterung

  • Variable a ist bereits grĂ¶ĂŸer als der maximale Wert eines vorzeichenbehafteten Integers
  • Jeder weitere Addition um 1 fĂŒhrt zu weiterem Überlauf in der BinĂ€rdarstellung
  • Overflow ist nur fĂŒr vorzeichenlose Integers definiert
  • GCC geht hier den Weg des geringsten Widerstands (Wrap-Around zu -INT_MAX)
    • 2147483648D = 10000000 00000000 00000000 00000000B
    • Interpretierung als Zweierkomplement → -2147483648
    • Abschließend 1 addieren
  • Das Verhalten ist aber abhĂ€ngig von der Compiler-Implementation!

Quiz 8

Frage: Ist dies standardkonformer C-Code?

void test(int n) {
    int arr[n];
    /* ... */
}
  • Ja
  • Nein

ErlÀuterung

  • Ja, aber nur in C ab C99. Variable Length Arrays sind in C++ (aus gutem Grund) nicht mehr erlaubt

Quiz 9

Frage: Welcher Wert wird ausgegeben?

#include <stdio.h>

int main() {
    int arr[] = { 42, 42, 21 };
    printf("%d\n", arr[3]);
    return 0;
}
  • undefiniert
  • 42
  • 21
  • Es erscheint ein grĂŒner Hase

Quiz 9 – Live-Code

#include <stdio.h>

int main() {
    int arr[] = { 42, 42, 21 };
    printf("%d\n", arr[3]);
    return 0;
}
c

Quiz 10

Frage: Wie viele Bytes belegt das Array wort?

char wort[] = "Hallo EidP!";
  • 12

 

ErlÀuterung

  • Der String enthĂ€lt 11 Zeichen → 11 Bytes
  • Plus 1 Byte fĂŒr die Null-Terminierung ('\0') → 12 Bytes

Quiz 11

Frage: Was ist das Ergebnis der Ausgabe?

#include <stdio.h>
#include <string.h>

char wort[] = "Eins\0Zwei\0Drei\0";
printf("%lu\n", strlen(wort));
  • 4

 

ErlÀuterung

  • strlen() erwartet einen NULL-terminierten String und hört beim ersten NULL-Byte auf

Quiz 12

Frage: Und wie lang ist wort wirklich?

#include <stdio.h>
#include <string.h>

char wort[] = "Eins\0Zwei\0Drei\0";
printf("%lu\n", sizeof(wort));
  • 16

 

ErlÀuterung

  • Der String enthĂ€lt 12 lesbare Zeichen und 3 NULL-Bytes → 15 Bytes
  • Am Ende kommt aber trotz allem immer noch ein weiteres NULL-Byte → 16 Bytes

Quiz 12 – Live-Code

#include <stdio.h>
#include <string.h>

int main() {
    char wort[] = "Eins\0Zwei\0Drei\0";
    printf("%lu\n", strlen(wort));
    printf("%lu\n", sizeof(wort));
}
c

Quiz 13

Welche Werte haben die Variablen lauf (links) und foo (rechts) hinter der der Schleife?

int lauf = 0, foo = 0;

do {
    if (lauf % 2 == 0) {
        if (foo) {
            foo += 3;
        } else {
            foo = 3;
        }
    }
    if (foo % 9 == 0) {
        break;
    }
    ++lauf;
} while (lauf);
  • 4

  • 9

Quiz 13 – Live-Code

#include <stdio.h>

int main() {
    int lauf = 0, foo = 0;

    do {
        if (lauf % 2 == 0) {
            if (foo) {
                foo += 3;
            } else {
                foo = 3;
            }
        }
        if (foo % 9 == 0) {
            break;
        }
        lauf++;
    } while (lauf);
    printf("lauf = %d, foo = %d\n", lauf, foo);

    return 0;
}
c

Quiz 14

Frage: Wie sieht die dritte Zeile der Ausgabe aus?

for (int i = 0; i < 100; ++i) {
    if (i % 5 != 0) {
        continue;
    }
    printf("%d: ", i);
    for (int k = 3; k > 0; k--) {
        printf("%d ", k);
    }
    printf("\n");
}
  • 10: 3 2 1 0

Quiz 14 – Live-Code

Frage: Wie sieht die dritte Zeile der Ausgabe aus?

#include <stdio.h>

int main() {
    for (int i = 0; i < 100; ++i) {
        if (i % 5 != 0) {
            continue;
        }
        printf("%d: ", i);
        for (int k = 3; k > 0; --k) {
            printf("%d ", k);
        }
        printf("\n");
    }

    return 0;
}
c

Quiz 15

Frage: HĂ€ngt die GrĂ¶ĂŸe eines Zeigers von dem Datentyp / der Datenstruktur ab, auf die er zeigt?

  • Ja
  • Nein

ErlÀuterung

Er hÀngt nur von der Wortbreite der Prozessorarchitektur ab.

Quiz 16

Frage: Wie groß ist der Zeiger p auf einer 32-Bit-Architektur?

char *p;
  • 4 Bytes
  • 8 Bytes
  • 2 Bytes
  • 16 Bytes

Quiz 17

Frage: Worauf zeigen die Zeiger p1 und p2 am Ende des Programms?

int a = 42;
int arr[] = { 4, 3, 2, 1};

int *p1 = &a, *p2 = arr + 3;

*p1 = 3;
arr[3] = 4711;
p1 = p2;
arr[1] = -1;
p2 -= 2;
*p2 = 1;
  • a
  • arr[0]
  • arr[1]
  • arr[2]
  • arr[3]

  • a
  • arr[0]
  • arr[1]
  • arr[2]
  • arr[3]

Quiz 17 – Live-Code

#include <stdio.h>

int main() {
    int a = 42;
    int arr[] = {4, 3, 2, 1};

    int *p1 = &a, *p2 = arr + 3;

    *p1 = 3;
    arr[3] = 4711;
    p1 = p2;
    arr[1] = -1;
    p2 -= 2;
    *p2 = 1;

    printf("&a: %p\narr: %p\n", &a, arr);
    printf("[0]: %p, [1]: %p, [2]: %p, [3]: %p\n",
           &(arr[0]), &(arr[1]), &(arr[2]), &(arr[3]));
    printf("p1: %p\n", p1);
    printf("p2: %p\n", p2);
    return 0;
}
c

Quiz 18

Frage: Was ist die Ausgabe des Programms?

const int n = 10, m = n / 2;
int *x = new int[n]; // Wegen const kein VLA
int *y = x + m;

for (int i = 0; i < m; ++i) {
    x[i] = i;
    y[i] = (m - i);
}

for (int i = 0; i < n; ++i) {
        printf("%d,", x[i]);
}
printf("\n");
  • 0,1,2,3,4,5,4,3,2,1,

Quiz 18 – Live-Code

#include <stdio.h>

int main() {
    const int n = 10, m = n / 2;
    int *x = new int[n];
    int *y = x + m;

    for (int i = 0; i < m; ++i) {
        x[i] = i;
        y[i] = (m - i);
    }

    for (int i = 0; i < n; ++i) {
        printf("%d,", x[i]);
    }
    printf("\n");
}
c

Quiz 19

Frage: In welchen Speicherbereichen liegen die Variablen?

int x = 2, y;
int main() {
    int *p = new int[42];
}
  • x
    • Datensegment
  • p
    • Stack
  • *p
    • Heap
  • y
    • Datensegment

Quiz 20

Frage: Was ist die Ausgabe des Programms?

int a[10];

for (int i = 0; i < 10; ++i) {
    a[i] = i + i;
}

int sum = 0;
for (int i = 0; i < 20; ++i) {
    sum = a[i];
}
printf("sum = %d\n", sum);
  • 0
  • 20
  • Undefiniertes Verhalten
  • Das Programm stĂŒrzt ab.

Quiz 20 – Live-Code

#include <stdio.h>

int main() {
    int a[10];
    int sum = 0;

    for (int i = 0; i < 10; ++i) {
        a[i] = i + i;
    }

    for (int i = 0; i < 20; ++i) {
        sum = a[i];
    }
    printf("sum = %d\n", sum);
    return 0;
}
cpp
  • GCC hat in diesem Fall die Zellen des Arrays genullt. Das muss aber nicht sein!

Quiz 21

Frage: Was ist die Ausgabe des Programms?

#include <stdio.h>

static int sum(int *x, int n) {
    int ret = 0;
    for (int i = 0; i < n; ++i) {
        ret += x[i];
        x[i] = 1;
    }
    return ret;
}

int main() {
    int a[] = { 10, 5, 3, 2, 1};
    printf("sum = %d, sum = %d\n", sum(a, 5), sum(a, 5));
}
  • sum = 21, sum = 5
  • sum = 21, sum = 21
  • Undefiniertes Verhalten
  • Das Programm stĂŒrzt ab.

Quiz 21 – Live-Code

#include <stdio.h>

static int sum(int *x, int n) {
    int ret = 0;
    for (int i = 0; i < n; ++i) {
        ret += x[i];
        x[i] = 1;
    }
    return ret;
}

int main() {
    int a[] = { 10, 5, 3, 2, 1};
    printf("sum = %d, sum = %d\n", sum(a, 5), sum(a, 5));
}
c

Quiz 22

Frage: Welchen Wert hat depth?

struct Object3D {
    unsigned int width;
    unsigned int height;
    unsigned int depth;
};

int main() {
    struct Object3D obj1 = { .width = 3, .height = 4 };
}
  • 0
  • Beliebig (Undefiniertes Verhalten)
  • Das Programm stĂŒrzt ab.

ErlÀuterung

  • Bei Initialisierung mit designierter Variablenliste gelten die gleichen Regeln wie fĂŒr statische und globale Variablen (Initialisierung mit 0, falls nicht explizit gesetzt)

Quiz 22 – Live-Code

#include <stdio.h>

struct Object3D {
    unsigned int width;
    unsigned int height;
    unsigned int depth;
};

int main() {
    struct Object3D obj1 = { .width = 3, .height = 4 };
    printf("width = %d, height = %d, depth = %d\n",
           obj1.width, obj1.height, obj1.depth);
}
c

Quiz 23

Was ist die Ausgabe des Programms?

#include <stdio.h>

struct Rectangle {
    int x, y;
    int width, height;
};

static struct Rectangle* newRectangle() {
    struct Rectangle rect = {0, 0, 10, 20};
    return &rect;
}

int main() {
    struct Rectangle* rect = newRectangle();
    printf("width = %d, height = %d\n", rect->width, rect->height);
}
  • width = 10, height = 20
  • Undefiniertes Verhalten
  • Das Programm stĂŒrzt ab.

Quiz 23 – Live-Code

#include <stdio.h>

struct Rectangle {
    int x, y;
    int width, height;
};

static struct Rectangle* newRectangle() {
    struct Rectangle rect = {0, 0, 10, 20};
    return ▭
}

int main() {
    struct Rectangle* rect = newRectangle();
    printf("width = %d, height = %d\n", rect->width, rect->height);
}
c

Quiz 24

Frage: Was ist die Ausgabe des Programms?

#include <stdio.h>
int cnt = 0;

int fak(int n) {
    int cnt = 0;
    if (n == 0) {
        ++cnt;
        return 1;
    }
    {
        extern int cnt;
        ++cnt;
    }
    return n * fak(n - 1);
}

int main() {
    printf("fak(5) = %d, cnt = %d\n", fak(5), cnt);
}
  • fak(5) = 120, cnt = 5
  • Undefiniertes Verhalten
  • Das Programm stĂŒrzt ab.

Quiz 24 – Live-Code

#include <stdio.h>
int cnt = 0;

int fak(int n) {
    int cnt = 0;
    if (n == 0) {
        ++cnt;
        return 1;
    }
    {
        extern int cnt;
        ++cnt;
    }
    return n * fak(n - 1);
}

int main() {
    printf("fak(5) = %d", fak(5));
    printf(", cnt = %d\n", cnt);
}
c

Quiz 25

Was passiert bei dem Aufruf von fak(10000)?

  • Die FakultĂ€t von 10000 wird ausgegeben.
  • Undefiniertes Verhalten
  • Das Programm stĂŒrzt ab.
  • Der Compiler weigert sich, zu bauen

Bonus-Quiz (FĂŒr die ganz harten Programmierer:innen 😉)

Frage: Was gibt das folgende Programm aus? (ASCII-Tabelle zur Hand nehmen)

char quelle[] = "Qivv} \\-Qew";
char ziel[12] = { 0 };

int i = 0;
for (char *c = quelle; *c != '\0'; c++, i++) {
        if (*c == ' ' || *c == '-') {
            ziel[i] = *c;
            continue;
        }
        ziel[i] = *c - 4;
}
printf("%s\n", ziel);
  • Merry X-Mas

Bonus-Quiz – Live-Code

#include <stdio.h>

int main() {
    char quelle[] = "Qivv} \\-Qew";
    char ziel[12] = { 0 };

    int i = 0;
    for (char *c = quelle; *c != '\0'; c++, i++) {
            if (*c == ' ' || *c == '-') {
                ziel[i] = *c;
                continue;
            }
            ziel[i] = *c - 4;
    }
    printf("%s\n", ziel);
}
c

🎄 🎅 Weihnachten und Silvester 2025 🎇 🎊

🎆 Alles Gute und einen guten Rutsch! Bis 2026! 🎆

Logo Sys
Weihnachtsvorlesung