Lerninhalte finden
Features
Entdecke
© StudySmarter 2024, all rights reserved.
Ein Unternehmen möchte eine Basis für ein Automatisierungsprojekt in der IT-Infrastruktur mit der Programmiersprache Python entwickeln. Das Projekt umfasst das Einlesen von CSV-Daten, die Analyse dieser Daten sowie das Generieren eines Berichts. Die Daten enthalten Informationen zu Servern in einem Rechenzentrum, wie z.B. „Host-Name“, „IP-Adresse“, „CPU-Auslastung“ und „Speicherverbrauch“.Schreibe ein Python-Skript, das folgende Anforderungen erfüllt:
Erstelle ein Python-Programm, das die CSV-Datei einliest und in ein DataFrame (verwende dazu die Bibliothek \texttt{Pandas}) umwandelt. Das DataFrame soll die Struktur der CSV-Datei vollständig widerspiegeln, d.h., jede Spalte der CSV-Datei wird zu einer Spalte des DataFrames. Überprüfe, ob die CSV-Datei korrekt eingelesen wurde, indem Du die ersten fünf Zeilen des DataFrames mithilfe der Methode \texttt{head()} ausgibst.
import pandas as pddef read_csv_file(file_path): # Lies die CSV-Datei ein df = pd.read_csv(file_path) # Gib die ersten fünf Zeilen aus print(df.head()) return df# Beispielaufruffile_path = 'server_data.csv'data_frame = read_csv_file(file_path)
Lösung:
Um ein Python-Programm zu schreiben, das eine CSV-Datei einliest und in ein DataFrame umwandelt, kannst Du die Pandas
-Bibliothek verwenden. Das folgende Programm liest die CSV-Datei ein und gibt die ersten fünf Zeilen aus, um zu überprüfen, ob die Datei korrekt eingelesen wurde. Folge diesen Schritten:
Pandas
-Bibliothek.read_csv_file(file_path)
, die eine CSV-Datei einliest und in ein DataFrame umwandelt.pd.read_csv(file_path)
ein.df.head()
aus.Hier ist das vollständige Skript:
import pandas as pddef read_csv_file(file_path): # Lies die CSV-Datei ein df = pd.read_csv(file_path) # Gib die ersten fünf Zeilen aus print(df.head()) return df# Beispielaufruffile_path = 'server_data.csv'data_frame = read_csv_file(file_path)
Erweitere das Skript um eine Analyse, die die durchschnittliche CPU-Auslastung und den durchschnittlichen Speicherverbrauch aller Server ermittelt. Verwende dabei die Methoden \texttt{mean()} der Pandas-Bibliothek, um die Berechnungen durchzuführen. Gib anschließend die berechneten Mittelwerte auf der Konsole aus.
import pandas as pddef read_csv_file(file_path): df = pd.read_csv(file_path) print(df.head()) return dfdef analyze_data(df): # Berechne die durchschnittliche CPU-Auslastung avg_cpu_usage = df['CPU-Auslastung'].mean() # Berechne den durchschnittlichen Speicherverbrauch avg_memory_usage = df['Speicherverbrauch'].mean() # Gib die Ergebnisse aus print('Durchschnittliche CPU-Auslastung: ', avg_cpu_usage) print('Durchschnittlicher Speicherverbrauch: ', avg_memory_usage)# Beispielaufruffile_path = 'server_data.csv'data_frame = read_csv_file(file_path)analyze_data(data_frame)
Lösung:
Um das Python-Skript zu erweitern, sodass es die durchschnittliche CPU-Auslastung und den durchschnittlichen Speicherverbrauch aller Server berechnet, kannst Du die Methode mean()
der Pandas
-Bibliothek verwenden. Folge diesen Schritten:
analyze_data(df)
, die die Analyse durchführt.mean()
.Hier ist das vollständige Skript:
import pandas as pddef read_csv_file(file_path): df = pd.read_csv(file_path) print(df.head()) return dfdef analyze_data(df): # Berechne die durchschnittliche CPU-Auslastung avg_cpu_usage = df['CPU-Auslastung'].mean() # Berechne den durchschnittlichen Speicherverbrauch avg_memory_usage = df['Speicherverbrauch'].mean() # Gib die Ergebnisse aus print('Durchschnittliche CPU-Auslastung: ', avg_cpu_usage) print('Durchschnittlicher Speicherverbrauch: ', avg_memory_usage)# Beispielaufruffile_path = 'server_data.csv'data_frame = read_csv_file(file_path)analyze_data(data_frame)
Mit diesem erweiterten Skript kannst Du nun die CSV-Datei einlesen und eine grundlegende Analyse der Serverdaten durchführen. Die berechneten Mittelwerte für die CPU-Auslastung und den Speicherverbrauch werden auf der Konsole ausgegeben.
In einem Objektorientierten System für eine Bibliothek werden Bücher und Zeitschriften verwaltet. Jedes Buch und jede Zeitschrift hat gemeinsame Eigenschaften wie Titel, Autor und Erscheinungsjahr. Zusätzlich haben Bücher Attribute wie ISBN und Seitenzahl, während Zeitschriften Attribute wie ISSN und Ausgabe haben. Implementiere ein Java-Programm, um diese Anforderungen zu erfüllen.
Definiere eine abstrakte Klasse \textcode{Publication}, welche die gemeinsamen Attribute \textcode{title}, \textcode{author} und \textcode{yearPublished} enthält. Schreibe auch die notwendigen Getter- und Setter-Methoden sowie einen abstrakten Methodenkopf für eine Methode \textcode{printDetails()}, die später in den Unterklassen überschrieben wird.
Lösung:
Um die Anforderungen zu erfüllen, kannst Du eine abstrakte Klasse Publication in Java definieren. Diese Klasse enthält die gemeinsamen Attribute title, author, und yearPublished sowie die notwendigen Getter- und Setter-Methoden. Außerdem wird ein abstrakter Methodenkopf für die Methode printDetails() deklariert. Hier ist ein Beispiel, wie Du dies in Java umsetzen kannst:
public abstract class Publication { private String title; private String author; private int yearPublished; // Getter-Methoden public String getTitle() { return title; } public String getAuthor() { return author; } public int getYearPublished() { return yearPublished; } // Setter-Methoden public void setTitle(String title) { this.title = title; } public void setAuthor(String author) { this.author = author; } public void setYearPublished(int yearPublished) { this.yearPublished = yearPublished; } // Abstrakte Methode printDetails public abstract void printDetails(); }
Implementiere die Klasse \textcode{Book}, welche von der abstrakten Klasse \textcode{Publication} erbt. Zusatzlich zu den geerbten Attributen, füge die spezifischen Attribute \textcode{isbn} und \textcode{numPages} hinzu. Implementiere den Konstruktor und die Methode \textcode{printDetails()}, sodass sie alle Informationen des Buches ausgibt.
Lösung:
Um die Klasse Book zu implementieren, welche von der abstrakten Klasse Publication erbt, müssen wir die notwendigen spezifischen Attribute isbn und numPages hinzufügen. Außerdem sollten wir den Konstruktor und die Methode printDetails() implementieren, sodass sie alle Informationen des Buches ausgibt. Hier ist ein Beispiel, wie dies in Java umsetzen kannst:
public class Book extends Publication { private String isbn; private int numPages; // Konstruktor public Book(String title, String author, int yearPublished, String isbn, int numPages) { setTitle(title); setAuthor(author); setYearPublished(yearPublished); this.isbn = isbn; this.numPages = numPages; } // Getter-Methoden public String getIsbn() { return isbn; } public int getNumPages() { return numPages; } // Setter-Methoden public void setIsbn(String isbn) { this.isbn = isbn; } public void setNumPages(int numPages) { this.numPages = numPages; } // Implementierung der abstrakten Methode printDetails @Override public void printDetails() { System.out.println("Title: " + getTitle()); System.out.println("Author: " + getAuthor()); System.out.println("Year Published: " + getYearPublished()); System.out.println("ISBN: " + isbn); System.out.println("Number of Pages: " + numPages); } }
Implementiere die Klasse \textcode{Magazine}, welche ebenfalls von der abstrakten Klasse \textcode{Publication} erbt. Zusatzlich zu den geerbten Attributen, füge die spezifischen Attribute \textcode{issn} und \textcode{issueNumber} hinzu. Implementiere den Konstruktor und die Methode \textcode{printDetails()}, sodass sie alle Informationen der Zeitschrift ausgibt.
Lösung:
Um die Klasse Magazine zu implementieren, welche von der abstrakten Klasse Publication erbt, müssen wir die notwendigen spezifischen Attribute issn und issueNumber hinzufügen. Außerdem sollten wir den Konstruktor und die Methode printDetails() implementieren, sodass sie alle Informationen der Zeitschrift ausgibt. Hier ist ein Beispiel, wie Du dies in Java umsetzen kannst:
public class Magazine extends Publication { private String issn; private int issueNumber; // Konstruktor public Magazine(String title, String author, int yearPublished, String issn, int issueNumber) { setTitle(title); setAuthor(author); setYearPublished(yearPublished); this.issn = issn; this.issueNumber = issueNumber; } // Getter-Methoden public String getIssn() { return issn; } public int getIssueNumber() { return issueNumber; } // Setter-Methoden public void setIssn(String issn) { this.issn = issn; } public void setIssueNumber(int issueNumber) { this.issueNumber = issueNumber; } // Implementierung der abstrakten Methode printDetails @Override public void printDetails() { System.out.println("Title: " + getTitle()); System.out.println("Author: " + getAuthor()); System.out.println("Year Published: " + getYearPublished()); System.out.println("ISSN: " + issn); System.out.println("Issue Number: " + issueNumber); } }
Schreibe eine Main-Klasse, in der du ein Buch und eine Zeitschrift instanziierst und die Methode \textcode{printDetails()} für jedes Objekt aufrufst, um die erwartete Ausgabe zu überprüfen. Zeige dabei auch wie du in Java Fehler handhabst, indem du z.B. überprüfst, ob Felder wie \textcode{title} nicht leer sind und im Fehlerfall eine Exception wirfst.
Lösung:
Um die Anforderungen zu erfüllen, kannst Du eine Main-Klasse schreiben, die ein Buch und eine Zeitschrift instanziiert und die Methode printDetails() für jedes Objekt aufruft. Dabei zeige ich auch, wie Du in Java Fehler handhabst, indem Du überprüfst, ob Felder wie title nicht leer sind und im Fehlerfall eine Exception wirfst. Hier ist ein Beispiel:
public class Main { public static void main(String[] args) { try { // Buch instanziieren Book book = new Book("Effective Java", "Joshua Bloch", 2008, "978-0134685991", 416); // Zeitschrift instanziieren Magazine magazine = new Magazine("National Geographic", "Various Authors", 2021, "0027-9358", 3); // Details des Buches und der Zeitschrift ausgeben book.printDetails(); magazine.printDetails(); } catch (Exception e) { System.out.println("Fehler: " + e.getMessage()); } } // Fehlerüberprüfungen in den Settermethoden public void setTitle(String title) { if (title == null || title.isEmpty()) { throw new IllegalArgumentException("Titel darf nicht leer sein"); } this.title = title; } public void setAuthor(String author) { if (author == null || author.isEmpty()) { throw new IllegalArgumentException("Autor darf nicht leer sein"); } this.author = author; } public void setYearPublished(int yearPublished) { if (yearPublished < 0) { throw new IllegalArgumentException("Erscheinungsjahr darf nicht negativ sein"); } this.yearPublished = yearPublished; } }
Schreibe ein C-Programm, das eine einfache Datenbank für Studenteninformationen verwaltet. Die Datenbank soll Studentendaten wie Matrikelnummer, Name und Studienfach speichern und grundlegende Funktionen wie Hinzufügen, Suchen und Löschen eines Studenten ermöglichen. Implementiere die Datenbank mithilfe von Arrays und Zeigern. Deine Lösung soll aus mehreren Dateien bestehen und Speicher dynamisch verwalten. Denke daran, zur Fehlerbehandlung entsprechende Maßnahmen zu implementieren und dein Programm auf Speicherlecks zu prüfen.
Teilaufgabe 1: Erstelle die Header-Dateien und Quellcodes für Dein Programm. Definiere in der Header-Datei eine Struktur struct Student
, die die Matrikelnummer, den Namen (C-String) und das Studienfach (C-String) enthält. Schreibe in der Quellcode-Datei die Funktionen zum Hinzufügen eines neuen Studenten und zum Anzeigen aller gespeicherten Studenten. Achte darauf, die Speicheralokation korrekt durchzuführen.
Lösung:
Um diese Teilaufgabe zu lösen, folgen wir den Anweisungen Schritt für Schritt:
struct Student
.Hier ist der Code für die Header-Datei student.h
:
'#ifndef STUDENT_H#define STUDENT_H#include <stdlib.h>#define NAME_LEN 100#define SUBJECT_LEN 100typedef struct { int matrikelnummer; char name[NAME_LEN]; char studienfach[SUBJECT_LEN];} Student;Student* student_erstelle(int matrikelnummer, const char* name, const char* studienfach);void student_zeige_alle(Student** studenten, int anzahl);void student_loesche(Student* student);#endif'
Dieser Header enthält:
struct Student
, welches Matrikelnummer, Name und Studienfach als Attribute enthält.student_erstelle
, student_zeige_alle
und student_loesche
.Hier ist der Code für die Quellcode-Datei student.c
:
'#include "student.h"#include <stdio.h>#include <string.h>Student* student_erstelle(int matrikelnummer, const char* name, const char* studienfach) { Student* s = (Student*)malloc(sizeof(Student)); if (s == NULL) { fprintf(stderr, "Speicher konnte nicht zugewiesen werden"); exit(EXIT_FAILURE); } s->matrikelnummer = matrikelnummer; strncpy(s->name, name, NAME_LEN-1); s->name[NAME_LEN-1] = '\0'; strncpy(s->studienfach, studienfach, SUBJECT_LEN-1); s->studienfach[SUBJECT_LEN-1] = '\0'; return s;}void student_zeige_alle(Student** studenten, int anzahl) { for (int i = 0; i < anzahl; i++) { Student* s = studenten[i]; printf("Matrikelnummer: %d, Name: %s, Studienfach: %s", s->matrikelnummer, s->name, s->studienfach); }}void student_loesche(Student* s) { free(s);}'
Diese Quellcode-Datei enthält:
student_erstelle
, die einen neuen Studenten erstellt und den Speicher dynamisch alloziert.student_zeige_alle
, die alle gespeicherten Studenten anzeigt.student_loesche
, die den Speicher eines Studenten freigibt.Vergiss nicht, alle Funktionen aufzurufen und zu testen, um sicherzustellen, dass sie wie erwartet funktionieren und keine Speicherlecks auftreten.
Teilaufgabe 2: Implementiere eine Funktion Student* find_student(int mat_nr)
, die einen Zeiger auf den Studenten mit der angegebenen Matrikelnummer zurückgibt. Wenn der Student nicht gefunden wird, soll die Funktion NULL
zurückgeben. Teste die Funktion, indem Du mehrere Studenten hinzufügst und dann nach deren Matrikelnummer suchst.
Lösung:
Um diese Teilaufgabe zu lösen, implementieren wir die Funktion find_student
in der Quellcode-Datei student.c
. Dazu benötigen wir auch eine Anpassung der Header-Datei student.h
, um die Funktion zu deklarieren. Auch sollten wir sicherstellen, dass wir eine Testfunktion haben, um die Funktionsweise zu überprüfen.
Hier ist der erweiterte Code für die Header-Datei student.h
:
'#ifndef STUDENT_H#define STUDENT_H#include <stdlib.h>#define NAME_LEN 100#define SUBJECT_LEN 100typedef struct { int matrikelnummer; char name[NAME_LEN]; char studienfach[SUBJECT_LEN];} Student;Student* student_erstelle(int matrikelnummer, const char* name, const char* studienfach);void student_zeige_alle(Student** studenten, int anzahl);void student_loesche(Student* student);Student* find_student(Student** studenten, int anzahl, int mat_nr);#endif'
Hier ist der erweiterte Code für die Quellcode-Datei student.c
:
'#include "student.h"#include <stdio.h>#include <string.h>Student* student_erstelle(int matrikelnummer, const char* name, const char* studienfach) { Student* s = (Student*)malloc(sizeof(Student)); if (s == NULL) { fprintf(stderr, "Speicher konnte nicht zugewiesen werden"); exit(EXIT_FAILURE); } s->matrikelnummer = matrikelnummer; strncpy(s->name, name, NAME_LEN-1); s->name[NAME_LEN-1] = '\0'; strncpy(s->studienfach, studienfach, SUBJECT_LEN-1); s->studienfach[SUBJECT_LEN-1] = '\0'; return s;}void student_zeige_alle(Student** studenten, int anzahl) { for (int i = 0; i < anzahl; i++) { Student* s = studenten[i]; printf("Matrikelnummer: %d, Name: %s, Studienfach: %s", s->matrikelnummer, s->name, s->studienfach); }}void student_loesche(Student* s) { free(s);}Student* find_student(Student** studenten, int anzahl, int mat_nr) { for (int i = 0; i < anzahl; i++) { if (studenten[i]->matrikelnummer == mat_nr) { return studenten[i]; } } return NULL;}'
Nun fügen wir eine Testfunktion in die Quellcode-Datei main.c
ein, um die Funktion zu testen:
'#include "student.h"#include <stdio.h>#include <stdlib.h>int main() { const int max_students = 3; Student* studenten[max_students]; studenten[0] = student_erstelle(1, "Alice", "Informatik"); studenten[1] = student_erstelle(2, "Bob", "Mathematik"); studenten[2] = student_erstelle(3, "Carlos", "Physik"); student_zeige_alle(studenten, max_students); int such_matrikelnummer = 2; Student* gefunden = find_student(studenten, max_students, such_matrikelnummer); if (gefunden) { printf("Gefundener Student: Matrikelnummer %d, Name: %s, Studienfach: %s", gefunden->matrikelnummer, gefunden->name, gefunden->studienfach); } else { printf("Student mit Matrikelnummer %d nicht gefunden.", such_matrikelnummer); } for (int i = 0; i < max_students; i++) { student_loesche(studenten[i]); } return 0;}'
Dieser Testcode:
Damit ist die Teilaufgabe erfüllt und die Funktion find_student
korrekt implementiert und getestet.
Teilaufgabe 3: Implementiere eine Funktion void delete_student(int mat_nr)
, die den Studenten mit der angegebenen Matrikelnummer aus der Datenbank löscht. Stelle sicher, dass der freigegebene Speicher korrekt verwaltet wird. Ergänze Dein Programm mit einem Beispiel, das zeigt, wie ein Student erfolgreich gelöscht wird.
Lösung:
Um diese Teilaufgabe zu lösen, implementieren wir die Funktion delete_student
in der Quellcode-Datei student.c
. Dazu benötigen wir auch eine Anpassung der Header-Datei student.h
, um die Funktion zu deklarieren. Ebenso fügen wir den entsprechenden Code in die Testfunktion ein.
Hier ist der erweiterte Code für die Header-Datei student.h
:
'#ifndef STUDENT_H#define STUDENT_H#include <stdlib.h>#define NAME_LEN 100#define SUBJECT_LEN 100typedef struct { int matrikelnummer; char name[NAME_LEN]; char studienfach[SUBJECT_LEN];} Student;Student* student_erstelle(int matrikelnummer, const char* name, const char* studienfach);void student_zeige_alle(Student** studenten, int anzahl);void student_loesche(Student* student);Student* find_student(Student** studenten, int anzahl, int mat_nr);void delete_student(Student** studenten, int* anzahl, int mat_nr);#endif'
Hier ist der erweiterte Code für die Quellcode-Datei student.c
:
'#include "student.h"#include <stdio.h>#include <string.h>Student* student_erstelle(int matrikelnummer, const char* name, const char* studienfach) { Student* s = (Student*)malloc(sizeof(Student)); if (s == NULL) { fprintf(stderr, "Speicher konnte nicht zugewiesen werden"); exit(EXIT_FAILURE); } s->matrikelnummer = matrikelnummer; strncpy(s->name, name, NAME_LEN-1); s->name[NAME_LEN-1] = '\0'; strncpy(s->studienfach, studienfach, SUBJECT_LEN-1); s->studienfach[SUBJECT_LEN-1] = '\0'; return s;}void student_zeige_alle(Student** studenten, int anzahl) { for (int i = 0; i < anzahl; i++) { Student* s = studenten[i]; printf("Matrikelnummer: %d, Name: %s, Studienfach: %s", s->matrikelnummer, s->name, s->studienfach); }}void student_loesche(Student* s) { free(s);}Student* find_student(Student** studenten, int anzahl, int mat_nr) { for (int i = 0; i < anzahl; i++) { if (studenten[i]->matrikelnummer == mat_nr) { return studenten[i]; } } return NULL;}void delete_student(Student** studenten, int* anzahl, int mat_nr) { for (int i = 0; i < *anzahl; i++) { if (studenten[i]->matrikelnummer == mat_nr) { student_loesche(studenten[i]); for (int j = i; j < *anzahl - 1; j++) { studenten[j] = studenten[j + 1]; } *anzahl -= 1; return; } } printf("Student mit Matrikelnummer %d nicht gefunden.", mat_nr);}'
Dieser Code enthält eine neue Funktion delete_student
, die einen Studenten anhand der Matrikelnummer aus der Datenbank löscht und den Speicher korrekt verwaltet.
Nun erweitern wir die Testfunktion in der Quellcode-Datei main.c
:
'#include "student.h"#include <stdio.h>#include <stdlib.h>int main() { int anzahl_studenten = 3; const int max_students = 3; Student* studenten[max_students]; studenten[0] = student_erstelle(1, "Alice", "Informatik"); studenten[1] = student_erstelle(2, "Bob", "Mathematik"); studenten[2] = student_erstelle(3, "Carlos", "Physik"); printf("Alle Studenten:"); student_zeige_alle(studenten, anzahl_studenten); printf("Student mit Matrikelnummer 2 suchen:"); Student* gefunden = find_student(studenten, anzahl_studenten, 2); if (gefunden) { printf("Gefundener Student: Matrikelnummer %d, Name: %s, Studienfach: %s", gefunden->matrikelnummer, gefunden->name, gefunden->studienfach); } else { printf("Student mit Matrikelnummer 2 nicht gefunden."); } printf("Student mit Matrikelnummer 2 löschen:"); delete_student(studenten, &anzahl_studenten, 2); printf("Alle Studenten nach dem Löschen:"); student_zeige_alle(studenten, anzahl_studenten); for (int i = 0; i < anzahl_studenten; i++) { student_loesche(studenten[i]); } return 0;}'
Dieser Testcode:
Damit ist die Teilaufgabe erfüllt und die Funktion delete_student
korrekt implementiert und getestet.
Teilaufgabe 4: Verwende gdb
und valgrind
, um Dein Programm auf Fehler und Speicherlecks zu prüfen. Erkläre, wie Du gdb
benutzt hast, um einen Segmentation Fault zu identifizieren, und wie Du valgrind
verwendet hast, um sicherzustellen, dass keine Speicherlecks vorhanden sind. Füge auch relevante Ausgaben und Debugging-Informationen hinzu.
Lösung:
Die Werkzeuge gdb
und valgrind
sind sehr nützlich, um Fehler in C-Programmen aufzuspüren und Speicherlecks zu identifizieren. Folgend beschreibe ich, wie diese Werkzeuge verwendet wurden, um das Studenten-Datenbank-Programm zu debuggen und zu überprüfen.
gdb
zur FehlerdiagnoseSchritte zur Verwendung von gdb
:
'gcc -g -o student_db main.c student.c'
gdb
:'gdb ./student_db'
'(gdb) break main'Dies setzt einen Breakpoint am Anfang der
main
-Funktion.'(gdb) run'Der Debugger startet das Programm und hält an der
main
-Funktion.'(gdb) next'Dies führt die nächste Zeile im Programm aus.
'(gdb) print variable_name'Dies zeigt den aktuellen Wert einer Variable an.
'(gdb) continue'Dies setzt die Ausführung des Programms fort, bis der nächste Breakpoint oder Fehler erreicht wird.
Beispiel:
'(gdb) runStarting program: /path/to/student_dbBreakpoint 1, main () at main.c:5(gdb) next(gdb) print anzahl_studenten$1 = 3(gdb) continue'
Angenommen, es tritt ein Segmentation Fault auf, zeigt gdb
die Zeile im Quellcode, wo der Fehler auftritt. Durch Überprüfen der Variablenwerte und Stapelverfolgungen kann der Fehler identifiziert und behoben werden.
valgrind
zur Überprüfung auf SpeicherlecksSchritte zur Verwendung von valgrind
:
'gcc -g -o student_db main.c student.c'
valgrind
:'valgrind --leak-check=full ./student_db'
valgrind
führt das Programm aus und überwacht den Speicherverbrauch.Beispielausgabe:
'==12345== Memcheck, a memory error detector==12345== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.==12345== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info==12345== Command: ./student_db==12345====12345== Invalid read of size 4==12345== at 0x401F3B: main (main.c:20)==12345== Address 0x4a3a068 is 0 bytes inside a block of size 8 free'd==12345== at 0x4C29BC3: free (vg_replace_malloc.c:530)==12345== by 0x401EAB: delete_student (student.c:36)==12345== by 0x401F1B: main (main.c:18)==12345== Block was alloc'd at==12345== at 0x4C27FFF: malloc (vg_replace_malloc.c:299)==12345== by 0x401D76: student_erstelle (student.c:10)==12345== by 0x401E16: main (main.c:8)==12345====12345== HEAP SUMMARY:==12345== in use at exit: 0 bytes in 0 blocks==12345== total heap usage: 6 allocs, 6 frees, 1,048 bytes allocated==12345====12345== All heap blocks were freed -- no leaks are possible==12345== For counts of detected and suppressed errors, rerun with: -v==12345== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)'
Die valgrind
-Ausgabe zeigt, dass ein ungültiger Lesevorgang einer bereits freigegebenen Speicheradresse stattgefunden hat und stellt sicher, dass alle Speicherblöcke korrekt freigegeben wurden.
Die Verwendung von gdb
hilft dabei, Segmentation Faults zu lokalisieren und zu beheben, indem man den Speicher und die Variablenwerte im Detail überprüft. valgrind
ermöglicht eine umfassende Überprüfung auf Speicherlecks und hilft sicherzustellen, dass alle Speicherressourcen korrekt verwaltet werden. Durch sorgfältige Anwendung dieser Tools können wir sicherstellen, dass das Studenten-Datenbank-Programm robust und speichereffizient ist.
Du wirst ein einfaches Softwaresystem entwerfen, das verschiedene Rechnungsarten berechnen kann (z.B. Bruttorechnung, Nettorechnung). In diesem Zusammenhang wirst Du Entwurfsmuster und Architekturprinzipien anwenden, um sicherzustellen, dass das System wartbar und erweiterbar bleibt. Betrachte die folgenden Anforderungen und entwickle eine Lösung.
Implementiere das Strategy-Entwurfsmuster, um die unterschiedlichen Rechnungsberechnungen (z.B. Bruttorechnung, Nettorechnung) zur Laufzeit austauschen zu können. Definiere Schnittstellen und konkrete Strategien für die einzelnen Berechnungsarten. Zeige anhand eines Codebeispiels, wie die Berechnung zur Laufzeit gewechselt werden kann. Achte darauf, das KISS-Prinzip anzuwenden.
Lösung:
Um das Strategy-Entwurfsmuster zu implementieren und die verschiedenen Rechnungsberechnungen zur Laufzeit austauschen zu können, folgen wir diesen Schritten:
Hier ist ein Beispiel in Python:
from abc import ABC, abstractmethod
# Schritt 1: Definiere eine Schnittstelle für die Strategie
class Rechnungsstrategie(ABC):
@abstractmethod
def berechne(self, betrag):
pass
# Schritt 2: Erstelle konkrete Strategien
class BruttoRechnung(Rechnungsstrategie):
def berechne(self, betrag):
return betrag * 1.19 # Beispiel mit 19% MwSt.
class NettoRechnung(Rechnungsstrategie):
def berechne(self, betrag):
return betrag / 1.19 # Beispiel mit 19% MwSt.
# Schritt 3: Implementiere die Kontextklasse
class Rechnungskontext:
def __init__(self, strategie: Rechnungsstrategie):
self.strategie = strategie
def set_strategie(self, strategie: Rechnungsstrategie):
self.strategie = strategie
def berechne_betrag(self, betrag):
return self.strategie.berechne(betrag)
# Beispiel für die Nutzung
betrag = 100
# Benutze Bruttorechnung
rechnungs_strategie = BruttoRechnung()
rechnung = Rechnungskontext(rechnungs_strategie)
print(f'Bruttorechnung: {rechnung.berechne_betrag(betrag)}')
# Wechsle zu Nettorechnung
rechnungs_strategie = NettoRechnung()
rechnung.set_strategie(rechnungs_strategie)
print(f'Nettorechnung: {rechnung.berechne_betrag(betrag)}')
In diesem Beispiel haben wir:
Rechnungsstrategie
erstellt, die die Methode berechne
deklariert.BruttoRechnung
und NettoRechnung
erstellt, die von Rechnungsstrategie
erben und die berechne
-Methode implementieren.Rechnungskontext
erstellt, die eine Instanz einer Rechnungsstrategie enthält und die Methode berechne_betrag
verwendet, um den Betrag zu berechnen.Dieses einfache Beispiel folgt dem KISS-Prinzip und zeigt, wie man das Strategy-Entwurfsmuster in Python implementieren kann.
Verwende das Singleton-Entwurfsmuster, um eine einzige Instanz der Klasse zu garantieren, die für die Berechnungslogik zuständig ist. Implementiere diese Klasse und erkläre, wie Du sicherstellst, dass nur eine Instanz während der Laufzeit existiert. Achte darauf, das Prinzip der Single Responsibility zu wahren und erkläre, welche Verantwortung die Klasse trägt.
Lösung:
Um das Singleton-Entwurfsmuster zu verwenden und sicherzustellen, dass nur eine einzige Instanz der Klasse für die Berechnungslogik während der Laufzeit existiert, folge diesen Schritten:
Hier ist ein Beispiel in Python:
class BerechnungsSingleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(BerechnungsSingleton, cls).__new__(cls)
return cls._instance
def brutto_berechnen(self, betrag):
return betrag * 1.19
def netto_berechnen(self, betrag):
return betrag / 1.19
In diesem Beispiel haben wir:
BerechnungsSingleton
erstellt, die eine einzige Instanz während der Laufzeit sicherstellt.__new__
überschrieben, um zu prüfen, ob die Instanz bereits existiert; wenn nicht, wird sie erstellt.brutto_berechnen
und netto_berechnen
hinzugefügt, die die Berechnungslogik kapseln.Single Responsibility Principle: Die Klasse BerechnungsSingleton
trägt die Verantwortung, die Berechnungslogik bereitzustellen. Sie ist ausschließlich für die Umsetzung der Berechnungslogik (Bruttoberechnung und Nettoberechnung) zuständig und ihre einzige Aufgabe besteht darin, diese Berechnungen durchzuführen. Andere Aufgaben, wie die Verwaltung von Benutzeroberflächen oder Datenzugriffe, gehören nicht zu ihrem Verantwortungsbereich, was die Einhaltung des Single Responsibility Principle gewährleistet.
Hier ein Beispiel, wie Du diese Singleton-Klasse verwenden kannst:
betrag = 100
berechner = BerechnungsSingleton()
print(f'Bruttobetrag: {berechner.brutto_berechnen(betrag)}')
print(f'Nettobetrag: {berechner.netto_berechnen(betrag)}')
# Überprüfen, ob dieselbe Instanz verwendet wird
ein_weiterer_berechner = BerechnungsSingleton()
print(berechner is ein_weiterer_berechner) # Ausgabe: True
In diesem Beispiel sehen wir, dass jede Instanz der Klasse BerechnungsSingleton
die gleiche Instanz ist, was die Einhaltung des Singleton-Entwurfsmusters garantiert.
Mit unserer kostenlosen Lernplattform erhältst du Zugang zu Millionen von Dokumenten, Karteikarten und Unterlagen.
Kostenloses Konto erstellenDu hast bereits ein Konto? Anmelden