Einführung in die Programmierung - Exam.pdf

Einführung in die Programmierung - Exam
Aufgabe 1) Gegeben ist folgendes einfaches Programmausschnitt in einer fiktiven Programmiersprache: int a = 5;int b = 2 * (a + 3);if (a < b) { a = a + 1;} else { b = b - 1;} a) Erstelle den Syntaxbaum für dieses Programmausschnitt und erkläre ihn. Nutze dazu die Kontextfreie Grammatik: Stmt → IfStmt | AssignStmt IfStmt → 'if' '(' Expr ')' '{' Stmt '}' 'else' '{' Stmt '}' AssignStmt → 'int' V...

© StudySmarter 2024, all rights reserved.

Aufgabe 1)

Gegeben ist folgendes einfaches Programmausschnitt in einer fiktiven Programmiersprache:

int a = 5;int b = 2 * (a + 3);if (a < b) {    a = a + 1;} else {    b = b - 1;}

a)

Erstelle den Syntaxbaum für dieses Programmausschnitt und erkläre ihn. Nutze dazu die Kontextfreie Grammatik:

  • StmtIfStmt | AssignStmt
  • IfStmt → 'if' '(' Expr ')' '{' Stmt '}' 'else' '{' Stmt '}'
  • AssignStmt → 'int' Var '=' Expr;
  • ExprArithExpr | RelExpr
  • ArithExprVar | Const | '(' Expr ')' | Expr '+' Expr | Expr '-' Expr | Expr '*' Expr | Expr '/' Expr
  • RelExprExpr '<' Expr | Expr '>' Expr | Expr '==' Expr
.

Lösung:

Um den Syntaxbaum für den gegebenen Programmausschnitt zu erstellen, verwenden wir die bereitgestellte kontextfreie Grammatik.

Hier ist der Programmausschnitt:

int a = 5;int b = 2 * (a + 3);if (a < b) {    a = a + 1;} else {    b = b - 1;}

Dies führt zu folgendem Syntaxbaum:

  • StmtList
    • AssignStmt
      • int Var → a
      • =
      • ExprArithExprConst → 5
    • AssignStmt
      • int Var → b
      • =
      • ExprArithExpr
        • 2
        • *
        • (ExprArithExpr
          • Var → a
          • +
          • ExprArithExpr
            • Const → 3
        • )
    • IfStmt
      • if
      • (ExprRelExpr
        • ExprArithExprVar → a
        • <
        • ExprArithExprVar → b
      • )
    • {StmtAssignStmt
      • Var → a
      • =
      • ExprArithExpr
        • Var → a
        • +
        • 1
      • ;
      }
    • else
    • {StmtAssignStmt
      • Var → b
      • =
      • ExprArithExpr
        • Var → b
        • -
        • 1
      • ;
      }

Erklärung des Syntaxbaums:

  • Der Baum beginnt mit der Wurzel 'StmtList', die eine Liste von Anweisungen im Programm darstellt.
  • Die erste Zuweisungsanweisung (AssignStmt) initialisiert die Variable 'a' mit dem Wert 5.
  • Die zweite Zuweisungsanweisung (AssignStmt) initialisiert die Variable 'b' mit dem Ausdruck '2 * (a + 3)'. Beachte, dass der Ausdruck selbst zu einem 'ArithExpr' reduziert wird, das aus einer Multiplikation besteht.
  • Die dritte Anweisung ist eine 'IfStmt', die überprüft, ob 'a' kleiner als 'b' ist.
  • Wenn die Bedingung erfüllt ist, wird 'a' um 1 erhöht (innere 'AssignStmt').
  • Wenn die Bedingung nicht erfüllt ist, wird 'b' um 1 verringert (innere 'AssignStmt' im else-Zweig).

b)

Beschreibe die Semantik des gegebenen Programms in Bezug auf \textit{Operational Semantics}. Definiere, wie das Programm auf einer abstrakten Maschine ausgeführt wird. Nutze dazu einen Pseudocode, um die Ausführung Schritt für Schritt darzustellen.

Lösung:

Beschreibung der Semantik des gegebenen Programms in Bezug auf Operational Semantics

Die Operational Semantics definieren, wie jedes Statement des Programms auf einer abstrakten Maschine ausgeführt wird. Das Ziel ist es, die Übergänge zwischen den Zuständen der Maschine zu beschreiben, während das Programm ausgeführt wird.

Hier ist der gegebene Programmausschnitt:

int a = 5;int b = 2 * (a + 3);if (a < b) {    a = a + 1;} else {    b = b - 1;}

