🔄

Vorlesung 3

Type Casting, Konstanten
und Operatoren

Fortgeschrittene Algorithmen und Programmierung
Wintersemester 2025/26
Prof. Dr. Alexandra Mikityuk
📍 Raum C308 | 🏫 HTW Berlin

Drücken Sie → oder Leertaste zum Starten

Themen der heutigen Vorlesung

Teil 1: Konvertierung & Konstanten

  • Type Casting (Cast-Operator)
  • Implizite vs. Explizite Konvertierung
  • Konstanten mit const
  • Präprozessor #define

Teil 2: Zufallszahlen & Operatoren

  • Zufallszahlen generieren
  • Kombinierte Zuweisungen
  • Inkrement/Dekrement
  • Operator-Prioritäten

Was ist Type Casting?

Type Casting = Typ-Umwandlung

Manchmal müssen wir einen Wert von einem Datentyp in einen anderen umwandeln.

💡 Alltags-Analogie:
Sie haben Wasser in einer Flasche (Container-Typ 1) und möchten es in ein Glas (Container-Typ 2) umfüllen. Das Wasser bleibt dasselbe, aber der Container ändert sich!

Implizit (automatisch)

C macht es von selbst

Explizit (manuell)

Wir sagen C, was zu tun ist

Implizite Typ-Konvertierung

C konvertiert automatisch, wenn ein kleinerer Typ einem größeren zugewiesen wird:

int ganzzahl = 42; double kommazahl; kommazahl = ganzzahl; // int → double (automatisch!) printf("%.2lf\n", kommazahl); // Ausgabe: 42.00 // Auch bei Berechnungen: int a = 5; double b = 2.0; double ergebnis = a + b; // a wird zu 5.0 konvertiert printf("%.2lf\n", ergebnis); // Ausgabe: 7.00
💡 Regel: Kleinerer Typ → Größerer Typ funktioniert automatisch und sicher!

Explizites Type Casting (Cast-Operator)

Wenn wir von größer nach kleiner konvertieren wollen, müssen wir es explizit sagen:

double kommazahl = 3.14159; int ganzzahl; // Expliziter Cast mit (int) ganzzahl = (int)kommazahl; // Nachkommastellen werden abgeschnitten! printf("%d\n", ganzzahl); // Ausgabe: 3 // Praktisches Beispiel: Division int zaehler = 5; int nenner = 2; double ergebnis1 = zaehler / nenner; // 2.0 (Integer-Division!) double ergebnis2 = (double)zaehler / nenner; // 2.5 (Korrekt!) printf("Ohne Cast: %.2lf\n", ergebnis1); printf("Mit Cast: %.2lf\n", ergebnis2);

Praxis: Type Casting bei Berechnungen

#include <stdio.h> int main() { // Durchschnitt berechnen int note1 = 85, note2 = 90, note3 = 78; int summe = note1 + note2 + note3; // FALSCH: Integer-Division double durchschnitt1 = summe / 3; printf("Falsch: %.2lf\n", durchschnitt1); // 84.00 // RICHTIG: Mit Cast double durchschnitt2 = (double)summe / 3; printf("Richtig: %.2lf\n", durchschnitt2); // 84.33 return 0; }
⚠️ Achtung: Bei Integer-Division werden Nachkommastellen IMMER abgeschnitten, auch wenn das Ergebnis in eine double-Variable gespeichert wird!

Quiz: Type Casting

Was ist das Ergebnis von: int x = 7 / 2;

A) 3.5
B) 3
C) 4
D) Compiler-Fehler

💡 Tipp: Beide Zahlen sind Integer!

Konstanten - Unveränderliche Werte

Warum Konstanten?

  • Sicherheit: Wert kann nicht versehentlich geändert werden
  • Lesbarkeit: Namen statt "magische Zahlen"
  • Wartbarkeit: Änderung nur an einer Stelle nötig
  • Performance: Compiler kann optimieren
Beispiel: Die Zahl Pi (3.14159...) ändert sich nie!
Besser als Konstante definieren statt überall 3.14159 einzutippen.

Konstanten mit const

Das const Schlüsselwort macht eine Variable unveränderlich:

const double PI = 3.14159265; const int MAX_STUDENTEN = 100; const double MEHRWERTSTEUER = 0.19; // Verwenden wie normale Variablen double radius = 5.0; double umfang = 2 * PI * radius; printf("Umfang: %.2lf\n", umfang); // FEHLER: Versuch, const zu ändern // PI = 3.14; // ❌ Compiler-Fehler!
💡 Convention: Konstanten-Namen werden traditionell in GROSSBUCHSTABEN geschrieben!

Konstanten mit #define

#define ist eine Präprozessor-Direktive (vor dem Kompilieren):

#include <stdio.h> // Konstanten mit #define (kein = und kein ;) #define PI 3.14159265 #define MAX_STUDENTEN 100 #define KURS_NAME "Algorithmen" int main() { double radius = 5.0; double flaeche = PI * radius * radius; printf("Kurs: %s\n", KURS_NAME); printf("Fläche: %.2lf\n", flaeche); return 0; }
⚠️ Beachten: #define verwendet KEIN = und KEIN ;! Der Präprozessor ersetzt einfach alle Vorkommen vor dem Kompilieren.

const vs. #define - Was ist besser?

Feature const #define
Typ-Sicherheit ✅ Hat einen Datentyp ❌ Nur Text-Ersetzung
Debugging ✅ Einfacher zu debuggen ❌ Schwieriger
Speicher ⚠️ Belegt Speicher ✅ Kein Speicher
Gültigkeitsbereich ✅ Respektiert Scope ⚠️ Global überall
Empfehlung ✅ Bevorzugen! ⚠️ Nur wenn nötig
💡 Moderne C-Programmierung: Verwenden Sie const wann immer möglich. #define ist ein Relikt aus alten C-Zeiten.

Quiz: Konstanten

Welche Deklaration ist korrekt für eine Konstante mit #define?

A) #define PI = 3.14;
B) #define PI 3.14
C) const #define PI 3.14;
D) #define const PI = 3.14;

Zufallszahlen generieren

Warum Zufallszahlen?

  • Spiele: Würfel werfen, Karten mischen
  • Simulation: Zufällige Ereignisse modellieren
  • Kryptographie: Sichere Passwörter, Schlüssel
  • Testing: Zufällige Testdaten generieren
💡 Wichtig: Computer erzeugen Pseudo-Zufallszahlen - sie sehen zufällig aus, folgen aber einem deterministischen Algorithmus.

Die rand() Funktion

rand() gibt eine Zufallszahl zwischen 0 und RAND_MAX zurück:

#include <stdio.h> #include <stdlib.h> // Für rand() und RAND_MAX int main() { // Zufallszahl generieren int zufallszahl = rand(); printf("Zufallszahl: %d\n", zufallszahl); // RAND_MAX ist die größte mögliche Zufallszahl printf("RAND_MAX: %d\n", RAND_MAX); return 0; }
⚠️ Problem: Ohne weitere Schritte gibt rand() bei jedem Programmlauf die GLEICHEN "Zufallszahlen" zurück!

srand() - Den Zufallsgenerator initialisieren

srand() setzt den "Seed" (Startwert) für den Zufallsgenerator:

#include <stdio.h> #include <stdlib.h> #include <time.h> // Für time() int main() { // Seed mit aktueller Zeit setzen (immer unterschiedlich!) srand(time(NULL)); // Jetzt echte "Zufallszahlen" printf("Zufallszahl 1: %d\n", rand()); printf("Zufallszahl 2: %d\n", rand()); printf("Zufallszahl 3: %d\n", rand()); return 0; }
💡 Regel: Rufen Sie srand(time(NULL)) EINMAL am Anfang von main() auf, dann können Sie rand() beliebig oft verwenden!

Zufallszahlen in einem Bereich

Meistens brauchen wir Zufallszahlen in einem bestimmten Bereich (z.B. Würfel: 1-6):

// Formel: rand() % (max - min + 1) + min // Würfel: 1 bis 6 int wuerfel = rand() % 6 + 1; // Zahl zwischen 0 und 99 int prozent = rand() % 100; // Zahl zwischen 10 und 50 int bereich = rand() % 41 + 10; // 41 = (50-10+1)
Erklärung: rand() % 6 + 1

rand() % 6 ergibt 0, 1, 2, 3, 4, oder 5
+ 1 verschiebt zu 1, 2, 3, 4, 5, oder 6
• Perfekt für einen Würfel!

Praxis: Würfel-Simulator

#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { // Zufallsgenerator initialisieren srand(time(NULL)); printf("Würfel-Simulator\n"); printf("================\n\n"); // 5 Mal würfeln for (int i = 1; i <= 5; i++) { int wurf = rand() % 6 + 1; printf("Wurf %d: %d\n", i, wurf); } return 0; }
Mögliche Ausgabe:
Würfel-Simulator
================

Wurf 1: 4
Wurf 2: 2
Wurf 3: 6
Wurf 4: 1
Wurf 5: 5

Quiz: Zufallszahlen

Welche Formel erzeugt eine Zufallszahl zwischen 1 und 10?

A) rand() % 10
B) rand() % 10 + 1
C) rand() % 11
D) rand() / 10 + 1

Kombinierte Zuweisungs-Operatoren

Abkürzungen für häufige Operationen:

Operator Beispiel Entspricht Beschreibung
+= x += 5 x = x + 5 Addition
-= x -= 3 x = x - 3 Subtraktion
*= x *= 2 x = x * 2 Multiplikation
/= x /= 4 x = x / 4 Division
%= x %= 3 x = x % 3 Modulo (Rest)