Um die Semantik des Programms zu beschreiben, betrachten wir folgende Schritte:

  1. Initialzustand:
  • Der Speicher ist leer.
  • Schritt 1 (int a = 5;)
    • Variable a wird initialisiert und bekommt den Wert 5.
    • Speicherzustand: {a: 5}
  • Schritt 2 (int b = 2 * (a + 3);)
    • Berechne den Ausdruck a + 3.
    • a hat den Wert 5, also lautet a + 3 gleich 8.
    • Multipliziere das Ergebnis (8) mit 2.
    • Variable b wird initialisiert und bekommt den Wert 16.
    • Speicherzustand: {a: 5, b: 16}
  • Schritt 3 (if (a < b) ...)
    • Teste die Bedingung a < b.
    • Da a = 5 und b = 16, ist die Bedingung wahr.
  • Schritt 4 (a = a + 1;)
    • Da die Bedingung in Schritt 3 wahr ist, wird der if-Zweig ausgeführt.
    • Addiere 1 zu a.
    • Ändere den Wert von a zu 6 (5 + 1).
    • Speicherzustand: {a: 6, b: 16}

    Finaler Speicherzustand: {a: 6, b: 16}

    Um die Ausführung schrittweise darzustellen, nutzen wir nun den Pseudocode:

    BEGIN Execution    // Initialzustand    a = ⊥    b = ⊥    // Schritt 1: Initialisierung von a    a = 5    // Schritt 2: Berechnung und Initialisierung von b    temp1 = a + 3    temp2 = 2 * temp1    b = temp2    // Schritt 3: Auswertung der if-Bedingung    if (a < b) THEN        // Schritt 4: if-Zweig wird ausgeführt        temp3 = a + 1        a = temp3    ELSE        // else-Zweig wird ausgeführt (wird in diesem Fall nicht ausgeführt)        temp4 = b - 1        b = temp4    ENDIF END Execution

    Dieser Pseudocode stellt die sequentielle Ausführung des Programms in einer abstrakten Maschine dar, wobei jeder Übergang und jede Berechnung explizit gezeigt wird.

    c)

    Verwende \textit{Axiomatic Semantics}, um zu zeigen, dass das gegebene Programm korrekt ist. Formuliere Vorbedingungen und Nachbedingungen und zeige ihren logischen Zusammenhang.

    Lösung:

    Verwendung der Axiomatic Semantics zur Verifizierung der Programmkorrektheit

    Axiomatic Semantics nutzen logische Aussagen, um Vorbedingungen (Preconditions) und Nachbedingungen (Postconditions) für Programme zu formulieren und ihre Korrektheit zu beweisen. In diesem Zusammenhang werden wir die Hoare-Logik verwenden.

    Gegeben ist der Programmausschnitt:

    int a = 5;int b = 2 * (a + 3);if (a < b) {    a = a + 1;} else {    b = b - 1;}

    Die Korrektheit des Programms muss unter der Annahme spezifischer Vorbedingungen und Nachbedingungen gezeigt werden.

    Vorbedingungen:

    Bevor das Programm ausgeführt wird, gibt es keine besonderen Vorbedingungen für die Variablen a und b, da sie im Programm selbst initialisiert werden.Wir nehmen an, dass der Speicher korrekt initialisiert ist:

    • Precondition: true (d.h. keine spezielle Vorbedingung nötig)

    Nachbedingungen:

    Für die Nachbedingungen definieren wir die erwarteten Werte der Variablen am Ende der Programmausführung.Nach der Ausführung des Programms erwarten wir Folgendes:

    • Postcondition: a = 6 ∧ b = 16

    Schritte zur Verifikation:

    1. Schritt 1: Initialisierung von a
      { true } int a = 5; { a = 5 }
      Hier setzen wir den Wert von a auf 5. Dies ergibt die Nachbedingung a = 5.
    2. Schritt 2: Initialisierung von b
      { a = 5 } int b = 2 * (a + 3); { a = 5 ∧ b = 16 }
      Hier berechnen wir b als 2 * (a + 3), was zu 2 * 8 führt, was 16 ergibt. Dies führt zur Nachbedingung a = 5 ∧ b = 16.
    3. Schritt 3: Bedingungsauswertung
      { a = 5 ∧ b = 16 } if (a < b) ... 

      Die Bedingung a < b ist wahr, da 5 < 16. Wir gehen also in den if-Zweig.

    4. Schritt 4a: if-Zweig
      { a = 5 ∧ b = 16 ∧ a < b } a = a + 1; { a = 6 ∧ b = 16 }
      Da die Bedingung a < b wahr ist, wird der Wert von a um 1 erhöht, so dass a = 6 ist. Die Nachbedingung ist nun a = 6 ∧ b = 16.
    5. Schritt 4b: else-Zweig (nicht ausgeführt)
      { a = 5 ∧ b = 16 ∧ ¬(a < b) } b = b - 1; { a = 5 ∧ b = 15 }

      Da die Bedingung a < b wahr ist, wird der else-Zweig nicht ausgeführt.

    6. Endzustand:
      Die Nachbedingung nach der Ausführung des gesamten Programms ist: { a = 6 ∧ b = 16 }

    Zusammenfassung:

    Wir haben die Korrektheit des gegebenen Programms unter Verwendung von Axiomatic Semantics nachgewiesen. Vom Anfangszustand ohne spezielle Vorbedingung haben wir gezeigt, dass die Nachbedingung a = 6 ∧ b = 16 am Ende der Programmausführung erfüllt ist.

    d)

    Führe eine Typüberprüfung für das Programmsegment durch. Identifiziere mögliche Typfehler und beschreibe, wie diese behoben werden können. Annahmen für die Typen:

    • 'int': Ganzzahltypen
    • 'bool': Boolesche Typen
    .

    Lösung:

    Typüberprüfung für das gegebene Programmausschnitt

    Die Typüberprüfung (Type Checking) stellt sicher, dass die Typen der Variablen und Ausdrücke im Programm korrekt verwendet werden und dass keine Typfehler auftreten. Hier ist der gegebene Programmausschnitt:

    int a = 5;int b = 2 * (a + 3);if (a < b) {    a = a + 1;} else {    b = b - 1;}

    Wir übernehmen folgende Annahmen für die Typen:

    • int: Ganzzahltypen
    • bool: Boolesche Typen

    Typüberprüfung Schritt für Schritt:

    1. Schritt 1: Initialisierung von a
      int a = 5;

      Hier wird die Variable a als int deklariert und mit der Ganzzahl 5 initialisiert. Die Typen sind kompatibel: a: int = 5: int. Es gibt keinen Typfehler.

    2. Schritt 2: Initialisierung von b
      int b = 2 * (a + 3);

      Hier wird die Variable b als int deklariert und mit dem Ausdruck 2 * (a + 3) initialisiert.

      • a ist bereits als int deklariert.
      • 3 ist eine Ganzzahl (int).
      • Der Ausdruck a + 3 ist daher vom Typ int.
      • 2 ist eine Ganzzahl (int), daher ist der Ausdruck 2 * (a + 3) ebenfalls vom Typ int.
      Die Typen sind kompatibel: b: int = 2 * (a + 3): int. Es gibt keinen Typfehler.
    3. Schritt 3: Bedingte Anweisung
      if (a < b) {    a = a + 1;} else {    b = b - 1;}

      Hier prüfen wir die Bedingung a < b und führen entsprechend den if- oder else-Zweig aus:

      • Die Bedingung a < b:
        • a und b sind beide vom Typ int.
        • Der Vergleichsoperator < zwischen zwei int-Werten ergibt einen bool-Wert.
        • Die Bedingung (a < b) ist daher vom Typ bool.
      Die Typen sind kompatibel: a < b: bool. Es gibt keinen Typfehler.
      • if-Zweig:
        a = a + 1;
        • a ist vom Typ int.
        • 1 ist eine Ganzzahl (int).
        • Der Ausdruck a + 1 ergibt ebenfalls einen int-Wert.
        Die Typen sind kompatibel: a: int = a + 1: int. Es gibt keinen Typfehler.
      • else-Zweig:
        b = b - 1;
        • b ist vom Typ int.
        • 1 ist eine Ganzzahl (int).
        • Der Ausdruck b - 1 ergibt ebenfalls einen int-Wert.
        Die Typen sind kompatibel: b: int = b - 1: int. Es gibt keinen Typfehler.

    Zusammenfassung der Typüberprüfung:

    Alle verwendeten Typen im Programmausschnitt sind korrekt und kompatibel.Es tritt kein Typfehler auf, da die Deklarationen und Zuweisungen den entsprechenden Typen int und bool entsprechen. Das Programm ist typensicher.

    Aufgabe 2)

    Implementierung eines einfachen BuchhaltungssystemsDu bist dafür verantwortlich, ein einfaches Buchhaltungssystem zu programmieren, das grundlegende Datentypen und Datenstrukturen verwendet. Das System soll Einnahmen und Ausgaben verfolgen können. Es wird dich verschiedene Felder wie Betrag (int oder float) und Kategorie (char) verwenden lassen, und die Informationen sollen in einer geeigneten Datenstruktur gespeichert werden, um eine leichte Verwaltung und Abfrage zu ermöglichen.

    a)

    Teilaufgabe 1: Implementiere mit C++ eine Struktur, die die Einnahmen und Ausgaben als Einträge mit den Feldern amount, date und category speichert. Verwende dafür den passenden Datentyp für jedes Feld. Erstelle dann eine Funktion, die eine neue Einnahme oder Ausgabe zur Liste hinzufügt und dabei die Werte für amount, date und category annimmt.

    struct Entry {    int amount;    std::string date;    char category;};class AccountingSystem {private:    std::vector entries;public:    void addEntry(int amount, std::string date, char category) {        Entry newEntry = {amount, date, category};        entries.push_back(newEntry);    }};

    Lösung:

    Implementierung eines einfachen BuchhaltungssystemsDu bist dafür verantwortlich, ein einfaches Buchhaltungssystem zu programmieren, das grundlegende Datentypen und Datenstrukturen verwendet. Das System soll Einnahmen und Ausgaben verfolgen können. Es wird dich verschiedene Felder wie Betrag (int oder float) und Kategorie (char) verwenden lassen, und die Informationen sollen in einer geeigneten Datenstruktur gespeichert werden, um eine leichte Verwaltung und Abfrage zu ermöglichen.

    Teilaufgabe 1: Implementiere mit C++ eine Struktur, die die Einnahmen und Ausgaben als Einträge mit den Feldern amount, date und category speichert. Verwende dafür den passenden Datentyp für jedes Feld. Erstelle dann eine Funktion, die eine neue Einnahme oder Ausgabe zur Liste hinzufügt und dabei die Werte für amount, date und category annimmt.

     struct Entry {    int amount;    std::string date;    char category;};class AccountingSystem {private:    std::vector<Entry> entries;public:    void addEntry(int amount, std::string date, char category) {        Entry newEntry = {amount, date, category};        entries.push_back(newEntry);    }};

    b)

    Teilaufgabe 2: Ergänze die obige Klassen AccountingSystem um eine Methode calculateTotal, die den Gesamtbetrag aller Einträge in einer bestimmten Kategorie berechnet und zurückgibt. Implementiere außerdem eine Methode getAllEntries, die alle Einträge einer bestimmten Kategorie auflistet. Berücksichtige dabei, dass der Betrag Differenzen von Einnahmen und Ausgaben zeigen kann. Ein negativer Betrag bedeutet eine Ausgabe. Stelle sicher, dass bei der Berechnung der Gesamtbetrag korrekt summiert wird.

    class AccountingSystem {private:    std::vector entries;public:    void addEntry(int amount, std::string date, char category) {        Entry newEntry = {amount, date, category};        entries.push_back(newEntry);    }    int calculateTotal(char category) {        int total = 0;        for (const auto& entry : entries) {            if (entry.category == category) {                total += entry.amount;            }        }        return total;    }    std::vector getAllEntries(char category) {        std::vector categoryEntries;        for (const auto& entry : entries) {            if (entry.category == category) {                categoryEntries.push_back(entry);            }        }        return categoryEntries;    }};

    Lösung:

    Implementierung eines einfachen BuchhaltungssystemsDu bist dafür verantwortlich, ein einfaches Buchhaltungssystem zu programmieren, das grundlegende Datentypen und Datenstrukturen verwendet. Das System soll Einnahmen und Ausgaben verfolgen können. Es wird dich verschiedene Felder wie Betrag (int oder float) und Kategorie (char) verwenden lassen, und die Informationen sollen in einer geeigneten Datenstruktur gespeichert werden, um eine leichte Verwaltung und Abfrage zu ermöglichen.

    Teilaufgabe 2: Ergänze die obige Klassen AccountingSystem um eine Methode calculateTotal, die den Gesamtbetrag aller Einträge in einer bestimmten Kategorie berechnet und zurückgibt. Implementiere außerdem eine Methode getAllEntries, die alle Einträge einer bestimmten Kategorie auflistet. Berücksichtige dabei, dass der Betrag Differenzen von Einnahmen und Ausgaben zeigen kann. Ein negativer Betrag bedeutet eine Ausgabe. Stelle sicher, dass bei der Berechnung der Gesamtbetrag korrekt summiert wird.

    struct Entry {    int amount;    std::string date;    char category;};class AccountingSystem {private:    std::vector<Entry> entries;public:    void addEntry(int amount, std::string date, char category) {        Entry newEntry = {amount, date, category};        entries.push_back(newEntry);    }    int calculateTotal(char category) {        int total = 0;        for (const auto& entry : entries) {            if (entry.category == category) {                total += entry.amount;            }        }        return total;    }    std::vector<Entry> getAllEntries(char category) {        std::vector<Entry> categoryEntries;        for (const auto& entry : entries) {            if (entry.category == category) {                categoryEntries.push_back(entry);            }        }        return categoryEntries;    }};

    Aufgabe 3)

    Gegeben sei eine Liste von Zahlen. Entwickle ein Python-Programm, das folgende Aufgaben erfüllt:

    a)

    1. Erstelle eine Funktion sum_positive_numbers, die alle positiven Zahlen in der Liste summiert. Verwende eine for-Schleife und eine Bedingung, um nur die positiven Zahlen zu summieren.

    Lösung:

    Um die Aufgabe zu lösen, erstelle eine Funktion sum_positive_numbers, die alle positiven Zahlen in einer gegebenen Liste summiert. Hier ist der Code:

    def sum_positive_numbers(numbers_list):    # Initialisiere die Summe    total = 0        # Schleife durch jede Zahl in der Liste    for number in numbers_list:        # Überprüfe, ob die Zahl positiv ist        if number > 0:            # Addiere die positive Zahl zur Summe            total += number        # Rückgabe der Gesamtsumme    return total# Beispiel-Liste von Zahlennumbers = [1, -4, 7, 12, -3, 5]# Aufruf der Funktion und Ausgabe des Ergebnissesprint(sum_positive_numbers(numbers_list=numbers))

    In diesem Beispiel:

    • Wir initialisieren eine Variable total mit dem Wert 0, um die Summe der positiven Zahlen zu speichern.
    • Mit einer for-Schleife durchlaufen wir jede Zahl in der gegebenen Liste numbers_list.
    • Innerhalb der Schleife prüfen wir mit einer if-Bedingung, ob die aktuelle Zahl größer als 0 ist. Wenn ja, addieren wir sie zur total Summe.
    • Am Ende der Schleife geben wir die Gesamtsumme zurück.

    b)

    2. Ergänze das Programm um eine Funktion find_first_negative, die die Position des ersten negativen Wertes in der Liste zurückgibt. Sollte keine negative Zahl vorhanden sein, soll die Funktion den Wert -1 zurückgeben. Verwende eine while-Schleife in deiner Implementierung.

    Lösung:

    Um die Aufgabe zu lösen, ergänzen wir das Programm um eine Funktion find_first_negative, die die Position des ersten negativen Wertes in der Liste zurückgibt. Wenn keine negative Zahl vorhanden ist, soll die Funktion den Wert -1 zurückgeben. Hier ist der Code:

    def sum_positive_numbers(numbers_list):    # Initialisiere die Summe    total = 0        # Schleife durch jede Zahl in der Liste    for number in numbers_list:        # Überprüfe, ob die Zahl positiv ist        if number > 0:            # Addiere die positive Zahl zur Summe            total += number        # Rückgabe der Gesamtsumme    return totaldef find_first_negative(numbers_list):    # Initialisiere den Index    index = 0        # Schleife durch die Liste mit while-Schleife    while index < len(numbers_list):        # Überprüfe, ob die aktuelle Zahl negativ ist        if numbers_list[index] < 0:            # Rückgabe des Index der ersten negativen Zahl            return index        # Erhöhe den Index        index += 1        # Rückgabe von -1, wenn keine negative Zahl gefunden wurde    return -1# Beispiel-Liste von Zahlennumbers = [1, -4, 7, 12, -3, 5]# Aufruf der Funktion und Ausgabe des Ergebnissesprint(sum_positive_numbers(numbers_list=numbers))print(find_first_negative(numbers_list=numbers))

    In diesem Beispiel:

    • Die Funktion sum_positive_numbers bleibt unverändert und summiert weiterhin alle positiven Zahlen in der Liste.
    • Die Funktion find_first_negative verwendet eine while-Schleife, um durch die Liste zu iterieren. Sie prüft bei jedem Schritt, ob das aktuelle Element negativ ist. Wenn eine negative Zahl gefunden wird, gibt sie deren Index zurück. Ist keine negative Zahl vorhanden, gibt sie -1 zurück.

    c)

    3. Implementiere eine Funktion skip_multiples_of_three, die alle Elemente durchläuft, aber alle Vielfachen von 3 überspringt und die restlichen Zahlen in einer neuen Liste zurückgibt. Nutze dabei die Kontrollstruktur continue.

    Lösung:

    Um die Aufgabe zu lösen, implementieren wir eine Funktion skip_multiples_of_three, die alle Elemente der Liste durchläuft, aber alle Vielfachen von 3 überspringt und die restlichen Zahlen in einer neuen Liste zurückgibt. Hier ist der Code:

    def sum_positive_numbers(numbers_list):    # Initialisiere die Summe    total = 0        # Schleife durch jede Zahl in der Liste    for number in numbers_list:        # Überprüfe, ob die Zahl positiv ist        if number > 0:            # Addiere die positive Zahl zur Summe            total += number        # Rückgabe der Gesamtsumme    return totaldef find_first_negative(numbers_list):    # Initialisiere den Index    index = 0        # Schleife durch die Liste mit while-Schleife    while index < len(numbers_list):        # Überprüfe, ob die aktuelle Zahl negativ ist        if numbers_list[index] < 0:            # Rückgabe des Index der ersten negativen Zahl            return index        # Erhöhe den Index        index += 1        # Rückgabe von -1, wenn keine negative Zahl gefunden wurde    return -1def skip_multiples_of_three(numbers_list):    # Initialisiere die neue Liste    result = []        # Schleife durch jede Zahl in der Liste    for number in numbers_list:        # Überprüfe, ob die Zahl ein Vielfaches von 3 ist        if number % 3 == 0:            # Überspringe dieses Element            continue        # Füge das Element zur neuen Liste hinzu        result.append(number)        # Rückgabe der neuen Liste    return result# Beispiel-Liste von Zahlennumbers = [1, -4, 7, 12, -3, 5, 9]# Aufruf der Funktionen und Ausgabe der Ergebnisseprint(sum_positive_numbers(numbers_list=numbers))print(find_first_negative(numbers_list=numbers))print(skip_multiples_of_three(numbers_list=numbers))

    In diesem Beispiel:

    • Die Funktion sum_positive_numbers summiert alle positiven Zahlen in der Liste.
    • Die Funktion find_first_negative findet den Index der ersten negativen Zahl in der Liste oder gibt -1 zurück, wenn keine negative Zahl vorhanden ist.
    • Die neue Funktion skip_multiples_of_three verwendet eine for-Schleife, um durch die Liste zu iterieren. Mit der Kontrollstruktur continue überspringt sie alle Elemente, die Vielfache von 3 sind, und fügt die restlichen Zahlen einer neuen Liste result hinzu. Schließlich gibt die Funktion diese neue Liste zurück.

    d)

    4. Erweitere das Programm um eine Funktion max_element_until_zero, die das größte Element in der Liste von Zahlen bis zum ersten Auftreten von Null zurückgibt. Wenn kein Null vorhanden ist, soll die Funktion das größte Element der Liste zurückgeben. Verwende mindestens eine Kontrollstruktur break in deiner Implementierung.

    Lösung:

    Um die Aufgabe zu lösen, ergänzen wir das Programm um eine Funktion max_element_until_zero, die das größte Element in der Liste bis zum ersten Auftreten von Null zurückgibt. Wenn keine Null vorhanden ist, soll die Funktion das größte Element der Liste zurückgeben. Hier ist der Code:

    def sum_positive_numbers(numbers_list):    # Initialisiere die Summe    total = 0        # Schleife durch jede Zahl in der Liste    for number in numbers_list:        # Überprüfe, ob die Zahl positiv ist        if number > 0:            # Addiere die positive Zahl zur Summe            total += number        # Rückgabe der Gesamtsumme    return totaldef find_first_negative(numbers_list):    # Initialisiere den Index    index = 0        # Schleife durch die Liste mit while-Schleife    while index < len(numbers_list):        # Überprüfe, ob die aktuelle Zahl negativ ist        if numbers_list[index] < 0:            # Rückgabe des Index der ersten negativen Zahl            return index        # Erhöhe den Index        index += 1        # Rückgabe von -1, wenn keine negative Zahl gefunden wurde    return -1def skip_multiples_of_three(numbers_list):    # Initialisiere die neue Liste    result = []        # Schleife durch jede Zahl in der Liste    for number in numbers_list:        # Überprüfe, ob die Zahl ein Vielfaches von 3 ist        if number % 3 == 0:            # Überspringe dieses Element            continue        # Füge das Element zur neuen Liste hinzu        result.append(number)        # Rückgabe der neuen Liste    return resultdef max_element_until_zero(numbers_list):    # Initialisiere das maximale Element    max_element = float('-inf')        # Schleife durch jede Zahl in der Liste    for number in numbers_list:        # Überprüfe, ob die aktuelle Zahl Null ist        if number == 0:            # Breche die Schleife bei Null            break        # Aktuallisiere max_element falls number größer ist        if number > max_element:            max_element = number        # Rückgabe des maximalen Elements    return max_element# Beispiel-Liste von Zahlennumbers = [1, -4, 7, 12, 0, -3, 5, 9]# Aufruf der Funktionen und Ausgabe der Ergebnisseprint(sum_positive_numbers(numbers_list=numbers))print(find_first_negative(numbers_list=numbers))print(skip_multiples_of_three(numbers_list=numbers))print(max_element_until_zero(numbers_list=numbers))

    In diesem Beispiel:

    • Die Funktion sum_positive_numbers summiert alle positiven Zahlen in der Liste.
    • Die Funktion find_first_negative findet den Index der ersten negativen Zahl in der Liste oder gibt -1 zurück, wenn keine negative Zahl vorhanden ist.
    • Die Funktion skip_multiples_of_three überspringt alle Vielfachen von 3 und gibt die restlichen Zahlen in einer neuen Liste zurück.
    • Die neue Funktion max_element_until_zero verwendet eine for-Schleife, um durch die Liste zu iterieren. Bei jedem Element wird geprüft, ob es Null ist. Wenn ja, wird die Schleife mit break beendet. Ansonsten wird das aktuelle Element mit dem momentan größten Element verglichen und ggf. aktualisiert.

    Aufgabe 4)

    Du hast zwei verschiedene Programmiersprachen gelernt: C (prozedural) und Java (objektorientiert). Du sollst nun ein einfaches Bankkontosystem einrichten, um die Unterschiede zwischen diesen Paradigmen besser zu verstehen. Ein Bankkonto hat eine Kontonummer, ein Guthaben und Methoden zum Einzahlen und Abheben von Geld.In C sollen diese Funktionen global definiert werden. In Java sollst Du eine Klasse 'Bankkonto' definieren.

    a)

    Schreibe in C eine Struktur 'Bankkonto', die die Kontonummer und das Guthaben speichert. Implementiere die Funktionen 'einzahlen' und 'abheben', die den entsprechenden Betrag zum Guthaben des Kontos hinzufügen bzw. davon abziehen. Achte darauf, dass das Guthaben nicht negativ werden kann.

    Lösung:

    Hier ist eine Umsetzung der geforderten Aufgabenstellung in C:

    • Zuerst definieren wir eine Struktur Bankkonto, die die Kontonummer und das Guthaben speichert.
    • Danach implementieren wir die Funktionen einzahlen und abheben, um Geld auf das Konto zu einzuzahlen und davon abzuheben. Wir sorgen dafür, dass das Guthaben nicht negativ werden kann.
    #include <stdio.h>#include <stdbool.h>typedef struct {    int kontonummer;    float guthaben;} Bankkonto;void einzahlen(Bankkonto *konto, float betrag) {    if (betrag > 0) {        konto->guthaben += betrag;    } else {        printf("Ungueltiger Betrag.");    }}bool abheben(Bankkonto *konto, float betrag) {    if (betrag > 0 && konto->guthaben >= betrag) {        konto->guthaben -= betrag;        return true;    } else {        printf("Abhebung fehlgeschlagen. Ungueltiger Betrag oder unzureichendes Guthaben.");        return false;    }}int main() {    Bankkonto konto;    konto.kontonummer = 12345;    konto.guthaben = 1000.0;    printf("Kontostand: %.2f", konto.guthaben);    einzahlen(&konto, 200.0);    printf("Nach Einzahlung von 200, Kontostand: %.2f", konto.guthaben);    abheben(&konto, 500.0);    printf("Nach Abhebung von 500, Kontostand: %.2f", konto.guthaben);    abheben(&konto, 800.0);    printf("Nach Abhebung von 800, Kontostand: %.2f", konto.guthaben);    return 0;}

    In dieser Implementierung speichern wir die Kontonummer und das Guthaben in einer Bankkonto Struktur.

    Die Funktion einzahlen:

    • Fügt den eingegebenen Betrag zum Guthaben des Kontos hinzu.
    • Überprüft, ob der Betrag positiv ist.

    Die Funktion abheben:

    • Zieht den eingegebenen Betrag vom Guthaben ab, falls dieser positiv ist und das Guthaben ausreicht.
    • Gibt eine entsprechende Fehlermeldung aus, falls die Bedingungen nicht erfüllt sind.

    Beachte, dass bool aus stdbool.h verwendet wird, um true und false Werte zu verwenden.

    b)

    Implementiere in Java eine Klasse 'Bankkonto' mit den Attributen 'kontonummer' und 'guthaben'. Implementiere die Methoden 'einzahlen' und 'abheben', die den entsprechenden Betrag zum oder vom Guthaben addieren bzw. subtrahieren. Achte darauf, dass das Guthaben nicht negativ wird.

    Lösung:

    Hier ist eine Umsetzung der geforderten Aufgabenstellung in Java:

    • Wir definieren eine Klasse Bankkonto mit den Attributen kontonummer und guthaben.
    • Wir implementieren die Methoden einzahlen und abheben, um Geld auf das Konto einzuzahlen und davon abzuheben. Wir sorgen dafür, dass das Guthaben nicht negativ werden kann.
    public class Bankkonto {    private int kontonummer;    private double guthaben;    public Bankkonto(int kontonummer, double startguthaben) {        this.kontonummer = kontonummer;        this.guthaben = startguthaben;    }    public void einzahlen(double betrag) {        if (betrag > 0) {            guthaben += betrag;            System.out.println("Einzahlung erfolgreich. Neuer Kontostand: " + guthaben);        } else {            System.out.println("Ungueltiger Betrag.");        }    }    public void abheben(double betrag) {        if (betrag > 0 && guthaben >= betrag) {            guthaben -= betrag;            System.out.println("Abhebung erfolgreich. Neuer Kontostand: " + guthaben);        } else {            System.out.println("Abhebung fehlgeschlagen. Ungueltiger Betrag oder unzureichendes Guthaben.");        }    }    public int getKontonummer() {        return kontonummer;    }    public double getGuthaben() {        return guthaben;    }    public static void main(String[] args) {        Bankkonto konto = new Bankkonto(12345, 1000.0);        System.out.println("Kontonummer: " + konto.getKontonummer());        System.out.println("Kontostand: " + konto.getGuthaben());        konto.einzahlen(200.0);        konto.abheben(500.0);        konto.abheben(800.0);    }}

    In dieser Implementierung speichern wir die Kontonummer und das Guthaben als Attribute der Bankkonto Klasse.

    Die Methode einzahlen:

    • Fügt den eingegebenen Betrag zum Guthaben des Kontos hinzu.
    • Überprüft, ob der Betrag positiv ist.

    Die Methode abheben:

    • Zieht den eingegebenen Betrag vom Guthaben ab, falls dieser positiv ist und das Guthaben ausreicht.
    • Gibt eine entsprechende Fehlermeldung aus, falls die Bedingungen nicht erfüllt sind.

    Der main Methode wird verwendet, um die Bankkonto Klasse zu testen.

    c)

    Erläutere die Hauptunterschiede zwischen den beiden Programmierstilen, die Du bei der Implementierung der Bankkontosysteme in C und Java erlebt hast. Gehe dabei insbesondere auf folgende Punkte ein:

    • Datenkapselung
    • Modularität
    • Verwendung von Konstrukten der jeweiligen Sprache (z.B. Strukturen in C vs. Klassen in Java)

    Lösung:

    Hier sind die Hauptunterschiede zwischen den beiden Programmierstilen, die Du bei der Implementierung der Bankkontosysteme in C und Java erlebt hast:

    • Datenkapselung:
    • In C: Daten und Funktionen sind getrennt. Wir definieren eine Struktur (struct) zur Speicherung der Daten und erstellen globale Funktionen, um Operationen auf diesen Daten auszuführen. Es gibt keine Möglichkeit, Daten innerhalb der Struktur zu kapseln oder zu schützen.
    • In Java: Daten und Methoden sind innerhalb einer Klasse gekapselt. Das bedeutet, dass die Daten nur über die Methoden der Klasse verändert werden können. Attributen können Zugriffsmodifikatoren (wie private, public) zugewiesen werden, um den Zugriff zu steuern und die Datenkapselung durchzusetzen.
    • Modularität:
    • In C: Das Programm ist weniger modular, da wir globale Funktionen verwenden, die auf globale oder externe Variablen zugreifen. Jedes Modul oder jede Funktion kann auf die Struktur zugreifen, was zu einer festeren Kopplung führen kann.
    • In Java: Das Programm ist modularer, da wir Klassen verwenden. Jede Klasse hat ihr eigenes Set von Daten und Methoden, was die Trennung von Verantwortlichkeiten erleichtert. Funktionen sind Methoden innerhalb von Klassen und haben direkten Zugriff auf die Daten dieser Klasse.
    • Verwendung von Konstrukten der jeweiligen Sprache:
    • In C: Wir verwenden Strukturen (structs) zur Speicherung der Daten. Funktionen sind unabhängig von den Strukturen und nehmen die Struktur als Parameter, um auf die Daten zuzugreifen oder diese zu manipulieren. Es gibt keine Konstruktoren in C, um Objekte zu erzeugen oder zu initialisieren.
    • In Java: Wir verwenden Klassen, die sowohl Daten (Attribute) als auch Methoden (Funktionalitäten) enthalten. Konstruktoren werden verwendet, um Objekte zu erstellen und zu initialisieren. Darüber hinaus unterstützt Java Konzepte wie Vererbung und Polymorphismus, die in C nicht vorhanden sind.

    Zusammenfassend lässt sich sagen, dass C als prozedurale Programmiersprache einen klaren und direkten Ansatz für das Programmieren bietet, jedoch weniger Unterstützung für Datenkapselung und Modularität bietet. Java als objektorientierte Programmiersprache bietet starke Datenkapselung, bessere Modularität und eine umfangreichere Nutzung von Klassen zur Strukturierung des Codes.

    d)

    Implementiere in Java eine abgeleitete Klasse 'Sparkonto', die von 'Bankkonto' erbt und eine zusätzliche Methode 'verzinsen(double zinssatz)' besitzt. Diese Methode soll das vorhandene Guthaben um einen bestimmten Zinssatz erhöhen, der als Parameter übergeben wird. Berechne das neue Guthaben nach dem Zinssatz gemäß der Formel newline

    Lösung:

    Hier ist eine Umsetzung der geforderten Aufgabenstellung in Java:

    • Zuerst definieren wir die Basisklasse Bankkonto wie zuvor.
    • Dann erstellen wir eine abgeleitete Klasse Sparkonto, die von Bankkonto erbt.
    • Schließlich fügen wir eine Methode verzinsen hinzu, die das Guthaben anhand eines Zinssatzes erhöht.
    public class Bankkonto {    private int kontonummer;    private double guthaben;    public Bankkonto(int kontonummer, double startguthaben) {        this.kontonummer = kontonummer;        this.guthaben = startguthaben;    }    public void einzahlen(double betrag) {        if (betrag > 0) {            guthaben += betrag;            System.out.println("Einzahlung erfolgreich. Neuer Kontostand: " + guthaben);        } else {            System.out.println("Ungueltiger Betrag.");        }    }    public void abheben(double betrag) {        if (betrag > 0 && guthaben >= betrag) {            guthaben -= betrag;            System.out.println("Abhebung erfolgreich. Neuer Kontostand: " + guthaben);        } else {            System.out.println("Abhebung fehlgeschlagen. Ungueltiger Betrag oder unzureichendes Guthaben.");        }    }    public int getKontonummer() {        return kontonummer;    }    public double getGuthaben() {        return guthaben;    }}public class Sparkonto extends Bankkonto {    public Sparkonto(int kontonummer, double startguthaben) {        super(kontonummer, startguthaben);    }    public void verzinsen(double zinssatz) {        if (zinssatz > 0) {            double zinsen = getGuthaben() * (zinssatz / 100);            einzahlen(zinsen);            System.out.println("Zinsen erfolgreich berechnet. Neuer Kontostand: " + getGuthaben());        } else {            System.out.println("Ungueltiger Zinssatz.");        }    }    public static void main(String[] args) {        Sparkonto sparkonto = new Sparkonto(54321, 2000.0);        System.out.println("Kontonummer: " + sparkonto.getKontonummer());        System.out.println("Kontostand: " + sparkonto.getGuthaben());        sparkonto.einzahlen(500.0);        sparkonto.abheben(300.0);        sparkonto.verzinsen(5);    }}}

    In dieser Implementierung wird die Klassenstruktur wie folgt erweitert:

    • Die Klasse Bankkonto bleibt wie zuvor definiert.
    • Die Klasse Sparkonto erbt von Bankkonto und erhält dadurch alle Attribute und Methoden der Basisklasse.
    • Die Methode verzinsen berechnet die Zinsen basierend auf einem Zinssatz und erhöht das Guthaben um diesen Betrag. Die Berechnung erfolgt gemäß der Formel:
    • ewline Darstellung der Formel:
    • Formel: ewline ewline ewline ewline
    ewline  
    Das bestehende Guthaben wird mit dem zinssatz multipliziert, um die Zinsen zu berechnen.
  • Dann wird der berechnete Betrag dem bestehenden Guthaben hinzugefügt.
  • Der main Methode in Sparkonto wird verwendet, um die erweiterten Funktionen zu testen.

    Sign Up

    Melde dich kostenlos an, um Zugriff auf das vollständige Dokument zu erhalten

    Mit unserer kostenlosen Lernplattform erhältst du Zugang zu Millionen von Dokumenten, Karteikarten und Unterlagen.

    Kostenloses Konto erstellen

    Du hast bereits ein Konto? Anmelden