Praxis: Kombinierte Operatoren

#include <stdio.h> int main() { int punkte = 100; printf("Start: %d Punkte\n", punkte); punkte += 50; // Bonus hinzufügen printf("Nach Bonus: %d\n", punkte); punkte -= 30; // Strafe abziehen printf("Nach Strafe: %d\n", punkte); punkte *= 2; // Verdoppeln printf("Verdoppelt: %d\n", punkte); punkte /= 4; // Vierteln printf("Geviertelt: %d\n", punkte); return 0; }
Ausgabe:
Start: 100 Punkte
Nach Bonus: 150
Nach Strafe: 120
Verdoppelt: 240
Geviertelt: 60

Inkrement (++) und Dekrement (--)

Spezielle Operatoren zum Erhöhen/Verringern um 1:

Operator Beispiel Entspricht Wann verwenden?
++ (Inkrement) x++ x = x + 1 Zähler erhöhen
-- (Dekrement) x-- x = x - 1 Zähler verringern
int zaehler = 0; zaehler++; // zaehler wird zu 1 zaehler++; // zaehler wird zu 2 zaehler++; // zaehler wird zu 3 zaehler--; // zaehler wird zu 2 printf("Zaehler: %d\n", zaehler); // Ausgabe: 2

Prefix (++x) vs. Postfix (x++)

Postfix (x++)

Erst verwenden, dann erhöhen

int x = 5; int y = x++; // y = 5, x = 6 printf("y: %d\n", y); // 5 printf("x: %d\n", x); // 6

Prefix (++x)

Erst erhöhen, dann verwenden

int x = 5; int y = ++x; // x = 6, y = 6 printf("y: %d\n", y); // 6 printf("x: %d\n", x); // 6
💡 Praxis-Tipp: In den meisten Fällen (z.B. Schleifen) macht der Unterschied nichts aus. Verwenden Sie das, was lesbarer ist!

Operator-Prioritäten

In welcher Reihenfolge werden Operationen ausgeführt?

Wie in der Mathematik: Punkt vor Strich!

int x = 5 + 3 * 2; // Was ist das Ergebnis? // Option 1: (5 + 3) * 2 = 16 ❌ // Option 2: 5 + (3 * 2) = 11 ✅ printf("%d\n", x); // Ausgabe: 11
⚠️ Regel: Multiplikation und Division haben höhere Priorität als Addition und Subtraktion!

Die wichtigsten Operator-Prioritäten

Priorität Operator Beschreibung Assoziativität
1 (höchste) () [] . Klammern, Arrays, Zugriff → Links nach rechts
2 ++ -- ! (type) Unäre Operatoren, Cast ← Rechts nach links
3 * / % Multiplikation, Division, Modulo → Links nach rechts
4 + - Addition, Subtraktion → Links nach rechts
5 < <= > >= Vergleich → Links nach rechts
6 == != Gleichheit/Ungleichheit → Links nach rechts
7 (niedrigste) = += -= *= /= Zuweisung ← Rechts nach links

Praxis: Operator-Prioritäten

int a = 10, b = 5, c = 2; // Beispiel 1: Punkt vor Strich int x = a + b * c; // 10 + (5 * 2) = 20 // Beispiel 2: Klammern ändern Priorität int y = (a + b) * c; // (10 + 5) * 2 = 30 // Beispiel 3: Mehrere Operationen int z = a * b + c / 2; // (10*5) + (2/2) = 51 // Beispiel 4: Inkrement int w = a++ + ++b; // 10 + 6 = 16, dann a=11 printf("x=%d, y=%d, z=%d, w=%d\n", x, y, z, w);
💡 Best Practice: Im Zweifelsfall Klammern verwenden! Code ist lesbar > kurz.

Quiz: Operator-Priorität

Was ist das Ergebnis von: int x = 10 + 5 * 2;

A) 30
B) 20
C) 25
D) 15

💡 Tipp: Punkt vor Strich!

Zusammenfassung

Was haben wir gelernt?

  • Type Casting - Explizit mit (type)
  • const für typsichere Konstanten
  • #define für Präprozessor-Konstanten
  • rand() und srand() für Zufallszahlen
  • +=, -=, *=, /= kombinierte Operatoren
  • ++, -- Inkrement/Dekrement
  • Prefix vs. Postfix
  • Operator-Prioritäten beachten!
🎯 Praxis-Tipp:
Üben Sie diese Konzepte mit kleinen Programmen - sie sind fundamental für alle weiteren Themen!

Vielen Dank!

Fragen? Weiter üben!

Prof. Dr. Alexandra Mikityuk
Raum: C308
Sprechstunde: Nach Vereinbarung

Nächste Vorlesung:
Funktionen und Pointer!

💻 Übungsaufgabe:
Schreiben Sie ein Programm, das Zufallszahlen generiert und Berechnungen damit durchführt!
🏠 Zurück zur Startseite
1 / 28