From 9aa80fb77228547dce707c888bc52e5f41763c44 Mon Sep 17 00:00:00 2001 From: Thomas Smits Date: Sun, 21 May 2023 21:10:46 +0200 Subject: [PATCH] Initial commit --- Assignment_001/readme.md | 12 ++ Assignment_001/solution/hello.c | 13 ++ Assignment_001/solution/readme.md | 3 + Assignment_002/readme.md | 12 ++ Assignment_002/solution/hello_define.c | 15 ++ Assignment_002/solution/readme.md | 3 + Assignment_003/readme.md | 12 ++ Assignment_003/solution/argv_printer.c | 15 ++ Assignment_003/solution/readme.md | 7 + Assignment_004/readme.md | 12 ++ Assignment_004/solution/hello_cmdline.c | 18 +++ Assignment_004/solution/readme.md | 3 + Assignment_005/readme.md | 14 ++ Assignment_005/solution/Makefile | 27 ++++ Assignment_005/solution/greeter.c | 6 + Assignment_005/solution/greeter.h | 11 ++ Assignment_005/solution/hello_greeter.c | 23 +++ Assignment_005/solution/readme.md | 8 + Assignment_006/readme.md | 53 ++++++ Assignment_006/solution/numberguess.c | 54 +++++++ Assignment_006/solution/readme.md | 3 + Assignment_007/readme.md | 131 +++++++++++++++ Assignment_007/solution/Makefile | 37 +++++ Assignment_007/solution/crypto.c | 91 +++++++++++ Assignment_007/solution/crypto.h | 58 +++++++ Assignment_007/solution/main.c | 72 +++++++++ Assignment_007/solution/readme.md | 10 ++ Assignment_007/solution/test-text.txt | 3 + Assignment_007/solution/test.c | 74 +++++++++ Assignment_008/readme.md | 28 ++++ Assignment_008/solution/countdown.c | 31 ++++ Assignment_008/solution/readme.md | 5 + Assignment_009/readme.md | 24 +++ Assignment_009/solution/readme.md | 3 + Assignment_009/solution/sizeof.c | 22 +++ Assignment_010/readme.md | 12 ++ Assignment_010/solution/readme.md | 3 + Assignment_010/solution/swap.c | 30 ++++ Assignment_011/readme.md | 21 +++ Assignment_011/solution/leet.c | 79 +++++++++ Assignment_011/solution/readme.md | 3 + Assignment_012/readme.md | 14 ++ Assignment_012/solution/print_array.c | 22 +++ Assignment_012/solution/readme.md | 3 + Assignment_013/readme.md | 14 ++ Assignment_013/solution/print_array_pointer.c | 25 +++ Assignment_013/solution/readme.md | 3 + Assignment_014/readme.md | 35 ++++ Assignment_014/solution/readme.md | 3 + Assignment_014/solution/strings.c | 31 ++++ Assignment_015/readme.md | 12 ++ Assignment_015/solution/readme.md | 3 + Assignment_015/solution/reverse.c | 38 +++++ Assignment_016/readme.md | 12 ++ Assignment_016/solution/readme.md | 5 + Assignment_016/solution/vararg_sum.c | 32 ++++ Assignment_017/readme.md | 23 +++ Assignment_017/solution/readme.md | 3 + Assignment_017/solution/typedef.c | 18 +++ Assignment_018/readme.md | 37 +++++ Assignment_018/solution/malloc_free.c | 39 +++++ Assignment_018/solution/readme.md | 3 + Assignment_019/readme.md | 19 +++ Assignment_019/solution/function_pointer.c | 73 +++++++++ Assignment_019/solution/readme.md | 3 + Assignment_020/readme.md | 39 +++++ Assignment_020/solution/readme.md | 3 + Assignment_020/solution/struct_book.c | 39 +++++ Assignment_021/readme.md | 23 +++ Assignment_021/solution/readme.md | 3 + Assignment_021/solution/union.c | 48 ++++++ Assignment_022/readme.md | 152 ++++++++++++++++++ Assignment_022/solution/.gitignore | 1 + Assignment_022/solution/Makefile | 51 ++++++ Assignment_022/solution/benchmark.h | 6 + Assignment_022/solution/minitest.h | 9 ++ Assignment_022/solution/readme.md | 11 ++ Assignment_022/solution/vector_heap.c | 104 ++++++++++++ Assignment_022/solution/vector_heap.h | 144 +++++++++++++++++ .../solution/vector_heap_benchmark.c | 36 +++++ Assignment_022/solution/vector_heap_test.c | 35 ++++ Assignment_022/vector_heap_test.c | 35 ++++ Assignment_023/kryptonier.jpg | Bin 0 -> 22186 bytes Assignment_023/minitest.h | 9 ++ Assignment_023/readme.md | 134 +++++++++++++++ Assignment_023/solution/.gitignore | 1 + Assignment_023/solution/Makefile | 51 ++++++ Assignment_023/solution/benchmark.h | 6 + Assignment_023/solution/minitest.h | 9 ++ Assignment_023/solution/readme.md | 11 ++ Assignment_023/solution/vector_stack.c | 100 ++++++++++++ Assignment_023/solution/vector_stack.h | 131 +++++++++++++++ .../solution/vector_stack_benchmark.c | 26 +++ Assignment_023/solution/vector_stack_test.c | 38 +++++ Assignment_023/vector_stack_test.c | 38 +++++ Assignment_024/readme.md | 12 ++ Assignment_024/solution/print_file.c | 42 +++++ Assignment_024/solution/readme.md | 3 + Assignment_025/readme.md | 14 ++ Assignment_025/solution/file_line_no.c | 47 ++++++ Assignment_025/solution/readme.md | 3 + Assignment_026/readme.md | 15 ++ Assignment_026/solution/read_write.c | 35 ++++ Assignment_026/solution/readme.md | 3 + Assignment_027/readme.md | 14 ++ Assignment_027/solution/pipe_rechner.c | 69 ++++++++ Assignment_027/solution/readme.md | 3 + Assignment_028/readme.md | 14 ++ Assignment_028/solution/readme.md | 6 + Assignment_028/solution/socket_client.c | 63 ++++++++ Assignment_028/solution/socket_server.c | 80 +++++++++ Assignment_029/readme.md | 21 +++ Assignment_029/solution/readme.md | 3 + Assignment_029/solution/threads.c | 33 ++++ readme.md | 39 +++++ 115 files changed, 3343 insertions(+) create mode 100644 Assignment_001/readme.md create mode 100644 Assignment_001/solution/hello.c create mode 100644 Assignment_001/solution/readme.md create mode 100644 Assignment_002/readme.md create mode 100644 Assignment_002/solution/hello_define.c create mode 100644 Assignment_002/solution/readme.md create mode 100644 Assignment_003/readme.md create mode 100644 Assignment_003/solution/argv_printer.c create mode 100644 Assignment_003/solution/readme.md create mode 100644 Assignment_004/readme.md create mode 100644 Assignment_004/solution/hello_cmdline.c create mode 100644 Assignment_004/solution/readme.md create mode 100644 Assignment_005/readme.md create mode 100644 Assignment_005/solution/Makefile create mode 100644 Assignment_005/solution/greeter.c create mode 100644 Assignment_005/solution/greeter.h create mode 100644 Assignment_005/solution/hello_greeter.c create mode 100644 Assignment_005/solution/readme.md create mode 100644 Assignment_006/readme.md create mode 100644 Assignment_006/solution/numberguess.c create mode 100644 Assignment_006/solution/readme.md create mode 100644 Assignment_007/readme.md create mode 100644 Assignment_007/solution/Makefile create mode 100644 Assignment_007/solution/crypto.c create mode 100644 Assignment_007/solution/crypto.h create mode 100644 Assignment_007/solution/main.c create mode 100644 Assignment_007/solution/readme.md create mode 100644 Assignment_007/solution/test-text.txt create mode 100644 Assignment_007/solution/test.c create mode 100644 Assignment_008/readme.md create mode 100644 Assignment_008/solution/countdown.c create mode 100644 Assignment_008/solution/readme.md create mode 100644 Assignment_009/readme.md create mode 100644 Assignment_009/solution/readme.md create mode 100644 Assignment_009/solution/sizeof.c create mode 100644 Assignment_010/readme.md create mode 100644 Assignment_010/solution/readme.md create mode 100644 Assignment_010/solution/swap.c create mode 100644 Assignment_011/readme.md create mode 100644 Assignment_011/solution/leet.c create mode 100644 Assignment_011/solution/readme.md create mode 100644 Assignment_012/readme.md create mode 100644 Assignment_012/solution/print_array.c create mode 100644 Assignment_012/solution/readme.md create mode 100644 Assignment_013/readme.md create mode 100644 Assignment_013/solution/print_array_pointer.c create mode 100644 Assignment_013/solution/readme.md create mode 100644 Assignment_014/readme.md create mode 100644 Assignment_014/solution/readme.md create mode 100644 Assignment_014/solution/strings.c create mode 100644 Assignment_015/readme.md create mode 100644 Assignment_015/solution/readme.md create mode 100644 Assignment_015/solution/reverse.c create mode 100644 Assignment_016/readme.md create mode 100644 Assignment_016/solution/readme.md create mode 100644 Assignment_016/solution/vararg_sum.c create mode 100644 Assignment_017/readme.md create mode 100644 Assignment_017/solution/readme.md create mode 100644 Assignment_017/solution/typedef.c create mode 100644 Assignment_018/readme.md create mode 100644 Assignment_018/solution/malloc_free.c create mode 100644 Assignment_018/solution/readme.md create mode 100644 Assignment_019/readme.md create mode 100644 Assignment_019/solution/function_pointer.c create mode 100644 Assignment_019/solution/readme.md create mode 100644 Assignment_020/readme.md create mode 100644 Assignment_020/solution/readme.md create mode 100644 Assignment_020/solution/struct_book.c create mode 100644 Assignment_021/readme.md create mode 100644 Assignment_021/solution/readme.md create mode 100644 Assignment_021/solution/union.c create mode 100644 Assignment_022/readme.md create mode 100644 Assignment_022/solution/.gitignore create mode 100644 Assignment_022/solution/Makefile create mode 100644 Assignment_022/solution/benchmark.h create mode 100644 Assignment_022/solution/minitest.h create mode 100644 Assignment_022/solution/readme.md create mode 100644 Assignment_022/solution/vector_heap.c create mode 100644 Assignment_022/solution/vector_heap.h create mode 100644 Assignment_022/solution/vector_heap_benchmark.c create mode 100644 Assignment_022/solution/vector_heap_test.c create mode 100644 Assignment_022/vector_heap_test.c create mode 100644 Assignment_023/kryptonier.jpg create mode 100644 Assignment_023/minitest.h create mode 100644 Assignment_023/readme.md create mode 100644 Assignment_023/solution/.gitignore create mode 100644 Assignment_023/solution/Makefile create mode 100644 Assignment_023/solution/benchmark.h create mode 100644 Assignment_023/solution/minitest.h create mode 100644 Assignment_023/solution/readme.md create mode 100644 Assignment_023/solution/vector_stack.c create mode 100644 Assignment_023/solution/vector_stack.h create mode 100644 Assignment_023/solution/vector_stack_benchmark.c create mode 100644 Assignment_023/solution/vector_stack_test.c create mode 100644 Assignment_023/vector_stack_test.c create mode 100644 Assignment_024/readme.md create mode 100644 Assignment_024/solution/print_file.c create mode 100644 Assignment_024/solution/readme.md create mode 100644 Assignment_025/readme.md create mode 100644 Assignment_025/solution/file_line_no.c create mode 100644 Assignment_025/solution/readme.md create mode 100644 Assignment_026/readme.md create mode 100644 Assignment_026/solution/read_write.c create mode 100644 Assignment_026/solution/readme.md create mode 100644 Assignment_027/readme.md create mode 100644 Assignment_027/solution/pipe_rechner.c create mode 100644 Assignment_027/solution/readme.md create mode 100644 Assignment_028/readme.md create mode 100644 Assignment_028/solution/readme.md create mode 100644 Assignment_028/solution/socket_client.c create mode 100644 Assignment_028/solution/socket_server.c create mode 100644 Assignment_029/readme.md create mode 100644 Assignment_029/solution/readme.md create mode 100644 Assignment_029/solution/threads.c create mode 100644 readme.md diff --git a/Assignment_001/readme.md b/Assignment_001/readme.md new file mode 100644 index 0000000..3a25298 --- /dev/null +++ b/Assignment_001/readme.md @@ -0,0 +1,12 @@ +# Simples Hello-World-Programm + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie ein Programm, das unter Verwendung von `printf` aus `` den Text `Hello, World!` ausgibt. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_001/solution/hello.c b/Assignment_001/solution/hello.c new file mode 100644 index 0000000..b4ca387 --- /dev/null +++ b/Assignment_001/solution/hello.c @@ -0,0 +1,13 @@ +/** + * Simples Hello-World-Programm. + * + * Schreiben Sie ein Programm, das unter Verwendung von + * `printf` aus `` den Text `Hello, World` + * ausgibt. + */ +#include + +int main(int argc, char** argv) { + printf("%s\n", "Hello, World!"); + return 0; +} diff --git a/Assignment_001/solution/readme.md b/Assignment_001/solution/readme.md new file mode 100644 index 0000000..ce712e3 --- /dev/null +++ b/Assignment_001/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Simples Hello-World-Programm + +Lösung: [hello.c](hello.c) \ No newline at end of file diff --git a/Assignment_002/readme.md b/Assignment_002/readme.md new file mode 100644 index 0000000..4c5ead2 --- /dev/null +++ b/Assignment_002/readme.md @@ -0,0 +1,12 @@ +# Simples Hello-World-Programm mit #define + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie ein einfaches Hello-World-Programm, das den Benutzer mit dem Text `Hello, World.` unter Verwendung von `printf` begrüßt. Benutzen Sie eine Konstante `GREETING`, die Sie per `#define` festlegen, um den Text `Hello, World.` zu speichern. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_002/solution/hello_define.c b/Assignment_002/solution/hello_define.c new file mode 100644 index 0000000..6e242e7 --- /dev/null +++ b/Assignment_002/solution/hello_define.c @@ -0,0 +1,15 @@ +/** + * Simples Hello-World-Programm mit #define. + * + * Schreiben Sie ein einfaches Hello-World-Programm, das den Benutzer mit dem + * Text `Hello, World.` unter Verwendung von `printf` begrüßt. Benutzen Sie eine + * Konstante `GREETING`, die Sie per `#define` festlegen, um den Text + * `Hello, World.` zu speichern. + */ +#include +#define GREETING "Hello, World." + +int main(int argc, char** argv) { + printf("%s\n", GREETING); + return 0; +} diff --git a/Assignment_002/solution/readme.md b/Assignment_002/solution/readme.md new file mode 100644 index 0000000..9c2ab85 --- /dev/null +++ b/Assignment_002/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Simples Hello-World-Programm mit #define + +Lösung: [hello_define.c](hello_define.c) \ No newline at end of file diff --git a/Assignment_003/readme.md b/Assignment_003/readme.md new file mode 100644 index 0000000..56f21ac --- /dev/null +++ b/Assignment_003/readme.md @@ -0,0 +1,12 @@ +# Kommandozeilenargumente ausgeben + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie ein Programm, dass die übergebenen Kommandozeilenargumente wieder ausgibt. Geben Sie auch das erste (Index 0) Argument aus. Was fällt Ihnen auf? + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_003/solution/argv_printer.c b/Assignment_003/solution/argv_printer.c new file mode 100644 index 0000000..38a0677 --- /dev/null +++ b/Assignment_003/solution/argv_printer.c @@ -0,0 +1,15 @@ +/** + * Kommandozeilenargumente ausgeben + * + * Schreiben Sie ein Programm, dass die übergebenen + * Kommandozeilenargumente wieder ausgibt. Geben Sie auch + * das erste (Index 0) Argument aus. + */ +#include + +int main(int argc, char** argv) { + for (int i = 0; i < argc; i++) { + printf("Argument %d: %s\n", i, argv[i]); + } + return 0; +} \ No newline at end of file diff --git a/Assignment_003/solution/readme.md b/Assignment_003/solution/readme.md new file mode 100644 index 0000000..d3fbf10 --- /dev/null +++ b/Assignment_003/solution/readme.md @@ -0,0 +1,7 @@ +# Lösung: Kommandozeilenargumente ausgeben + +Das erste Argument enthält immer den Namen des Programms selbst. + +Lösung: + + * [argv_printer.c](argv_printer.c) \ No newline at end of file diff --git a/Assignment_004/readme.md b/Assignment_004/readme.md new file mode 100644 index 0000000..8d6e9c0 --- /dev/null +++ b/Assignment_004/readme.md @@ -0,0 +1,12 @@ +# Hello-World-Programm, das den Namen von der Kommandozeile nimmt + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie ein einfaches Hello-World-Programm, das den Namen des Nutzers auf der Kommandozeile als Argument entgegen nimmt. Wird kein Argument gegeben, soll der Nutzer als `` begrüßt werden. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_004/solution/hello_cmdline.c b/Assignment_004/solution/hello_cmdline.c new file mode 100644 index 0000000..41ca4f2 --- /dev/null +++ b/Assignment_004/solution/hello_cmdline.c @@ -0,0 +1,18 @@ +/** + * Hello-World-Programm, das den Namen von der Kommandozeile nimmt. + * + * Schreiben Sie ein einfaches Hello-World-Programm, das den Namen des + * Nutzers auf der Kommandozeile als Argument entgegen nimmt. Wird + * kein Argument gegeben, soll der Nutzer als `` begrüßt werden. + */ +#include + +int main(int argc, char** argv) { + if (argc < 2) { + printf("Hello, %s.\n", ""); + } + else { + printf("Hello, %s.\n", argv[1]); + } + return 0; +} diff --git a/Assignment_004/solution/readme.md b/Assignment_004/solution/readme.md new file mode 100644 index 0000000..b3f4bcf --- /dev/null +++ b/Assignment_004/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Hello-World-Programm, das den Namen von der Kommandozeile nimmt + +Lösung: [hello_cmdline.c](hello_cmdline.c) \ No newline at end of file diff --git a/Assignment_005/readme.md b/Assignment_005/readme.md new file mode 100644 index 0000000..1d26bfc --- /dev/null +++ b/Assignment_005/readme.md @@ -0,0 +1,14 @@ +# Simples Hello-World-Programm mit externer Funktion + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie eine Header-Datei `greeter.h`, welche eine Funktion `greet` definiert. Diese Funktion nimmt eine Zeichenkette (`char*`) für den Namen der zu begrüßenden Person und gibt dann `Hello, NAME.` aus, wobei `NAME` durch den Namen ersetzt wird. Implementieren Sie diese Funktion in einer Datei `greet.c`. + +Schreiben Sie ein Programm `hello_greeter.c`, welches diese Funktion aus `greet.c` benutzt, um den Benutzer zu begrüßen. Der Name der Person wird auf der Kommandozeile übergeben. Wird kein Argument gegeben, soll der Nutzer als `` begrüßt werden. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_005/solution/Makefile b/Assignment_005/solution/Makefile new file mode 100644 index 0000000..a5047d0 --- /dev/null +++ b/Assignment_005/solution/Makefile @@ -0,0 +1,27 @@ +CC = cc +COMPILER_OPTIONS = -Wall +BIN_DIR = obj +BINARIES = $(BIN_DIR)/hello_greeter +MAIN = $(BIN_DIR)/hello_greeter +OBJ = $(BIN_DIR)/hello_greeter.o \ + $(BIN_DIR)/greeter.o + +.PHONY: all +all: $(BINARIES) + +.PHONY: clean +clean: + rm -rf $(BIN_DIR) + +.PHONY: test +test: all + @$(MAIN) + @$(MAIN) Thomas + +$(BIN_DIR)/%.o: %.c *.h + mkdir -p $(BIN_DIR) + $(CC) $(COMPILER_OPTIONS) -o $@ -c $< + +$(MAIN): $(OBJ) + mkdir -p $(BIN_DIR) + $(CC) $(COMPILER_OPTIONS) -o $@ $^ diff --git a/Assignment_005/solution/greeter.c b/Assignment_005/solution/greeter.c new file mode 100644 index 0000000..c4e3a46 --- /dev/null +++ b/Assignment_005/solution/greeter.c @@ -0,0 +1,6 @@ +#include "greeter.h" +#include + +void greet(const char* name) { + printf("Hello, %s.\n", name); +} diff --git a/Assignment_005/solution/greeter.h b/Assignment_005/solution/greeter.h new file mode 100644 index 0000000..8b167d7 --- /dev/null +++ b/Assignment_005/solution/greeter.h @@ -0,0 +1,11 @@ +#ifndef GREETER_H +#define GREETER_H + +/** + * Begrüßt jemanden. + * + * @param name Name der Person, die begrüßt wird. + */ +void greet(const char* name); + +#endif diff --git a/Assignment_005/solution/hello_greeter.c b/Assignment_005/solution/hello_greeter.c new file mode 100644 index 0000000..dbf6ead --- /dev/null +++ b/Assignment_005/solution/hello_greeter.c @@ -0,0 +1,23 @@ +/** + * Simples Hello-World-Programm mit externer Funktion. + * + * Schreiben Sie eine Header-Datei `greeter.h`, welche eine Funktion `greet` + * definiert. Diese Funktion nimmt eine Zeichenkette (`char*`) für den Namen + * der zu begrüßenden Person und gibt dann `Hello, NAME.` aus, wobei `NAME` + * durch den Namen ersetzt wird. Implementieren Sie diese Funktion in einer + * Datei `greet.c`. Schreiben Sie ein Programm `hello_greeter.c`, welches + * diese Funktion aus `greet.c` benutzt, um den Benutzer zu begrüßen. Der + * Name der Person wird auf der Kommandozeile übergeben. Wird + * kein Argument gegeben, soll der Nutzer als `` begrüßt werden. + */ +#include +#include "greeter.h" + +int main(int argc, char** argv) { + if (argc < 2) { + greet(""); + } + else { + greet(argv[1]); + } +} diff --git a/Assignment_005/solution/readme.md b/Assignment_005/solution/readme.md new file mode 100644 index 0000000..d8937cf --- /dev/null +++ b/Assignment_005/solution/readme.md @@ -0,0 +1,8 @@ +# Lösung: Simples Hello-World-Programm mit externer Funktion + +Lösung: + + * [greeter.h](greeter/greeter.h) + * [greeter.c](greeter/greeter.c) + * [hello_greeter.h](greeter/hello_greeter.c) + * [Makefile](greeter/Makefile) diff --git a/Assignment_006/readme.md b/Assignment_006/readme.md new file mode 100644 index 0000000..a353e0e --- /dev/null +++ b/Assignment_006/readme.md @@ -0,0 +1,53 @@ +# Zahlenraten + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +**Ziel**: Ziel dieses Assignments ist es, erste Schritte mit C zu machen und die Syntax kennenzulernen. Als Test Ihrer Kenntnisse werden Sie ein _ganz_ einfaches Spiel in C programmieren. + +## Zahlenraten entwickeln + +### Beschreibung des Programms + +Schreiben Sie ein einfaches Zahlenraten-Spiel (`zahlenraten.c`) in C mit folgenden Eigenschaften: + + * Das Spiel zieht zufällig eine Zahl zwischen 1 und 100, die der Benutzer erraten soll. + * Der Benutzer wird aufgefordert eine Zahl zwischen 1 und 100 einzugeben. + * Hat er die richtige Zahl geraten, beendet sich das Programm und zeigt die Anzahl der Versuche an. + * Hat er die Zahl nicht geraten, sagt ihm das Programm, ob die Zahl zu groß oder zu klein war und nimmt die nächste Eingabe entgegen. + +Eine beispielhafte Session mit dem Programm sieht dann wie folgt aus: + +```console +Bitte geben Sie eine Zahl ein: 50 +Zu groß +Bitte geben Sie eine Zahl ein: 25 +Zu groß +Bitte geben Sie eine Zahl ein: 12 +Zu klein +Bitte geben Sie eine Zahl ein: 20 +Zu groß +Bitte geben Sie eine Zahl ein: 16 +Zu klein +Bitte geben Sie eine Zahl ein: 18 +Zu klein +Bitte geben Sie eine Zahl ein: 19 +Richtig nach 7 Versuchen. +``` + +### C-Features + +Bitte verwenden Sie die folgenden C-Features in Ihrem Programm: + + * Benutzung von Formatstrings mit `printf` + * Generierung von Zufallszahlen mit der Funktion [random](https://man7.org/linux/man-pages/man3/srandom.3.html) + * Lesen von Zahlen und Strings von er Konsole mit `fgets` + +Lesen Sie die Dokumentation von `random` sorgfältig; andernfalls ist 84 die Lösung aller Runden. + + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_006/solution/numberguess.c b/Assignment_006/solution/numberguess.c new file mode 100644 index 0000000..f4e8ab1 --- /dev/null +++ b/Assignment_006/solution/numberguess.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include + +#define RANGE 100 +#define BUF_LENGTH 255 + +int main(int argc, char** argv) { + + char buffer[BUF_LENGTH]; + int attempt = 0; + + /* seed random generator */ + srandom(time(NULL)); + + int number = (random() % RANGE) + 1; + + for (;;) { + attempt++; + printf("Bitte geben Sie eine Zahl im Bereich 1-%d ein: ", RANGE); + int guess = 0; + + memset(buffer, 0, BUF_LENGTH); + + if (fgets(buffer, BUF_LENGTH - 1, stdin) != 0) { + sscanf(buffer, "%d", &guess); + /* Alternative zu sscanf + char* newline = strchr(buffer, '\n'); + if (newline) { + *newline = '\0'; + } + guess = atoi(buffer); + */ + } + + if (guess < 1 || guess > RANGE) { + continue; + } + + if (guess < number) { + puts("Zu klein"); + } + else if (guess > number) { + puts("Zu groß"); + } + else { + printf("Richtig nach %d Versuchen.\n", attempt); + break; + } + } + + return 0; +} diff --git a/Assignment_006/solution/readme.md b/Assignment_006/solution/readme.md new file mode 100644 index 0000000..5bec6f7 --- /dev/null +++ b/Assignment_006/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Zahlenraten + +Lösung: [numberguess.c](numberguess.c) diff --git a/Assignment_007/readme.md b/Assignment_007/readme.md new file mode 100644 index 0000000..3c12e79 --- /dev/null +++ b/Assignment_007/readme.md @@ -0,0 +1,131 @@ +# Verschlüsselung in C + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Ihre Aufgabe besteht darin, ein C-Programm zu schreiben, dass Daten mit einem einfachen XOR-Algorithmus verschlüsseln kann. + +Die Verschlüsselungsfunktionen sind bereits deklariert worden. Sie finden es in der Datei [crypto.h](crypto.h). Lesen aufmerksam die Kommentare in dieser Datei. + +Implementieren Sie die Funktionen in einer Datei `crypto.c`. Verändern Sie nicht den Inhalt von `crypto.h`. Der Schlüssel, repräsentiert durch die Struktur `KEY` besteht aus einer Zeichenkette und einer Zahl, die das Verschlüsselungsverfahren anzeiht `type`. `type` ist für die XOR-Verschlüsseung mit `1` festgelegt. + +*Tipp*: Denken Sie daran, keinen Code zu duplizieren und führen Sie gegebenenfalls weitere Funktionen ein, um dies zu vermeiden. + + +## XOR-Verschlüsselung + +Implementieren Sie ein Verschlüsselung, die auf der Verknüpfung von Text und Schlüssel per XOR basiert. + +Bei der XOR-Verschlüsselung werden Klartext und Schlüssel per XOR miteinander verknüpft. Der Schlüssel kann ein beliebig langer Text sein. Wenn der Klartext länger als der Schlüssel ist, wird der Schlüssel einfach wiederholt. Die Zahlenwerte von Schlüssel und Klartext werden dann per XOR miteinander verknüpft. Die Entschlüsselung funktioniert genauso, indem wieder der verschlüsselte Text und der Schlüssel per XOR miteinander verknüpft werden. + +Beispielsweise würde beim Schlüssel `TPERULES` (damit ist jetzt auch klar, woher diese Aufgabe ursprünglich stammt) folgendes passieren: + +```console +Klartext: + A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +Schlüssel: + T P E R U L E S T P E R U L E S T P E R U L E S T P + 20 16 5 18 21 12 5 19 20 16 5 18 21 12 5 19 20 16 5 18 21 12 5 19 20 16 +Ergebnis: + U R F V P J B [ ] Z N ^ X B J C E B V F @ Z R K M J + 21 18 6 22 16 10 2 27 29 26 14 30 24 2 10 3 5 2 22 6 0 26 18 11 13 10 +Schlüssel: + T P E R U L E S T P E R U L E S T P E R U L E S T P + 20 16 5 18 21 12 5 19 20 16 5 18 21 12 5 19 20 16 5 18 21 12 5 19 20 16 +Ergebnis: + A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +``` + +Das Ergebnis entsteht durch das XOR-Verknüpfen der Zahlenwerte, z.B. wird `A` mit `T` verschlüsselt, indem man `1 ^ 20 = 21` rechnet. Die Entschlüsselung erfolgt dann umgekehrt, d.h. `21 ^ 20 = 1`, womit sich wieder ein `A` ergibt. +Beachten Sie, dass bei der XOR-Verschlüsselung der Schlüssel `KEY.chars` beliebig lang werden kann. Außerdem brauchen Sie zur Darstellung des verschlüsselten Textes mehr als 26 Buchstaben, nämlich 32. Nehmen Sie daher einfach noch die Zeichen `@=0, [=27, \=28, ]=29, ^=30 und _=31` mit auf. + + +## Makefile + +Schreiben Sie ein Makefile, dass das Bauen und Testen des Programms automatisiert. Folgende Targets sollten mindestens vorhanden sein: + + * `all` + * `clean` + * `runtest` + +Weitere Targets werden für das Erstellen der Objektdateien und das Linken benötigt. Fügen Sie diese ebenfalls ein. + + +## Test + +Schreiben Sie automatisierte Unit-Tests mit denen Sie die korrekte Funktionsweise der Implementierungen überprüfen. Legen Sie die Tests in eine andere Datei als die Verschlüsselung. Denken Sie daran, auch die Fehler zu testen. + +Da die Unit-Test-Frameworks für C relativ schwergewichtig sind, verwenden Sie am besten zwei einfache Makros nach dem folgenden Vorbild. So ersparen Sie sich das Einbinden eines Frameworks. + +```c +#define mu_assert(message, test) do { if (!(test)) return message; } while (0) +#define mu_run_test(test) do { char *message = test(); tests_run++; \ + if (message) return message; } while (0) + +int test_run = 0; +``` + +Die Test können dann wie folgt geschrieben werden: + +```c +static char* test1() { + mu_assert("Meldung", 1 == 1); +} + +static char* allTests() { + mu_run_test(test1); + /* weitere Tests */ + return 0; +} + +int main() { + char *result = allTests(); + + if (result != 0) printf("%s\n", result); + else printf("ALL TESTS PASSED\n"); + + printf("Tests run: %d\n", tests_run); + + return result != 0; +} +``` + +## Programm + +Schreiben Sie *ein* Programm, das sowohl ver- auch entschlüsseln kann. Wie es genutzt wird, bestimmt es selbst aus dem Namen, unter dem es aufgerufen wurde (siehe Wert von `argv[0]`): + + * unter dem Namen `encrypt` verschlüsselt es + * unter dem Namen `decrypt` entschlüsselt es + +Das Programm bekommt als ersten Kommandozeilen-Parameter den Schlüssel übergeben. Wenn ein zweiter Parameter gegeben ist, wird dies als Dateiname interpretiert. Andernfalls liest das Programm die Eingaben von `stdin`. + +Der verschlüsselte Text wird in jedem Fall auf der Console (`stdout`) wieder ausgegeben. + +Beachten Sie, dass das Programm auch prüfen muss, ob die Parameter korrekt angegeben wurden und nicht läuft, wenn z.B. der Schlüssel fehlt. Auch müssen falsche Zeichen im Text oder Schlüssel gemeldet werden. + +```console +$ ./encrypt MYKEY +HALLO +EXGIV +$ ./decrypt MYKEY +EXGIV +HALLO +$ ./encrypt MYKEY ../test.txt +IPNVADJ_]\DWSQ\UMS_L@A_@JY\E +I\Y]OHKXFQALNVJHR^K^ +@P_]THQY@KHWS_\DUNK +$ ./encrypt +Usage: KEY [file name] +$ ./encrypt aaa ../test.txt +Error: Key contains illegal characters +``` + +Fehlermeldungen geben Sie bitte grundsätzlich auf `stderr` aus. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_007/solution/Makefile b/Assignment_007/solution/Makefile new file mode 100644 index 0000000..e9317b5 --- /dev/null +++ b/Assignment_007/solution/Makefile @@ -0,0 +1,37 @@ +# Makefile for the project +OUTPUT_DIR = output + +.PHONY: all +all: $(OUTPUT_DIR) $(OUTPUT_DIR)/encrypt $(OUTPUT_DIR)/decrypt $(OUTPUT_DIR)/test runtest + +.PHONY: clean +clean: + rm $(OUTPUT_DIR)/*.o $(OUTPUT_DIR)/encrypt $(OUTPUT_DIR)/test $(OUTPUT_DIR)/decrypt + rmdir $(OUTPUT_DIR) + +$(OUTPUT_DIR): + mkdir $(OUTPUT_DIR) + +$(OUTPUT_DIR)/crypto.o: crypto.c crypto.h + cc -o $@ -c $< + +$(OUTPUT_DIR)/main.o: main.c crypto.h + cc -o $@ -c $< + +$(OUTPUT_DIR)/test.o: test.c crypto.h + cc -o $@ -c $< + +$(OUTPUT_DIR)/encrypt: $(OUTPUT_DIR)/main.o $(OUTPUT_DIR)/crypto.o + cc -o $@ $^ + +$(OUTPUT_DIR)/decrypt: $(OUTPUT_DIR)/main.o $(OUTPUT_DIR)/crypto.o + cc -o $@ $^ + +$(OUTPUT_DIR)/test: $(OUTPUT_DIR)/test.o $(OUTPUT_DIR)/crypto.o + cc -o $@ $^ + +.PHONY: runtest +runtest: $(OUTPUT_DIR)/test + @echo "Running tests" + @echo "---------------------" + $< diff --git a/Assignment_007/solution/crypto.c b/Assignment_007/solution/crypto.c new file mode 100644 index 0000000..c4cece7 --- /dev/null +++ b/Assignment_007/solution/crypto.c @@ -0,0 +1,91 @@ +#include "crypto.h" +#include + +static int charToInt(char c) { + return c - 'A' + 1; +} + +static char intToChar(int i) { + return (char) (i + 'A' - 1); +} + +static int checkCharacters(const char* inputChars, const char* charSet, int error) { + char* p = (char*) inputChars; + + while (*p) { + if (strchr(charSet, *p) == NULL) { + return error; + } + + p++; + } + + return 0; +} + +static int checkKey(KEY key) { + int check; + + if (strlen(key.chars) == 0) { + return E_KEY_TOO_SHORT; + } + + check = checkCharacters(key.chars, KEY_CHARACTERS, E_KEY_ILLEGAL_CHAR); + + if (check) { + return check; + } + + return 0; +} + + +static int xor(KEY key, const char* message, char* result) { + int i, pos, check; + size_t size; + size_t keySize; + + check = checkKey(key); + + if (check) { + return check; + } + + size = strlen(message); + keySize = strlen(key.chars); + + for (i = 0, pos = 0; i < size; i++) { + int v1 = charToInt(message[i]); + int v2 = charToInt(key.chars[pos]); + + result[i] = intToChar(v1 ^ v2); + + if (++pos >= keySize) { + pos = 0; + } + } + + result[size] = '\0'; /* terminate string */ + + return 0; +} + +int encrypt(KEY key, const char* message, char* output) { + int error = checkCharacters(message, MESSAGE_CHARACTERS, E_MESSAGE_ILLEGAL_CHAR); + + if (error) { + return error; + } + + return xor(key, message, output); +} + +int decrypt(KEY key, const char* cyphertext, char* output) { + int error = checkCharacters(cyphertext, CYPHER_CHARACTERS, E_CYPHER_ILLEGAL_CHAR); + + if (error) { + return error; + } + + return xor(key, cyphertext, output); +} diff --git a/Assignment_007/solution/crypto.h b/Assignment_007/solution/crypto.h new file mode 100644 index 0000000..525ab8c --- /dev/null +++ b/Assignment_007/solution/crypto.h @@ -0,0 +1,58 @@ +#ifndef __CRYPTO_H__ +#define __CRYPTO_H__ + +/** Length of key not sufficient. */ +#define E_KEY_TOO_SHORT 1 + +/** Key contains illegal characters. */ +#define E_KEY_ILLEGAL_CHAR 2 + +/** Message contains illegal characters. */ +#define E_MESSAGE_ILLEGAL_CHAR 3 + +/** Cypher text contains illegal characters. */ +#define E_CYPHER_ILLEGAL_CHAR 4 + +#define KEY_CHARACTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define MESSAGE_CHARACTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define CYPHER_CHARACTERS "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + +/** + * Key used in de- and encryption. + */ +typedef struct { + int type; /* Type of the key. */ + char* chars; /* Key characters. */ +} KEY; + +/** + * Encrypt the given text and return the encrypted version. The input text + * may only contain the letters A-Z. No space or other characters are + * allowed. In case of illegal characters in the text, the function + * returns E_MESSAGE_ILLEGAL_CHAR. The key must contain a valid character set + * and have a sufficient length. For XOR encryption only the characters + * A-Z are valid in the key. The key must have at least a length of 1. + * + * @param key Key to be used for the encryption + * @param input Clear text + * @param output Encrypted text + * @return 0 on success, otherwise error code + */ +int encrypt(KEY key, const char* input, char* output); + +/** + * Decrypt the given text and return the decrypted version. The cypher text + * may only contain the characters defined as output of the encrypt function. + * For other characters the function will return E_CYPHER_ILLEGAL_CHAR. + * The key must contain a valid character set + * and have a sufficient length. For XOR encryption only the characters + * A-Z are valid in the key. The key must have at least a length of 1. + * + * @param key Key to be used for the decryption + * @param cypherText Cypher text + * @param output Decrypted text + * @return 0 on success, otherwise error code + */ +int decrypt(KEY key, const char* cypherText, char* output); + +#endif /* __CRYPTO_H__ */ diff --git a/Assignment_007/solution/main.c b/Assignment_007/solution/main.c new file mode 100644 index 0000000..ae13b2f --- /dev/null +++ b/Assignment_007/solution/main.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include "crypto.h" +#include + +#define BUFFER_SIZE 255 + +int main(int argc, char** argv) { + + /* encrypt or decrypt function */ + int (*func)(KEY, const char*, char*); + + if (argc < 2) { + fprintf(stderr, "Usage: KEY [file name]\n\n"); + exit(1); + } + + if (strstr(argv[0], "encrypt")) { + func = encrypt; + } + else if (strstr(argv[0], "decrypt")) { + func = decrypt; + } + else { + func = encrypt; + } + + KEY key; + key.type = 1; + key.chars = argv[1]; + FILE* f; + + if (argc == 3) { + char *file = argv[2]; + if (!(f = fopen(file, "r"))) { + fprintf(stderr, "Could not open %s: %s\n", file, strerror(errno)); + exit(1); + } + } + else { + f = stdin; + } + + char buffer[BUFFER_SIZE]; + char result[BUFFER_SIZE]; + + while (fgets(buffer, BUFFER_SIZE - 1, f)) { + + /* remove newline character at the end of line */ + char* lineEnd = strchr(buffer, 10); + if (lineEnd) { + *lineEnd = '\0'; + } + + /* encrypt or decrypt */ + int error = func(key, buffer, result); + + if (error) { + fprintf(stderr, "Error: %d\n", error); + exit(error); + } + + printf("%s\n", result); + } + + if (argc == 3) { + fclose(f); + } + + return 0; +} \ No newline at end of file diff --git a/Assignment_007/solution/readme.md b/Assignment_007/solution/readme.md new file mode 100644 index 0000000..b3156e7 --- /dev/null +++ b/Assignment_007/solution/readme.md @@ -0,0 +1,10 @@ +# Lösung: Verschlüsselung in C + +Lösung: + + * [crypto.c](crypto/crypto.c) + * [crypto.h](crypto/crypto.h) + * [main.c](crypto/main.c) + * [test.c](crypto/test.c) + * [test-text.txt](crypto/test-text.txt) + * [Makefile](crypto/Makefile) \ No newline at end of file diff --git a/Assignment_007/solution/test-text.txt b/Assignment_007/solution/test-text.txt new file mode 100644 index 0000000..51c92e0 --- /dev/null +++ b/Assignment_007/solution/test-text.txt @@ -0,0 +1,3 @@ +DIESXISTXEINXTEXTXZUMXTESTEN +DERXVERSCHLUESSEKUNG +MITXMEHRERENXZEILEN diff --git a/Assignment_007/solution/test.c b/Assignment_007/solution/test.c new file mode 100644 index 0000000..43812e4 --- /dev/null +++ b/Assignment_007/solution/test.c @@ -0,0 +1,74 @@ +#include "crypto.h" +#include +#include +#include + +#define mu_assert(message, test) do { if (!(test)) return message; } while (0) +#define mu_run_test(test) do { char *message = test(); tests_run++; \ + if (message) return message; } while (0) +int tests_run; + +static char* testRoundtrip() { + char* text = strdup("DIESXISTXEINXTEST"); + char* result = (char*) malloc(strlen(text) + 1); + char* result2 = (char*) malloc(strlen(text) + 1); + + KEY key = { 1, "KEY" }; + encrypt(key, text, result); + decrypt(key, result, result2); + + mu_assert("Roundtrip failed", strcmp(result2, text) == 0); + return 0; +} + +static char* testIllegalKey() { + char* text = strdup("DIESXISTXEINXTEST"); + char* result = (char*) malloc(strlen(text) + 1); + int error; + + KEY key1 = { 1, "" }; + error = encrypt(key1, text, result); + mu_assert("Zero key not detected", error == E_KEY_TOO_SHORT); + + KEY key2 = { 1, "abcd"}; + error = encrypt(key2, text, result); + mu_assert("Illegal char in key not detected: abcd", error == E_KEY_ILLEGAL_CHAR); + + KEY key3 = { 1, "@[\\]^_"}; + error = encrypt(key3, text, result); + mu_assert("Illegal char in key not detected: @[\\]^_", error == E_KEY_ILLEGAL_CHAR); + return 0; +} + +static char* textIllegalMessage() { + KEY key1 = { 1, "KEY" }; + int error = encrypt(key1, "ABCD AB", NULL); + mu_assert("Illegal char in message not detected: ABCD AB", error == E_MESSAGE_ILLEGAL_CHAR); + return 0; +} + +static char* textIllegalCypher() { + KEY key1 = { 1, "KEY" }; + int error = decrypt(key1, "ABCD AB", NULL); + mu_assert("Illegal char in cypher not detected: ABCD AB", error == E_CYPHER_ILLEGAL_CHAR); + return 0; +} + +static char* allTests() { + mu_run_test(testRoundtrip); + mu_run_test(testIllegalKey); + mu_run_test(textIllegalMessage); + mu_run_test(textIllegalCypher); + return 0; +} + +int main() { + char *result = allTests(); + + if (result != 0) printf("%s\n", result); + else printf("ALL TESTS PASSED\n"); + + printf("Tests run: %d\n", tests_run); + + return result != 0; +} diff --git a/Assignment_008/readme.md b/Assignment_008/readme.md new file mode 100644 index 0000000..fb3cb1a --- /dev/null +++ b/Assignment_008/readme.md @@ -0,0 +1,28 @@ +# Countdown + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie ein Programm, dass rückwärts von 10 bis 0 zählt und dann "Launch!" ausgibt. Verwenden Sie eine `for`-Schleife und die `printf`-Funktion aus ´`. + +```console +10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 +Launch! +``` + +Versuchen Sie die Ausgabe wie im Beispiel mit einem führenden Leerzeichen für die Zahlen < 10 zu realisieren. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_008/solution/countdown.c b/Assignment_008/solution/countdown.c new file mode 100644 index 0000000..64598b3 --- /dev/null +++ b/Assignment_008/solution/countdown.c @@ -0,0 +1,31 @@ +/** + * Schreiben Sie ein Programm, dass rückwärts von 10 bis 0 zählt + * und dann "Launch!" ausgibt. Verwenden Sie eine `for`-Schleife + * und die `printf`-Funktion aus ´`. + * + * ```console + * 10 + * 9 + * 8 + * 7 + * 6 + * 5 + * 4 + * 3 + * 2 + * 1 + * Launch! + * ``` + * + * Versuchen Sie die Ausgabe wie im Beispiel mit einem führenden + * Leerzeichen für die Zahlen < 10 zu realisieren. + */ +#include + +int main(int argc, char** argv) { + for (int i = 10; i > 0; i--) { + printf("%2d\n", i); + } + printf("%s\n", "Launch!"); + return 0; +} diff --git a/Assignment_008/solution/readme.md b/Assignment_008/solution/readme.md new file mode 100644 index 0000000..be1158e --- /dev/null +++ b/Assignment_008/solution/readme.md @@ -0,0 +1,5 @@ +# Lösung: Countdown + +Lösung: + + * [countdown.c](countdown.c) diff --git a/Assignment_009/readme.md b/Assignment_009/readme.md new file mode 100644 index 0000000..f256a61 --- /dev/null +++ b/Assignment_009/readme.md @@ -0,0 +1,24 @@ +# Größe von Datentypen + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie ein Programm, das die Größe von verschiedenen Datentypen mithilfe von `sizeof` ausgibt: + + * `char` + * `short` + * `int` + * `long` + * `long long` + * `float` + * `double` + +Geben Sie dann noch die Größe eines Arrays von `int`-Werten und eines Strings aus. + +Überlegen Sie, wie man vielleicht mit `sizeof` die Länge des Arrays berechnen kann. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_009/solution/readme.md b/Assignment_009/solution/readme.md new file mode 100644 index 0000000..d879967 --- /dev/null +++ b/Assignment_009/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Größe von Datentypen + +Lösung: [sizeof.c](sizeof.c) diff --git a/Assignment_009/solution/sizeof.c b/Assignment_009/solution/sizeof.c new file mode 100644 index 0000000..71171ea --- /dev/null +++ b/Assignment_009/solution/sizeof.c @@ -0,0 +1,22 @@ +#include + +int main(int argc, char *argv[]) +{ + int array[] = { 1, 2, 3, 4, 5 }; + char name[] = "Thomas"; + + printf("The size of a short is : %ld\n", sizeof(short)); + printf("The size of an int : %ld\n", sizeof(int)); + printf("The size of a long is : %ld\n", sizeof(long)); + printf("The size of a long long is : %ld\n", sizeof(long long)); + printf("The size of a float is : %ld\n", sizeof(float)); + printf("The size of a double is : %ld\n", sizeof(double)); + printf("The size of areas (int[]) : %ld\n", sizeof(array)); + printf("The number of ints in array: %ld\n", + sizeof(array) / sizeof(int)); + printf("The size of a char : %ld\n", sizeof(char)); + printf("The size of name (char[]) : %ld\n", sizeof(name)); + printf("The number of chars : %ld\n", sizeof(name) / sizeof(char)); + + return 0; +} diff --git a/Assignment_010/readme.md b/Assignment_010/readme.md new file mode 100644 index 0000000..ee81dd5 --- /dev/null +++ b/Assignment_010/readme.md @@ -0,0 +1,12 @@ +# Vertauschen von zwei Integer-Werte + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie eine Funktion `swap`, der man zwei `int`-Werte übergibt und welche die Werte vertauscht. Ruft man die Funktion also mit zwei Variablen `a` und `b` auf, hat danach die Variable `a` den Wert der Variablen `b` und umgekehrt + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_010/solution/readme.md b/Assignment_010/solution/readme.md new file mode 100644 index 0000000..3616b65 --- /dev/null +++ b/Assignment_010/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Vertauschen von zwei Integer-Werte + +Lösung: [swap.c](swap.c) diff --git a/Assignment_010/solution/swap.c b/Assignment_010/solution/swap.c new file mode 100644 index 0000000..ddddd9d --- /dev/null +++ b/Assignment_010/solution/swap.c @@ -0,0 +1,30 @@ +/** + * Vertauschen von zwei Integer-Werte. + * + * Schreiben Sie eine Funktion `swap`, der man zwei `int`-Werte + * übergibt und welche die Werte vertauscht. Ruft man die Funktion + * also mit zwei Variablen `a` und `b` auf, hat danach die Variable + * `a` den Wert der Variablen `b` und umgekehrt. + */ +#include +#include + +void swap(int *a, int *b) { + int tmp = *a; + *a = *b; + *b = tmp; +} + +int main(int argc, char** argv) { + int a = 23; + int b = 42; + + assert(a == 23 && b == 42); + + swap(&a, &b); + + assert(a == 42 && b == 23); + + puts("OK"); + return 0; +} diff --git a/Assignment_011/readme.md b/Assignment_011/readme.md new file mode 100644 index 0000000..dfa2062 --- /dev/null +++ b/Assignment_011/readme.md @@ -0,0 +1,21 @@ +# Leet Speak + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie eine Funktion `leet`, welche eine Zeichenkette übergeben bekommt und diese in Leet-Speak umwandelt. Die Funktion gibt eine neue Zeichenkette zurück, die Ersetzungen entsprechend der folgenden Tabelle enthält: + + - a, A -> 4 + - e, E -> 3 + - l, L -> 1 + - o, O -> 0 + - s, S -> 5 + - t, T -> 7 + +So wird z.B. aus dem String `Leet Speak` der String `1337 5p34k`. Die neue Zeichenkette soll so angelegt werden, dass die Aufrufer der Funktion diese danach mit `free` wieder freigeben können. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_011/solution/leet.c b/Assignment_011/solution/leet.c new file mode 100644 index 0000000..063d5d0 --- /dev/null +++ b/Assignment_011/solution/leet.c @@ -0,0 +1,79 @@ +/** + * Leet Speak. + * + * Schreiben Sie eine Funktion `leet`, welche eine Zeichenkette übergeben + * bekommt und diese in Leet-Speak umwandelt. Die Funktion gibt eine + * neue Zeichenkette zurück, die Ersetzungen entsprechend der folgenden + * Tabelle enthält: + * + * - a, A -> 4 + * - e, E -> 3 + * - l, L -> 1 + * - o, O -> 0 + * - s, S -> 5 + * - t, T -> 7 + * + * So wird z.B. aus dem String `Leet Speak` der String `1337 5p34k`. + * + * Die neue Zeichenkette soll so angelegt werden, dass die Aufrufer der Funktion + * diese danach mit `free` wieder freigeben können. + */ +#include +#include +#include +#include + +char* leet(const char* text) { + char* cpy = strdup(text); + char* p = cpy; + + while (*p) { + switch (*p) { + case 'a': + case 'A': + *p = '4'; + break; + case 'e': + case 'E': + *p = '3'; + break; + case 'l': + case 'L': + *p = '1'; + break; + case 'o': + case 'O': + *p = '0'; + break; + case 's': + case 'S': + *p = '5'; + break; + case 't': + case 'T': + *p = '7'; + break; + } + p++; + } + + return cpy; +} + +void test_leet(const char* text, const char* expected) { + char* result = leet(text); + assert(strcmp(result, expected) == 0); + free(result); +} + +int main(int argc, char** argv) { + test_leet("hello", "h3110"); + test_leet("Hello", "H3110"); + test_leet("HELLO", "H3110"); + test_leet("leet", "1337"); + test_leet("LeEt", "1337"); + test_leet("Leet Speak", "1337 5p34k"); + test_leet("mmmmm", "mmmmm"); + puts("OK"); + return 0; +} diff --git a/Assignment_011/solution/readme.md b/Assignment_011/solution/readme.md new file mode 100644 index 0000000..3aa5614 --- /dev/null +++ b/Assignment_011/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Leet Speak + +Lösung: [leet.c](leet.c) diff --git a/Assignment_012/readme.md b/Assignment_012/readme.md new file mode 100644 index 0000000..6ff0613 --- /dev/null +++ b/Assignment_012/readme.md @@ -0,0 +1,14 @@ +# Array ausgeben + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie eine Funktion `print_array`, welche die Elemente eines übergebenen Arrays von `int`-Werten ausgibt. Die Funktion bekommt die Länge des Arrays übergeben. + +Verwenden Sie Indices [x] beim Zugriff auf die einzelnen Elemente. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_012/solution/print_array.c b/Assignment_012/solution/print_array.c new file mode 100644 index 0000000..1dd0f6b --- /dev/null +++ b/Assignment_012/solution/print_array.c @@ -0,0 +1,22 @@ +/** + * Array ausgeben. + * + * Schreiben Sie eine Funktion `print_array`, welche die Elemente + * eines übergebenen Arrays von `int`-Werten ausgibt. Die Funktion + * bekommt die Länge des Arrays übergeben. + * + * Verwenden Sie Indices [x] beim Zugriff auf die einzelnen Elemente. + */ +#include + +void print_array(int* array, size_t len) { + for (int i = 0; i < len; i++) { + printf("%d\n", array[i]); + } +} + +int main(int argc, char** argv) { + int values[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + print_array(values, 8); + return 0; +} diff --git a/Assignment_012/solution/readme.md b/Assignment_012/solution/readme.md new file mode 100644 index 0000000..b0d377f --- /dev/null +++ b/Assignment_012/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Array ausgeben + +Lösung: [print_array.c](print_array.c) diff --git a/Assignment_013/readme.md b/Assignment_013/readme.md new file mode 100644 index 0000000..351bb26 --- /dev/null +++ b/Assignment_013/readme.md @@ -0,0 +1,14 @@ +# Array mit Pointer-Arithmetik ausgeben + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie eine Funktion `print_array`, welche die Elemente eines übergebenen Arrays von `int`-Werten ausgibt. Die Funktion soll solange laufen, bis sie ein Element mit dem Wert `0` antrifft. + +Verwenden Sie Pointer-Arithmetik, um über die Elemente des Arrays zu laufen, d.h. verzichten Sie auf die Verwendung von Indices [x] beim Zugriff. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_013/solution/print_array_pointer.c b/Assignment_013/solution/print_array_pointer.c new file mode 100644 index 0000000..2be38b7 --- /dev/null +++ b/Assignment_013/solution/print_array_pointer.c @@ -0,0 +1,25 @@ +/** + * Array mit Pointer-Arithmetik ausgeben. + * + * Schreiben Sie eine Funktion `print_array`, welche die Elemente + * eines übergebenen Arrays von `int`-Werten ausgibt. Die Funktion + * soll solange laufen, bis sie ein Element mit dem Wert `0` antrifft. + * + * Verwenden Sie Pointer-Arithmetik, um über die Elemente des Arrays + * zu laufen, d.h. verzichten Sie auf die Verwendung von Indices + * [x] beim Zugriff. + */ +#include + +void print_array(int* array) { + int *p = array; /* pointer to first element */ + while (*p) { + printf("%d\n", *p++); + } +} + +int main(int argc, char** argv) { + int values[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + print_array(values); + return 0; +} diff --git a/Assignment_013/solution/readme.md b/Assignment_013/solution/readme.md new file mode 100644 index 0000000..c81eba7 --- /dev/null +++ b/Assignment_013/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Array mit Pointer-Arithmetik ausgeben + +Lösung: [print_array_pointer.c](print_array_pointer.c) diff --git a/Assignment_014/readme.md b/Assignment_014/readme.md new file mode 100644 index 0000000..edd065a --- /dev/null +++ b/Assignment_014/readme.md @@ -0,0 +1,35 @@ +# String-Verarbeitung + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Implementieren Sie eine Funktion mit dem Namen `manipulate_text`, die einen Parameter vom Typ `char*` erhält. Die Funktion soll den übergebenen Text manipulieren und die folgenden Operationen durchführen: + + 1. Kopieren Sie den Text in einen neuen String mithilfe der Funktion `strcpy`. + 2. Prüfen Sie, ob der Text bereits das Wort `great` enthält. + - ist der String enthalten, hängen Sie `" again"` an den Text an. + - ist der String nicht enthalten, hängen Sie `" great again"` an. + +Nach der Manipulation gibt die Funktion das Ergebnis aus. Sie hat keinen Rückgabewert. + +In der `main`-Funktion soll der Benutzer aufgefordert werden, einen Text einzugeben. Der eingegebene Text soll an die Funktion `manipulate_text` übergeben werden, um die Operationen durchzuführen. Anschließend sollen der ursprüngliche Text und der manipulierte Text ausgegeben werden. + +Eine beispielhafte Benutzung des Programms sieht wie folgt aus: + +```console +Geben Sie einen Text ein: Make America +Original Text: Make America +Manipulierter Text: Make America great again +``` + +```console +Geben Sie einen Text ein: Make America great +Original Text: Make America great +Manipulierter Text: Make america great again +```` + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_014/solution/readme.md b/Assignment_014/solution/readme.md new file mode 100644 index 0000000..cee4961 --- /dev/null +++ b/Assignment_014/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: String-Verarbeitung + +Lösung: [strings.c](strings.c) diff --git a/Assignment_014/solution/strings.c b/Assignment_014/solution/strings.c new file mode 100644 index 0000000..9812aba --- /dev/null +++ b/Assignment_014/solution/strings.c @@ -0,0 +1,31 @@ +#include +#include +#include + +void manipulate_text(char* text) { + char copiedText[100]; + + strcpy(copiedText, text); + + if (strstr(copiedText, "great") != NULL) { + strcat(copiedText, " again"); + } + else { + strcat(copiedText, " great again"); + } + + printf("Manipulierter Text: %s\n", copiedText); +} + +int main() { + char text[100]; + + printf("Geben Sie einen Text ein: "); + fgets(text, sizeof(text), stdin); + *(strchr(text, '\n')) = '\0'; // Zeilenumbruch entfernen + + printf("Original Text: %s\n", text); + manipulate_text(text); + + return 0; +} diff --git a/Assignment_015/readme.md b/Assignment_015/readme.md new file mode 100644 index 0000000..2ae144b --- /dev/null +++ b/Assignment_015/readme.md @@ -0,0 +1,12 @@ +# String umdrehen + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie eine Funktion `reverse`, der man einen String übergibt und die diesen String dann umdreht. So wird z.B. aus dem String `abcd` der String `dcba`. Die Funktion verändert den ihr übergebenen String direkt. Der Aufrufer der Funktion muss dafür Sorge tragen, dass der übergebene String schreibbar ist. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_015/solution/readme.md b/Assignment_015/solution/readme.md new file mode 100644 index 0000000..12b7f97 --- /dev/null +++ b/Assignment_015/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: String umdrehen + +Lösung: [reverse.c](reverse.c) diff --git a/Assignment_015/solution/reverse.c b/Assignment_015/solution/reverse.c new file mode 100644 index 0000000..1daf37b --- /dev/null +++ b/Assignment_015/solution/reverse.c @@ -0,0 +1,38 @@ +/** + * String umdrehen. + * + * Schreiben Sie eine Funktion `reverse`, der man einen String übergibt und + * die diesen String dann umdreht. So wird z.B. aus dem String `abcd` der + * String `dcba`. Die Funktion verändert den ihr übergebenen String direkt. + * Der Aufrufer der Funktion muss dafür Sorge tragen, dass der übergebene + * String schreibbar ist. + */ +#include +#include +#include + +void reverse(char* chars) { + int len = strlen(chars); + for (int i = 0; i < len / 2; i++) { + char tmp = chars[i]; + chars[i] = chars[len - i - 1]; + chars[len -i - 1] = tmp; + } +} + +void test_reverse(const char* input, const char* expected) { + char buffer[255]; + strcpy(buffer, input); + reverse(buffer); + assert(strcmp(buffer, expected) == 0); +} + +int main(int argc, char** argv) { + test_reverse("hello world", "dlrow olleh"); + test_reverse("helloworld", "dlrowolleh"); + test_reverse("a", "a"); + test_reverse("ab", "ba"); + test_reverse("abc", "cba"); + puts("OK"); + return 0; +} diff --git a/Assignment_016/readme.md b/Assignment_016/readme.md new file mode 100644 index 0000000..27645d4 --- /dev/null +++ b/Assignment_016/readme.md @@ -0,0 +1,12 @@ +# Vararg Funktion schreiben + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie ein Funktion `sum_numbers`, der man eine beliebige Anzahl von Integer-Werten übergeben kann und die dann die Summe der Werte zurückgibt. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_016/solution/readme.md b/Assignment_016/solution/readme.md new file mode 100644 index 0000000..01d2626 --- /dev/null +++ b/Assignment_016/solution/readme.md @@ -0,0 +1,5 @@ +# Lösung: Vararg Funktion schreiben + +Lösung: + + * [vararg_sum.c](vararg_sum.c) \ No newline at end of file diff --git a/Assignment_016/solution/vararg_sum.c b/Assignment_016/solution/vararg_sum.c new file mode 100644 index 0000000..d65c12e --- /dev/null +++ b/Assignment_016/solution/vararg_sum.c @@ -0,0 +1,32 @@ +/** + * Vararg Funktion schreiben + * + * Schreiben Sie ein Funktion `sum_numbers`, der + * man eine beliebige Anzahl von Integer-Werten übergeben + * kann und die dann die Summe der Werte zurückgibt. + */ +#include +#include +#include + +int sum_numbers(int count, ...) { + int result = 0; + va_list args; + va_start(args, count); + + for (int i = 0; i < count; i++) { + result += va_arg(args, int); + } + + va_end(args); + + return result; +} + +int main(int argc, char** argv) { + assert(sum_numbers(1, 1) == 1); + assert(sum_numbers(2, 1, 2) == 3); + assert(sum_numbers(3, 1, 2, 3) == 6); + assert(sum_numbers(4, 1, 2, 3, 10) == 16); + return 0; +} diff --git a/Assignment_017/readme.md b/Assignment_017/readme.md new file mode 100644 index 0000000..920b6b7 --- /dev/null +++ b/Assignment_017/readme.md @@ -0,0 +1,23 @@ +# typedef verwenden + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie ein Programm, das `typedef` verwendet, um einen benutzerdefinierten Datentyp `int_pointer_t` zu erstellen. Der benutzerdefinierte Datentyp soll einen Zeiger auf eine ganze Zahl ohne Vorzeichen darstellen. + +Schreiben Sie eine Funktion namens `double_number`, die einen Parameter vom Typ `int_pointer_t` erhält und den Wert, auf den der Zeiger zeigt, verdoppelt. + +Schreiben Sie eine `main`-Funktion, in der Sie eine Variable vom Typ `int_pointer_t` erstellen und sie auf eine ganze Zahl initialisieren. Rufen Sie dann die Funktion `double_number` auf und übergeben Sie die erstellte Variable als Parameter. Geben Sie schließlich den neuen Wert der Zahl auf der Konsole aus. + +Ihr Programm sollte die folgende Ausgabe erzeugen: + +```console +Ursprüngliche Zahl: 5 +Verdoppelte Zahl: 10 +``` + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_017/solution/readme.md b/Assignment_017/solution/readme.md new file mode 100644 index 0000000..335db71 --- /dev/null +++ b/Assignment_017/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: typedef verwenden + +Lösung: [typedef.c](typedef.c) \ No newline at end of file diff --git a/Assignment_017/solution/typedef.c b/Assignment_017/solution/typedef.c new file mode 100644 index 0000000..bfc1e75 --- /dev/null +++ b/Assignment_017/solution/typedef.c @@ -0,0 +1,18 @@ +#include + +typedef unsigned int* int_pointer_t; + +void double_number(int_pointer_t value) { + *value *= 2; +} + +int main(int argc, char** argv) { + unsigned int value = 5; + int_pointer_t zahlPointer = &value; + + printf("Ursprüngliche Zahl: %d\n", value); + double_number(zahlPointer); + printf("Verdoppelte Zahl: %d\n", value); + + return 0; +} diff --git a/Assignment_018/readme.md b/Assignment_018/readme.md new file mode 100644 index 0000000..00b650f --- /dev/null +++ b/Assignment_018/readme.md @@ -0,0 +1,37 @@ +# Dynamische Speicherverwaltung mit malloc und free + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie ein C-Programm, das die Funktionen `malloc` und `free` zur dynamischen Speicherallokation und -freigabe verwendet. Das Programm soll ein dynamisches Array von ganzen Zahlen erstellen. + +Schreiben Sie eine Funktion namens `create_array`, die einen Parameter erhält, der die Größe des Arrays angibt. Die Funktion soll dynamisch Speicher für das Array reservieren und die Adresse des reservierten Speichers zurückgeben. + +Schreiben Sie eine Funktion namens `print_array`, die Elemente des Arrays auf der Konsole ausgibt. + +Schreiben Sie eine Funktion namens `free_array`, welche den Speicher freigibt, der für das Array reserviert wurde. + +In der `main`-Funktion soll die Funktion `create_array` aufgerufen werden, um ein dynamisches Array mit einer vom Benutzer eingegebenen Größe zu erstellen. Anschließend sollen einige Beispieldaten abgefragt und in das Array geschrieben werden. Die Funktion `print_array` soll aufgerufen werden, um die Elemente des Arrays anzuzeigen. Zum Schluss soll die Funktion `free_array` aufgerufen werden, um den reservierten Speicher freizugeben. + +Eine beispielhafter Programmablauf könnte wie folgt aussehen: + +```console +Geben Sie die Größe des Arrays ein: 4 +Geben Sie die Elemente des Arrays ein: +Element 0: 10 +Element 1: 11 +Element 2: 12 +Element 3: 13 + +Das Array enthält folgende Elemente: +Element 0: 10 +Element 1: 11 +Element 2: 12 +Element 3: 13 +``` + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_018/solution/malloc_free.c b/Assignment_018/solution/malloc_free.c new file mode 100644 index 0000000..d98574b --- /dev/null +++ b/Assignment_018/solution/malloc_free.c @@ -0,0 +1,39 @@ +#include +#include + +int* create_array(int size) { + int* array = (int*) malloc(size * sizeof(int)); + return array; +} + +void print_array(const int* array, int size) { + for (int i = 0; i < size; i++) { + printf("Element %d: %d\n", i, array[i]); + } +} + +void free_array(int* array) { + free(array); +} + +int main(int argc, char** argv) { + int size; + + printf("Geben Sie die Größe des Arrays ein: "); + scanf("%d", &size); + + int* array = create_array(size); + + printf("Geben Sie die Elemente des Arrays ein:\n"); + for (int i = 0; i < size; i++) { + printf("Element %d: ", i); + scanf("%d", &array[i]); + } + + printf("Das Array enthält folgende Elemente:\n"); + print_array(array, size); + + free_array(array); + + return 0; +} diff --git a/Assignment_018/solution/readme.md b/Assignment_018/solution/readme.md new file mode 100644 index 0000000..5f1a4cd --- /dev/null +++ b/Assignment_018/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Dynamische Speicherverwaltung mit malloc und free + +Lösung: [malloc_free.c](malloc_free.c) \ No newline at end of file diff --git a/Assignment_019/readme.md b/Assignment_019/readme.md new file mode 100644 index 0000000..baa47d4 --- /dev/null +++ b/Assignment_019/readme.md @@ -0,0 +1,19 @@ +# Funktionspointer benutzen + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie eine Funktion `print_data`, der eine Liste von Strings und eine Ausgabefunktion als Funktionspointer übergeben wird. `print_data` läuft über die Strings und übergibt diese dann der Ausgabefunktion für die eigentliche Ausgabe. + +Schreiben Sie zwei verschiedene Ausgabefunktionen: + + * `to_console` welche den String einfach auf der Konsole ausgibt und + * `to_console_ucase` welche den String auf der Konsole ausgibt aber vorher in Großbuchstaben umwandelt. + +Testen Sie Ihr Programm mit `print_data` und beiden Ausgabefunktionen. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_019/solution/function_pointer.c b/Assignment_019/solution/function_pointer.c new file mode 100644 index 0000000..4d3d17b --- /dev/null +++ b/Assignment_019/solution/function_pointer.c @@ -0,0 +1,73 @@ +/** + * Funktionspointer verwenden + * + * Schreiben Sie eine Funktion `print_data`, der eine Liste + * von Strings und eine Ausgabefunktion als Funktionspointer + * übergeben wird. `print_data` läuft über die Strings und + * übergibt diese dann der Ausgabefunktion für die eigentliche + * Ausgabe. + * + * Schreiben Sie zwei verschiedene Ausgabefunktionen: + * + * - `to_console` welche den String einfach auf der Konsole ausgibt und + * - `to_console_ucase` welche den String auf der Konsole ausgibt + * aber vorher in Großbuchstaben umwandelt. + * + * Testen Sie Ihr Programm mit `print_data` und beiden Ausgabefunktionen. + */ +#include +#include +#include +#include + +// Funktionspointer-Typ für Ausgabefunktionen +typedef void (*OutputFunction)(const char*); + +// Funktion, die die Datenliste durchläuft und die angegebene Ausgabefunktion aufruft +void print_data(const char* data[], int count, OutputFunction outputFunc) { + for (int i = 0; i < count; i++) { + outputFunc(data[i]); + } +} + +char *to_uppercase(const char *lower) { + int len = strlen(lower); + + // Allocate space for new string + char *upper = (char *) malloc(sizeof(char) * (len + 1)); + + // Add null terminator to string + upper[len] = '\0'; + + // Convert characters to uppercase one by one + for (int i = 0; i < len; i++) { + upper[i] = toupper(lower[i]); + } + + return upper; +} + +// Ausgabefunktion, die die Daten auf der Konsole ausgibt +void to_console(const char* data) { + printf("%s\n", data); +} + +// Ausgabefunktion, die die Daten in eine Datei schreibt +void to_console_ucase(const char* data) { + char *ucase = to_uppercase(data); + to_console(ucase); + free(ucase); +} + +int main() { + const char* data[] = { "Daten 1", "Daten 2", "Daten 3" }; + int count = sizeof(data) / sizeof(data[0]); + + // Funktionszeiger für Konsolenausgabe + print_data(data, count, to_console); + + // Funktionszeiger für Dateiausgabe + print_data(data, count, to_console_ucase); + + return 0; +} diff --git a/Assignment_019/solution/readme.md b/Assignment_019/solution/readme.md new file mode 100644 index 0000000..6379c48 --- /dev/null +++ b/Assignment_019/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Funktionspointer benutzen + +Lösung: [function_pointer.c](function_pointer.c) \ No newline at end of file diff --git a/Assignment_020/readme.md b/Assignment_020/readme.md new file mode 100644 index 0000000..ab67677 --- /dev/null +++ b/Assignment_020/readme.md @@ -0,0 +1,39 @@ +# Struct verwenden + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Entwerfen Sie ein C-Programm, das eine `struct` verwendet, um Informationen über verschiedene Bücher zu speichern. Verwenden Sie das Schlüsselwort `typedef`, um diese Struktur als `book_t` wiederverwenden zu können. + +Erstellen Sie eine Struktur, die die folgenden Eigenschaften enthält: + + * Titel (Zeichenkette) + * Autor (Zeichenkette) + * Erscheinungsjahr (ganze Zahl) + * ISBN (Zeichenkette) + +Schreiben Sie eine Funktion namens `print_book`, die ein `buch_t` als Parameter nimmt und die Details des Buches auf der Konsole ausgibt. + +Schreiben Sie eine `main`-Funktion, die eine Array von Büchern erstellt und mit einigen Beispieldaten initialisiert. Rufen Sie dann die Funktion `print_book` für jedes Buch im Array auf. + +Ihr Programm sollte die folgende Ausgabe erzeugen: + +```console +Buch 1 +Titel: Harry Potter und der Stein der Weisen +Autor: J.K. Rowling +Erscheinungsjahr: 1997 +ISBN: 978-3551354013 + +Buch 2 +Titel: Der Herr der Ringe +Autor: J.R.R. Tolkien +Erscheinungsjahr: 1954 +ISBN: 978-3608939842 +``` + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_020/solution/readme.md b/Assignment_020/solution/readme.md new file mode 100644 index 0000000..0b2f61f --- /dev/null +++ b/Assignment_020/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Struct verwenden + +Lösung: [struct_book.c](struct_book.c) \ No newline at end of file diff --git a/Assignment_020/solution/struct_book.c b/Assignment_020/solution/struct_book.c new file mode 100644 index 0000000..cfea08b --- /dev/null +++ b/Assignment_020/solution/struct_book.c @@ -0,0 +1,39 @@ +#include + +typedef struct { + char *titel; + char *autor; + int erscheinungsjahr; + char *isbn; +} book_t; + +void print_book(book_t *book) { + printf("Titel: %s\n", book->titel); + printf("Autor: %s\n", book->autor); + printf("Erscheinungsjahr: %d\n", book->erscheinungsjahr); + printf("ISBN: %s\n", book->isbn); + printf("\n"); +} + +int main(int argc, char** argv) { + book_t books[] = { + { + "Harry Potter und der Stein der Weisen", + "J.K. Rowling", + 1997, + "978-3551354013" + }, + { + "Der Herr der Ringe", + "J.R.R. Tolkien", + 1954, + "978-3608939842" + } }; + + for (int i = 0; i < 2; i++) { + printf("Buch %d\n", i + 1); + print_book(&books[i]); + } + + return 0; +} diff --git a/Assignment_021/readme.md b/Assignment_021/readme.md new file mode 100644 index 0000000..db76277 --- /dev/null +++ b/Assignment_021/readme.md @@ -0,0 +1,23 @@ +# Union verwenden + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie ein Programm, das eine Union verwendet, um entweder eine ganze Zahl oder eine Gleitkommazahl zu speichern. + +Erstellen Sie eine Union mit dem Namen `number_t`, die die folgenden Mitglieder enthält: + + * `ganzzahl` (ganze Zahl) + * `gleitkommazahl` (Fließkommazahl) + +Definieren Sie eine `enum` namens `number_type`, mit den Elementen `GANZZAHL` und `GLEITKOMMAZAHL`. + +Schreiben Sie eine Funktion namens `print_number`, die ein `number_t` und einen Parameter vom Typ `number_type` erhält, der den gewählten Datentyp angibt. Die Funktion soll den Inhalt der Union je nach gewähltem Datentyp auf der Konsole ausgeben. + +Schreiben Sie eine `main`-Funktion, in der Sie eine Variable vom Typ `number_t` erstellen und einige Beispieldaten in die Union speichern. Rufen Sie dann die Funktion `print_number` auf und übergeben Sie das Union-Mitglied und den gewählten Datentyp, um den Inhalt der Union anzuzeigen. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_021/solution/readme.md b/Assignment_021/solution/readme.md new file mode 100644 index 0000000..71cf468 --- /dev/null +++ b/Assignment_021/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Union verwenden + +Lösung: [union.c](union.c) \ No newline at end of file diff --git a/Assignment_021/solution/union.c b/Assignment_021/solution/union.c new file mode 100644 index 0000000..7d82d88 --- /dev/null +++ b/Assignment_021/solution/union.c @@ -0,0 +1,48 @@ +#include + +typedef union { + int ganzzahl; + float gleitkommazahl; +} number_t; + +typedef enum { + GANZZAHL, + GLEITKOMMAZAHL +} number_type; + +void print_number(number_t zahl, number_type typ) { + switch (typ) { + case GANZZAHL: + printf("Ganzzahl: %d\n", zahl.ganzzahl); + break; + case GLEITKOMMAZAHL: + printf("Gleitkommazahl: %.2f\n", zahl.gleitkommazahl); + break; + default: + printf("Ungültiger Typ\n"); + break; + } +} + +int main() { + number_t zahl; + number_type typ; + + printf("Wählen Sie den number_type (0 für Ganzzahl, 1 für Gleitkommazahl): "); + scanf("%d", (int*)&typ); // Eingabe als int, dann Umwandlung in enum number_type + + if (typ == GANZZAHL) { + printf("Geben Sie eine Ganzzahl ein: "); + scanf("%d", &zahl.ganzzahl); + } else if (typ == GLEITKOMMAZAHL) { + printf("Geben Sie eine Gleitkommazahl ein: "); + scanf("%f", &zahl.gleitkommazahl); + } else { + printf("Ungültiger Typ\n"); + return 0; + } + + print_number(zahl, typ); + + return 0; +} diff --git a/Assignment_022/readme.md b/Assignment_022/readme.md new file mode 100644 index 0000000..59e825b --- /dev/null +++ b/Assignment_022/readme.md @@ -0,0 +1,152 @@ +# Assignment: Vektor (heap-basiert) + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Ihre Rakete hat das Raumschiff der Kryptonier getroffen und es ist mit einer lauten Explosion vom Himmel gefallen. Sie fühlen sich wie Will Smith in [Independence Day](https://www.imdb.com/title/tt0116629). + +**Ziel**: Ziel dieses Assignments ist es, die Vektoren der letzten Woche auf ein anderes Speichermodell umzubauen. + +## Vector: Struktur und Funktionen + +### Beschreibung des Programms + +Die hier zu implementierende Aufgabe orientiert sich in der Funktionsweise an den stack-basierten Vektoren des letzten Assignments, allerdings mit dem Unterschied, dass die Speicherallokation jetzt von den Funktionen Ihrer Vektor-Bibliothek durchgeführt wird. + +Implementieren Sie eine Struktur `Vector` und die dazugehörigen Funktionen in einer Datei `vector_heap.c` mit deren Hilfe man auf dreidimensionalen Vektoren die wichtigsten Operationen durchführen kann. Drei Dimensionen reichen, um die Flugbahn der Rakete zu berechnen! + +Die Komponenten x, y und z sollen als `double` gespeichert werden. + +Ihre Implementierung soll die folgenden Aktionen unterstützen: + + * `vec_new` - Erzeugen eines neuen Vektors mit Daten für die drei Komponenten + * `vec_new_null` - Erzeugt einen Nullvektor (alle drei Komponenten [x,y,z] sind 0) + * `vec_add` - Addieren zweier Vektoren + * `vec_sub` - Subtrahieren zweier Vektoren + * `vec_mul_scalar` - Multiplikation des Vektors mit einem Skalar + * `vec_mul_dot` - Skalarmultiplikation zweier Vektoren + * `vec_mul_cross` - Kreuzprodukt zweier Vektoren + * `vec_norm` - Erzeugung des Einheitsvektors aus einem gegebenen Vektor (d.h. Vektor der Länge 1 mit derselben Richtung wie der ursprüngliche Vektor). Beachten Sie, dass vom Nullvektor kein Einheitsvektor erzeugt werden kann. In diesem Fall müssen Sie eine entsprechende Rückgabe machen, um den Fehler anzuzeigen. + * `vec_length` - Berechnung des Betrages (der Länge) eines Vektors + * `vec_collinear` - Test, ob zwei Vektoren kollinear (parallel oder antiparallel) sind + * `vec_equals` - Test, ob zwei Vektoren gleich sind + * `vec_print` - Ausgabe des Vektors auf der Console + * `vec_to_s` - Umwandlung des Vektors in einen String + +Keine der Funktionen verändert die übergebenen Vektoren, sondern erzeugt einen neuen Vektor und gibt diesen zurück. Siehe hierzu das Beispiel unten. + +Bei einer C-Bibliothek muss man sich entscheiden, wer für die Allokation des Speichers zuständig ist. Hier entscheiden wir uns dafür, dass die Bibliothek den Speicher beschafft und der Verwender ihn wieder freigeben muss. +Auch die `vec_to_str`-Funktion beschafft Speicher für den String per `malloc`, den der Verwender per `free` wieder freigeben muss. Das folgende Beispiel zeigt, wie Ihre Vektor-Bibliothek zu benutzen ist: + +```c +Vector *v1, *v2, *v3, *v4, *v5; +char *result; + +/* Vektoren erzeugen */ +v1 = vec_new( 10.0, 20.0, 30.0); +v2 = vec_new(-20.0, 99.0, 38.0); + +/* Kreuzprodukt berechnen. v1 und v2 bleiben unverändert, + Ergebnis wird als neuer Vektor (v3) zurück gegeben. */ +v3 = vec_mul_cross(v1, v2); + +/* Ergebnis ausgeben */ +result = vec_to_str(v3); +printf("Das Ergebnis ist: %s\n", result); +free(result); + +/* Speicher für die Vektoren wieder freigeben */ +free(v3); +free(v2); +free(v1); +``` + +Schreiben Sie eine Header-Datei `vector_heap.h`, welche die exportierten Funktionen als Prototypen enthält. Diese werden wir für die Tests benötigen. Kommentieren Sie die Funktionen ausreichend. + + +## Tests + +Überprüfen Sie die Funktionalität Ihrer Implementierung mit entsprechenden Unit-Tests (Datei `vector_heap_test.c`) und weisen Sie mit diesen Tests nach, dass die implementierten Operationen richtig funktionieren. + +Für die Unit-Tests steht Ihnen eine ganz einfache Testbibliothek über das Header-File `minitest.h` zur Verfügung. Die Datei `vector_heap_test.c` enthält ein Beispiel für die Benutzung. Verwenden Sie das dort benutzte Schema und fügen Sie Ihre Tests hinzu. + +Verwenden Sie bitte __mindestens__ die folgenden Testdaten/Testfälle. + +### Multiplikation mit einem Skalar + + * `[1, -5, 3] * 6 = [ 6, -30, 18 ]` + * `[ 1, -5, 3 ] * -3 = [ -3, 15, -9 ]` + + +### Skalarprodukt zweier Vektoren + + * `[ 1, 2, 3 ] * [ -7, 8, 9 ] = 36` + * `[ -5, 9, 7 ] * [ 10, 3, 8 ] = 33` + + +### Addition und Subtraktion + + * `[ 4, 0, 8 ] + [ -1, 4, 7 ] = [ 3, 4, 15 ]` + * `[ 4, 0, 8 ] - [ -1, 4, 7 ] = [ 5, -4, 1 ]` + * `[ 4, 0, 8 ] + [ -1, 4, 7 ] = [ -1, 4, 7 ] + [ 4, 0, 8 ]` + + +### Kreuzprodukt + + * `[ 1, 2, 3 ] x [ -7, 8, 9 ] = [ -6, -30, 22 ]` + * `[ 1, 2, 8 ] x [ 4, 3, 5 ] = [ -14, 27, -5 ]` + + +### Betrag + + * `|[ 1, 1, 1 ]| = sqrt(3)` + * `|[ 5, 4, 3 ]| = sqrt(50)` + + +### Kollinearität + + * `[ 4, 5, 7 ]` und `[ 16, 20, 28 ]` sind kollinear + * `[ 4, 5, 7 ]` und `[ 16, 20, 21 ]` sind nicht kollinear + + +### Komplexere Rechnung + + * `([ -1, 5, -2 ] x [ 2, 1, 2 ]) * [ 2, 0, 5 ] = -31` + + +## Makefile + +Automatisieren Sie das Compilieren und Testen Ihrer Programme mit einem Makefile. Dieses sollte mindestens die folgenden Targets haben: + + * `all` - baut alle Dateien + * `clean` - setzt das Projekt zurück und löscht alle Kompilationsergebnisse + * `test` - führt die oben beschriebenen Tests aus + +Sie benötigen natürlich weitere Targets für die Objektdateien und fertigen Executables. + + +## Benchmark + +Sie haben jetzt zwei verschiedene Implementierungen einer Vektor-Bibliothek. Einmal wird der Speicher von der Bibliothek beschafft, einmal vom Verwender. Die spannende Frage ist, welche Version schneller ist. + +Schreiben Sie für beide Bibliotheken einen kleinen Benchmark, der folgende Schritte wiederholt durchführt und die Zeit für die Ausführung misst. + + * Zwei Vektoren v1 und v2 anlegen. + * Das Kreuzprodukt der Vektoren bestimmen (v3). + * Das Produkt von v2 und v3 bestimmen. + * Den Vektor v3 mit einem Skalar multiplizieren. + * Den Vektor v4 mit einem anderen Skalar multiplizieren. + +Sie können die Funktion `clock()` aus `` verwenden, um eine genaue Zeitmessung durchzuführen. + +Die Benchmarks sollten `vector_heap_benchmark.c` und `vector_stack_benchmark.c` heißen und in den jeweiligen Verzeichnissen der Bibliotheken liegen. Nehmen Sie die Ausführung der Benchmarks auch in die Makefiles auf, sodass sie beim `test`-Target ausgeführt werden. + +Was fällt Ihnen auf? + + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) + * Vektorrechnung: [Wikipedia: Vektor -- Rechenoperationen](https://de.wikipedia.org/wiki/Vektor#Rechenoperationen)typedef \ No newline at end of file diff --git a/Assignment_022/solution/.gitignore b/Assignment_022/solution/.gitignore new file mode 100644 index 0000000..2416a67 --- /dev/null +++ b/Assignment_022/solution/.gitignore @@ -0,0 +1 @@ +obj/ diff --git a/Assignment_022/solution/Makefile b/Assignment_022/solution/Makefile new file mode 100644 index 0000000..0b10244 --- /dev/null +++ b/Assignment_022/solution/Makefile @@ -0,0 +1,51 @@ +CC = gcc +CC_OPTIONS = -Wall + +BIN_DIR = bin +BINARIES = \ + $(BIN_DIR)/countdown \ + $(BIN_DIR)/file_line_no \ + $(BIN_DIR)/hello \ + $(BIN_DIR)/hello_cmdline \ + $(BIN_DIR)/hello_define \ + $(BIN_DIR)/leet \ + $(BIN_DIR)/numberguess \ + $(BIN_DIR)/pipe_rechner \ + $(BIN_DIR)/print_array \ + $(BIN_DIR)/print_array_pointer \ + $(BIN_DIR)/print_file \ + $(BIN_DIR)/read_write \ + $(BIN_DIR)/reverse \ + $(BIN_DIR)/sizeof \ + $(BIN_DIR)/socket_client \ + $(BIN_DIR)/socket_server \ + $(BIN_DIR)/swap \ + $(BIN_DIR)/hello_greeter \ + $(BIN_DIR)/vararg_sum \ + $(BIN_DIR)/argv_printer \ + $(BIN_DIR)/function_pointer \ + $(BIN_DIR)/struct_book \ + $(BIN_DIR)/typedef \ + $(BIN_DIR)/malloc_free \ + $(BIN_DIR)/union \ + $(BIN_DIR)/strings \ + $(BIN_DIR)/threads + + +.PHONY: all +all: $(BINARIES) + +.PHONY: clean +clean: + -rm $(BINARIES) + -rm $(BIN_DIR)/*.o + -rmdir $(BIN_DIR) + +$(BIN_DIR)/%: %.c + mkdir -p $(BIN_DIR) + $(CC) $(CC_OPTIONS) -o $@ $< + +$(BIN_DIR)/hello_greeter: greeter/greeter.c greeter/greeter.h greeter/hello_greeter.c + $(CC) $(CC_OPTIONS) -c greeter/greeter.c -o $(BIN_DIR)/greeter.o + $(CC) $(CC_OPTIONS) -c greeter/hello_greeter.c -o $(BIN_DIR)/hello_greeter.o + $(CC) $(CC_OPTIONS) $(BIN_DIR)/greeter.o $(BIN_DIR)/hello_greeter.o -o $(BIN_DIR)/hello_greeter diff --git a/Assignment_022/solution/benchmark.h b/Assignment_022/solution/benchmark.h new file mode 100644 index 0000000..64a089a --- /dev/null +++ b/Assignment_022/solution/benchmark.h @@ -0,0 +1,6 @@ +#ifndef BENCHMARK_H +#define BENCHMARK_H + +#define RUNS 100000000 + +#endif /* BENCHMARK_H */ \ No newline at end of file diff --git a/Assignment_022/solution/minitest.h b/Assignment_022/solution/minitest.h new file mode 100644 index 0000000..4de137f --- /dev/null +++ b/Assignment_022/solution/minitest.h @@ -0,0 +1,9 @@ +#ifndef MINITEST_H +#define MINITEST_H + +#define mu_in_delta(a, b, delta) (((a) >= ((b) - (delta))) && ((a) <= ((b) + (delta)))) +#define mu_assert(message, test) do { if (!(test)) return message; } while (0) +#define mu_run_test(test) do { char *message = test(); tests_run++; \ + if (message) return message; } while (0) + +#endif /* MINITEST_H */ \ No newline at end of file diff --git a/Assignment_022/solution/readme.md b/Assignment_022/solution/readme.md new file mode 100644 index 0000000..31f48df --- /dev/null +++ b/Assignment_022/solution/readme.md @@ -0,0 +1,11 @@ +# Lösung: Vektor (heap-basiert) + +Lösung: + + * [benchmark.h](benchmark.h) + * [Makefile](Makefile) + * [minitest.h](minitest.h) + * [vector_heap_benchmark.c](vector_heap_benchmark.c) + * [vector_heap.c](vector_heap.c) + * [vector_heap.h](vector_heap.h) + * [vector_heap_test.c](vector_heap_test.c) diff --git a/Assignment_022/solution/vector_heap.c b/Assignment_022/solution/vector_heap.c new file mode 100644 index 0000000..c63c00c --- /dev/null +++ b/Assignment_022/solution/vector_heap.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include "vector_heap.h" + +Vector* vec_new(double x, double y, double z) { + Vector* result = (Vector*) malloc(sizeof(Vector)); + if (!result) { + /* malloc failed */ + return NULL; + } + + result->x = x; + result->y = y; + result->z = z; + + return result; +} + +Vector* vec_new_null() { + return vec_new(0.0, + 0.0, + 0.0); +} + +Vector* vec_mul_scalar(Vector* v, double scalar) { + return vec_new(v->x * scalar, + v->y * scalar, + v->z * scalar); +} + +double vec_mul_dot(Vector* first, Vector *second) { + return first->x * second->x + + first->y * second->y + + first->z * second->z; +} + +Vector* vec_mul_cross(Vector* first, Vector *second) { + return vec_new(first->y * second->z - first->z * second->y, + first->z * second->x - first->x * second->z, + first->x * second->y - first->y * second->x); +} + +Vector* vec_add(Vector* first, Vector *second) { + return vec_new(first->x + second->x, + first->y + second->y, + first->z + second->z); +} + +Vector* vec_sub(Vector* first, Vector *second) { + return vec_new(first->x - second->x, + first->y - second->y, + first->z - second->z); +} + +int vec_equals(Vector* first, Vector *second) { + return (first->x == second->x) + && (first->y == second->y) + && (first->z == second->z); +} + +#define MAX_LENGTH 128 + +char* vec_to_str(Vector* v) { + char* result = (char*) malloc(MAX_LENGTH + 1); + snprintf(result, MAX_LENGTH, "[ %.2f %.2f %.2f ]", v->x, v->y, v->z); + return result; +} + +void vec_print(Vector* v) { + char* str = vec_to_str(v); + printf("%s", str); + free(str); +} + +double vec_length(Vector* v) { + return sqrt(v->x * v->x + + v->y * v->y + + v->z * v->z); +} + +Vector* vec_norm(Vector* v) { + double length = vec_length(v); + + if (length == 0.0) { + /* no norm for a null vector */ + return NULL; + } + + return vec_new(v->x / length, + v->y / length, + v->z / length); +} + +int vec_collinear(Vector* first, Vector* second) { + Vector* cross = vec_mul_cross(first, second); + Vector* null = vec_new_null(); + int result = vec_equals(null, cross); + + free(cross); + free(null); + + return result; +} diff --git a/Assignment_022/solution/vector_heap.h b/Assignment_022/solution/vector_heap.h new file mode 100644 index 0000000..753b634 --- /dev/null +++ b/Assignment_022/solution/vector_heap.h @@ -0,0 +1,144 @@ +#ifndef VECTOR_HEAP_H +#define VECTOR_HEAP_H + +/** + * Struktur zur Darstellung eines dreidimensionalen Vektors. + */ +typedef struct { + double x; + double y; + double z; +} Vector; + +/** + * Erzeugt einen neuen Vektor mit den angegebenen Elementen. + * + * Verwender müssen den Speicher mit free wieder freigeben. + * + * @param x die x-Komponente des Vektors + * @param y die y-Komponente des Vektors + * @param z die z-Komponente des Vektors + * @return der erzeugte Vektor + */ +Vector* vec_new(double x, double y, double z); + +/** + * Erzeugt einen Vektor mit dem Wert 0 für alle Komponenten und erzeugt + * so den Nullvektor. + * + * Verwender müssen den Speicher mit free wieder freigeben. + * + * @return der erzeugte Vektor + */ +Vector* vec_new_null(); + +/** + * Skalarmultiplikation: Multiplikation des Vektors mit einem Skalar. + * + * Verwender müssen den Speicher mit free wieder freigeben. + * + * @param v Vektor, der mit dem Skalar multipliziert werden soll + * @param scalar Skalar mit dem multipliziert werden soll + * @return das Ergebnis der Skalarmultiplikation + */ +Vector* vec_mul_scalar(Vector* v, double scalar); + +/** + * Multiplikation des Vektors mit einem Vektor. + * + * @param first Vektor, der mit dem anderen multipliziert werden soll + * @param second Vektor, der mit dem anderen multipliziert werden soll + * @return das Ergebnis der Multiplikation + */ +double vec_mul_dot(Vector* first, Vector *second); + +/** + * Bestimmt das Kreuzprodukt der beiden Vektoren. + * + * Verwender müssen den Speicher mit free wieder freigeben. + * + * @param first Vektor, der mit dem anderen multipliziert werden soll + * @param second Vektor, der mit dem anderen multipliziert werden soll + * @return das Ergebnis der Multiplikation + */ +Vector* vec_mul_cross(Vector* first, Vector *second); + +/** + * Addiert zwei Vektoren. + * + * Verwender müssen den Speicher mit free wieder freigeben. + * + * @param first Vektor, der mit dem anderen addiert werden soll + * @param second Vektor, der mit dem anderen addiert werden soll + * @return das Ergebnis der Addition + */ +Vector* vec_add(Vector* first, Vector *second); + +/** + * Subtrahiert zwei Vektoren. + * + * Verwender müssen den Speicher mit free wieder freigeben. + * + * @param first Vektor, von dem subtrahiert wird + * @param second Vektor, der subtrahiert wird + * @return das Ergebnis der Subtraktion + */ +Vector* vec_sub(Vector* first, Vector *second); + +/** + * Vergleicht zwei Vektoren auf Gleichheit der Komponenten. + * + * @param first Vektor, der verglichen werden soll + * @param second Vektor, der verglichen werden soll + * @return TRUE wenn die Vektoren gleich sind, sonst FALSE + */ +int vec_equals(Vector* first, Vector *second); + +/** + * Wandelt den gegebenen Vektor in eine String um und alloziert den + * dafür nötigen Speicher. + * + * Verwender müssen den Speicher mit free wieder freigeben. + * + * @param v Vektor, der umgewandelt werden soll + * @return String-Repräsentation des Vektors + */ +char* vec_to_str(Vector* v); + +/** + * Gibt den Vektor aus. + * + * @param v Vektor, der ausgegeben werden soll + */ +void vec_print(Vector* v); + +/** + * Bestimmt die Lönge des Vektors. + * + * @param v Vektor, dessen Länge bestimmt werden soll. + * @return die Länge des Vektors + */ +double vec_length(Vector* v); + +/** + * Bestimmt den Einheitsvektor zum gegeben Vektor. + * + * Verwender müssen den Speicher mit free wieder freigeben. + * + * @param v Vektor, für den die Norm bestimmt werden soll + * @return den Einheitsvektor, oder NULL im Fehlerfall (v hat die Länge 0) + */ +Vector* vec_norm(Vector* v); + +/** + * Testet, ob die beiden Vektoren kollinear sind. + * + * Verwender müssen den Speicher mit free wieder freigeben. + * + * @param first Vektor, der verglichen werden soll + * @param second Vektor, der verglichen werden soll + * @return TRUE wenn die Vektoren kollinear sind, sonst FALSE + */ +int vec_collinear(Vector* first, Vector* second); + +#endif /* VECTOR_HEAP_H */ \ No newline at end of file diff --git a/Assignment_022/solution/vector_heap_benchmark.c b/Assignment_022/solution/vector_heap_benchmark.c new file mode 100644 index 0000000..2d27fb8 --- /dev/null +++ b/Assignment_022/solution/vector_heap_benchmark.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include "vector_heap.h" +#include "benchmark.h" + +int main(int argv, char** argc) { + clock_t before, after; + + before = clock(); + + Vector *v1, *v2, *v3, *v4, *v5; + + v1 = vec_new(10, 20, 30); + v2 = vec_new(-20, 99, 38); + + + for (long long i = 0; i < RUNS; i++) { + v3 = vec_mul_cross(v1, v2); + vec_mul_dot(v3, v2); + + v4 = vec_mul_scalar(v3, 10.0); + v5 = vec_mul_scalar(v3, 0.1); + + free(v3); + free(v4); + free(v5); + } + + free(v1); + free(v2); + + after = clock(); + + printf("Runtime: %.3f seconds\n", (after - before) / (double) CLOCKS_PER_SEC); +} \ No newline at end of file diff --git a/Assignment_022/solution/vector_heap_test.c b/Assignment_022/solution/vector_heap_test.c new file mode 100644 index 0000000..60640bd --- /dev/null +++ b/Assignment_022/solution/vector_heap_test.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include "minitest.h" +#include "vector_heap.h" + +static char* test_creation() { + Vector* vec = vec_new(3.0, 1.0, -5.0); + mu_assert("Equal x", vec->x == 3.0); + mu_assert("Equal y", vec->y == 1.0); + mu_assert("Equal z", vec->z == -5.0); + free(vec); + + return 0; +} + +static int tests_run; + +static char* allTests() { + mu_run_test(test_creation); + /* Weitere Tests hier einfügen */ + + return 0; +} + +int main() { + char *result = allTests(); + + if (result != 0) printf("%s\n", result); + else printf("ALL TESTS PASSED\n"); + + printf("Tests run: %d\n", tests_run); + + return result != 0; +} diff --git a/Assignment_022/vector_heap_test.c b/Assignment_022/vector_heap_test.c new file mode 100644 index 0000000..60640bd --- /dev/null +++ b/Assignment_022/vector_heap_test.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include "minitest.h" +#include "vector_heap.h" + +static char* test_creation() { + Vector* vec = vec_new(3.0, 1.0, -5.0); + mu_assert("Equal x", vec->x == 3.0); + mu_assert("Equal y", vec->y == 1.0); + mu_assert("Equal z", vec->z == -5.0); + free(vec); + + return 0; +} + +static int tests_run; + +static char* allTests() { + mu_run_test(test_creation); + /* Weitere Tests hier einfügen */ + + return 0; +} + +int main() { + char *result = allTests(); + + if (result != 0) printf("%s\n", result); + else printf("ALL TESTS PASSED\n"); + + printf("Tests run: %d\n", tests_run); + + return result != 0; +} diff --git a/Assignment_023/kryptonier.jpg b/Assignment_023/kryptonier.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3d50cafa3479cb9905552f566443173bf83c90b9 GIT binary patch literal 22186 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 GKmXZHo(= ((b) - (delta))) && ((a) <= ((b) + (delta)))) +#define mu_assert(message, test) do { if (!(test)) return message; } while (0) +#define mu_run_test(test) do { char *message = test(); tests_run++; \ + if (message) return message; } while (0) + +#endif /* MINITEST_H */ \ No newline at end of file diff --git a/Assignment_023/readme.md b/Assignment_023/readme.md new file mode 100644 index 0000000..937a457 --- /dev/null +++ b/Assignment_023/readme.md @@ -0,0 +1,134 @@ +# Assignment: Vektor (stack-basiert) + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Es ist sechs Uhr morgens, Ihr Radiowecker weckt Sie mit dem Song "I Got You Babe" von Sonny and Cher. Irgendwie erinnert Sie das an einen [Film](https://www.imdb.com/title/tt0107048), den Sie vor längerer Zeit gesehen haben, mit Bill Murray... + +![Quelle: Pixabay.com](kryptonier.jpg) + +Es gibt einen lauten Knall. Sie schauen zum Himmel uns sehen dort ein Raumschiff der Kryptonier, die offensichtlich die Weltherrschaft an sich reißen wollen; woher Sie das wissen? Natürlich aus den vielen Filmen, die Sie gesehen haben: Aliens == böse. Zum Glück haben Sie noch eine kleine Rakete im Garten (woher auch immer die stammt), die Sie auf das Raumschiff abfeuern könnten. Aber wie bloß die Flugbahn berechnen? Dazu bietet sich doch die gute alte Vektorrechnung an... + +Wie bitte? Die Geschichte kennen wir doch schon. Wieso schon wieder die Kryptonier? Wenn Ihnen das nicht klar ist, sollten Sie noch einmal den [Film](https://www.imdb.com/title/tt0107048) mit Bill Murray schauen. + +**Ziel**: Ziel dieses Assignments ist es, Vektoren in C zu implementieren. + + +## Vector: Struktur und Funktionen + +### Beschreibung des Programms + +Implementieren Sie eine Struktur `Vector` und die dazugehörigen Funktionen in einer Datei `vector_stack.c` mit deren Hilfe man auf dreidimensionalen Vektoren die wichtigsten Operationen durchführen kann. Drei Dimensionen reichen, um die Flugbahn der Rakete zu berechnen -- also kein Grund für mehr Dimensionen! + +Die Komponenten x, y und z sollen als `double` gespeichert werden. + +Ihre Implementierung soll die folgenden Aktionen unterstützen: + + * `vec_init` - Befüllen des Vektors mit Daten für die drei Komponenten + * `vec_null` - Setzen eines Vektors als Nullvektor (alle drei Komponenten [x,y,z] sind 0) + * `vec_add` - Addieren zweier Vektoren + * `vec_sub` - Subtrahieren zweier Vektoren + * `vec_mul_scalar` - Multiplikation des Vektors mit einem Skalar + * `vec_mul_dot` - Skalarmultiplikation zweier Vektoren + * `vec_mul_cross` - Kreuzprodukt zweier Vektoren + * `vec_norm` - Erzeugung des Einheitsvektors aus einem gegebenen Vektor (d.h. Vektor der Länge 1 mit derselben Richtung wie der ursprüngliche Vektor). Beachten Sie, dass vom Nullvektor kein Einheitsvektor erzeugt werden kann. In diesem Fall müssen Sie eine entsprechende Rückgabe machen, um den Fehler anzuzeigen. + * `vec_length` - Berechnung des Betrages (der Länge) eines Vektors + * `vec_collinear` - Test, ob zwei Vektoren kollinear (parallel oder antiparallel) sind + * `vec_equals` - Test, ob zwei Vektoren gleich sind + * `vec_print` - Ausgabe des Vektors auf der Console + * `vec_to_s` - Umwandlung des Vektors in einen String + +Keine der Funktionen verändert die übergebenen Vektoren, sondern schreibt das Ergebnis in den ebenfalls übergebenen Vektor für das Ergebnis. Siehe hierzu das Beispiel unten. + +Bei einer C-Bibliothek muss man sich entscheiden, wer für die Allokation des Speichers zuständig ist. Hier entscheiden wir uns dafür, dass der Verwender der Funktionen den Speicher beschaffen muss und den Funktionen als Pointer übergeben. Das folgende Beispiel zeigt, wie Ihre Vektor-Bibliothek zu benutzen ist: + +```c +Vector v1, v2, v3; +char* result; + +/* Vektoren initialisieren */ +vec_init(&v1, 10.0, 20.0, 30.0); +vec_init(&v2, -20.0, 99.0, 38.0); + +/* Kreuzprodukt berechnen. v1 und v2 bleiben unverändert, + Ergebnis wird in v3 gespeichert. */ +vec_mul_cross(&v3, v1, v2); + +/* Ergebnis ausgeben */ +result = vec_to_str(v3); +printf("Das Ergebnis ist: %s\n", result); +free(result); +``` + +Einzig die `vec_to_str`-Funktion beschafft Speicher für den String per `malloc`, den der Verwender per `free` wieder freigeben muss. Alle anderen Funktionen führen keine Speicherallokation durch. + +Schreiben Sie eine Header-Datei `vector_stack.h`, welche die exportierten Funktionen als Prototypen enthält. Diese werden wir für die Tests benötigen. Kommentieren Sie die Funktionen ausreichend. + +## Tests + +Überprüfen Sie die Funktionalität Ihrer Implementierung mit entsprechenden Unit-Tests (Datei `vektor_stack_test.c`) und weisen Sie mit diesen Tests nach, dass die implementierten Operationen richtig funktionieren. + +Für die Unit-Tests steht Ihnen eine ganz einfache Testbibliothek über das Header-File `minitest.h` zur Verfügung. Die Datei `vektor_stack_test.c` enthält ein Beispiel für die Benutzung dieser Bibliothek. Verwenden Sie das dort benutzte Schema und fügen Sie Ihre Tests hinzu. + +Verwenden Sie bitte __mindestens__ die folgenden Testdaten/Testfälle. + +### Multiplikation mit einem Skalar + + * `[1, -5, 3] * 6 = [ 6, -30, 18 ]` + * `[ 1, -5, 3 ] * -3 = [ -3, 15, -9 ]` + + +### Skalarprodukt zweier Vektoren + + * `[ 1, 2, 3 ] * [ -7, 8, 9 ] = 36` + * `[ -5, 9, 7 ] * [ 10, 3, 8 ] = 33` + + +### Addition und Subtraktion + + * `[ 4, 0, 8 ] + [ -1, 4, 7 ] = [ 3, 4, 15 ]` + * `[ 4, 0, 8 ] - [ -1, 4, 7 ] = [ 5, -4, 1 ]` + * `[ 4, 0, 8 ] + [ -1, 4, 7 ] = [ -1, 4, 7 ] + [ 4, 0, 8 ]` + + +### Kreuzprodukt + + * `[ 1, 2, 3 ] x [ -7, 8, 9 ] = [ -6, -30, 22 ]` + * `[ 1, 2, 8 ] x [ 4, 3, 5 ] = [ -14, 27, -5 ]` + + +### Betrag + + * `|[ 1, 1, 1 ]| = sqrt(3)` + * `|[ 5, 4, 3 ]| = sqrt(50)` + + +### Kollinearität + + * `[ 4, 5, 7 ]` und `[ 16, 20, 28 ]` sind kollinear + * `[ 4, 5, 7 ]` und `[ 16, 20, 21 ]` sind nicht kollinear + + +### Komplexere Rechnung + + * `([ -1, 5, -2 ] x [ 2, 1, 2 ]) * [ 2, 0, 5 ] = -31` + + +## Makefile + +Automatisieren Sie das Kompilieren und Testen Ihrer Programme mit einem Makefile. Dieses sollte mindestens die folgenden Targets haben: + + * `all` - baut alle Dateien + * `clean` - setzt das Projekt zurück und löscht alle Kompilationsergebnisse + * `test` - führt die oben beschriebenen Tests aus + +Sie benötigen natürlich weitere Targets für die Objektdateien und fertigen Executables. + + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) + + * Vektorrechnung: [Wikipedia: Vektor -- Rechenoperationen](https://de.wikipedia.org/wiki/Vektor#Rechenoperationen) \ No newline at end of file diff --git a/Assignment_023/solution/.gitignore b/Assignment_023/solution/.gitignore new file mode 100644 index 0000000..2416a67 --- /dev/null +++ b/Assignment_023/solution/.gitignore @@ -0,0 +1 @@ +obj/ diff --git a/Assignment_023/solution/Makefile b/Assignment_023/solution/Makefile new file mode 100644 index 0000000..0b10244 --- /dev/null +++ b/Assignment_023/solution/Makefile @@ -0,0 +1,51 @@ +CC = gcc +CC_OPTIONS = -Wall + +BIN_DIR = bin +BINARIES = \ + $(BIN_DIR)/countdown \ + $(BIN_DIR)/file_line_no \ + $(BIN_DIR)/hello \ + $(BIN_DIR)/hello_cmdline \ + $(BIN_DIR)/hello_define \ + $(BIN_DIR)/leet \ + $(BIN_DIR)/numberguess \ + $(BIN_DIR)/pipe_rechner \ + $(BIN_DIR)/print_array \ + $(BIN_DIR)/print_array_pointer \ + $(BIN_DIR)/print_file \ + $(BIN_DIR)/read_write \ + $(BIN_DIR)/reverse \ + $(BIN_DIR)/sizeof \ + $(BIN_DIR)/socket_client \ + $(BIN_DIR)/socket_server \ + $(BIN_DIR)/swap \ + $(BIN_DIR)/hello_greeter \ + $(BIN_DIR)/vararg_sum \ + $(BIN_DIR)/argv_printer \ + $(BIN_DIR)/function_pointer \ + $(BIN_DIR)/struct_book \ + $(BIN_DIR)/typedef \ + $(BIN_DIR)/malloc_free \ + $(BIN_DIR)/union \ + $(BIN_DIR)/strings \ + $(BIN_DIR)/threads + + +.PHONY: all +all: $(BINARIES) + +.PHONY: clean +clean: + -rm $(BINARIES) + -rm $(BIN_DIR)/*.o + -rmdir $(BIN_DIR) + +$(BIN_DIR)/%: %.c + mkdir -p $(BIN_DIR) + $(CC) $(CC_OPTIONS) -o $@ $< + +$(BIN_DIR)/hello_greeter: greeter/greeter.c greeter/greeter.h greeter/hello_greeter.c + $(CC) $(CC_OPTIONS) -c greeter/greeter.c -o $(BIN_DIR)/greeter.o + $(CC) $(CC_OPTIONS) -c greeter/hello_greeter.c -o $(BIN_DIR)/hello_greeter.o + $(CC) $(CC_OPTIONS) $(BIN_DIR)/greeter.o $(BIN_DIR)/hello_greeter.o -o $(BIN_DIR)/hello_greeter diff --git a/Assignment_023/solution/benchmark.h b/Assignment_023/solution/benchmark.h new file mode 100644 index 0000000..64a089a --- /dev/null +++ b/Assignment_023/solution/benchmark.h @@ -0,0 +1,6 @@ +#ifndef BENCHMARK_H +#define BENCHMARK_H + +#define RUNS 100000000 + +#endif /* BENCHMARK_H */ \ No newline at end of file diff --git a/Assignment_023/solution/minitest.h b/Assignment_023/solution/minitest.h new file mode 100644 index 0000000..4de137f --- /dev/null +++ b/Assignment_023/solution/minitest.h @@ -0,0 +1,9 @@ +#ifndef MINITEST_H +#define MINITEST_H + +#define mu_in_delta(a, b, delta) (((a) >= ((b) - (delta))) && ((a) <= ((b) + (delta)))) +#define mu_assert(message, test) do { if (!(test)) return message; } while (0) +#define mu_run_test(test) do { char *message = test(); tests_run++; \ + if (message) return message; } while (0) + +#endif /* MINITEST_H */ \ No newline at end of file diff --git a/Assignment_023/solution/readme.md b/Assignment_023/solution/readme.md new file mode 100644 index 0000000..1f77ea0 --- /dev/null +++ b/Assignment_023/solution/readme.md @@ -0,0 +1,11 @@ +# Lösung: Vektor (stack-basiert) + +Lösung: + + * [benchmark.h](benchmark.h) + * [Makefile](Makefile) + * [minitest.h](minitest.h) + * [vector_stack_benchmark.c](vector_stack_benchmark.c) + * [vector_stack.c](vector_stack.c) + * [vector_stack.h](vector_stack.h) + * [vector_stack_test.c](vector_stack_test.c) \ No newline at end of file diff --git a/Assignment_023/solution/vector_stack.c b/Assignment_023/solution/vector_stack.c new file mode 100644 index 0000000..1d98790 --- /dev/null +++ b/Assignment_023/solution/vector_stack.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include "vector_stack.h" + +void vec_init(Vector* result, double x, double y, double z) { + result->x = x; + result->y = y; + result->z = z; +} + +void vec_null(Vector* result) { + vec_init(result, 0.0, 0.0, 0.0); +} + +void vec_mul_scalar(Vector* result, Vector v, double scalar) { + vec_init(result, v.x * scalar, + v.y * scalar, + v.z * scalar); +} + +double vec_mul_dot(Vector first, Vector second) { + return first.x * second.x + + first.y * second.y + + first.z * second.z; +} + +void vec_mul_cross(Vector* result, Vector first, Vector second) { + return vec_init(result, first.y * second.z - first.z * second.y, + first.z * second.x - first.x * second.z, + first.x * second.y - first.y * second.x); +} + +void vec_add(Vector* result, Vector first, Vector second) { + return vec_init(result, first.x + second.x, + first.y + second.y, + first.z + second.z); +} + +void vec_sub(Vector* result, Vector first, Vector second) { + return vec_init(result, first.x - second.x, + first.y - second.y, + first.z - second.z); +} + +int vec_equals(Vector first, Vector second) { + return (first.x == second.x) + && (first.y == second.y) + && (first.z == second.z); +} + +static const int MAX_LENGTH=128; + +char* vec_to_str(Vector v) { + char* result = (char*) malloc(MAX_LENGTH); + + if (!result) { + return NULL; + } + + snprintf(result, MAX_LENGTH, "[ %.2f %.2f %.2f ]", v.x, v.y, v.z); + return result; +} + +void vec_print(Vector v) { + char* str = vec_to_str(v); + printf("%s", str); + free(str); +} + +double vec_length(Vector v) { + return sqrt(v.x * v.x + + v.y * v.y + + v.z * v.z); +} + +int vec_norm(Vector* result, Vector v) { + double length = vec_length(v); + + if (length == 0.0) { + /* no norm for a null vector */ + return -1; + } + + vec_init(result, v.x / length, + v.y / length, + v.z / length); + + return 0; +} + +int vec_collinear(Vector first, Vector second) { + Vector cross, nullVector; + + vec_mul_cross(&cross, first, second); + vec_null(&nullVector); + int result = vec_equals(nullVector, cross); + + return result; +} diff --git a/Assignment_023/solution/vector_stack.h b/Assignment_023/solution/vector_stack.h new file mode 100644 index 0000000..d864de2 --- /dev/null +++ b/Assignment_023/solution/vector_stack.h @@ -0,0 +1,131 @@ +#ifndef VECTOR_STACK_H +#define VECTOR_STACK_H + +/** + * Struktur zur Darstellung eines dreidimensionalen Vektors. + */ +typedef struct Vector { + double x; + double y; + double z; +} Vector; + +typedef int bool; + +/** + * Befüllt einen Vektor mit den angegebenen Elementen. + * + * @param result (out) Vektor, der befüllt werden soll + * @param x die x-Komponente des Vektors + * @param y die y-Komponente des Vektors + * @param z die z-Komponente des Vektors + */ +void vec_init(Vector* result, double x, double y, double z); + +/** + * Befüllt einen Vektor mit dem Wert 0 für alle Komponenten und erzeugt + * so den Nullvektor. + * + * @param result (out) Vektor, der befüllt werden soll + */ +void vec_null(Vector* result); + +/** + * Skalarmultiplikation: Multiplikation des Vektors mit einem Skalar. + * + * @param result (out) Vektor, der befüllt werden soll + * @param v Vektor, der mit dem Skalar multipliziert werden soll + * @param scalar Skalar mit dem multipliziert werden soll + */ +void vec_mul_scalar(Vector* result, Vector v, double scalar); + +/** + * Multiplikation des Vektors mit einem Vektor. + * + * @param result (out) Vektor für das Ergebnis + * @param first Vektor, der mit dem anderen multipliziert werden soll + * @param second Vektor, der mit dem anderen multipliziert werden soll + */ +double vec_mul_dot(Vector first, Vector second); + +/** + * Bestimmt das Kreuzprodukt der beiden Vektoren. + * + * @param result (out) Vektor für das Ergebnis + * @param first Vektor, der mit dem anderen multipliziert werden soll + * @param second Vektor, der mit dem anderen multipliziert werden soll + */ +void vec_mul_cross(Vector* result, Vector first, Vector second); + +/** + * Addiert zwei Vektoren. + * + * @param result (out) Vektor für das Ergebnis + * @param first Vektor, der mit dem anderen addiert werden soll + * @param second Vektor, der mit dem anderen addiert werden soll + */ +void vec_add(Vector* result, Vector first, Vector second); + +/** + * Subtrahiert zwei Vektoren. + * + * @param result (out) Vektor für das Ergebnis + * @param first Vektor, von dem subtrahiert wird + * @param second Vektor, der subtrahiert wird + */ +void vec_sub(Vector* result, Vector first, Vector second); + +/** + * Vergleicht zwei Vektoren auf Gleichheit der Komponenten. + * + * @param first Vektor, der verglichen werden soll + * @param second Vektor, der verglichen werden soll + * @return TRUE wenn die Vektoren gleich sind, sonst FALSE + */ +bool vec_equals(Vector first, Vector second); + +/** + * Wandelt den gegebenen Vektor in eine String um und alloziert den + * dafür nötigen Speicher. + * + * Verwender müssen den Speicher mit free wieder freigeben. + * + * @param v Vektor, der umgewandelt werden soll + * @return String-Repräsentation des Vektors + */ +char* vec_to_str(Vector v); + +/** + * Gibt den Vektor aus. + * + * @param v Vektor, der ausgegeben werden soll + */ +void vec_print(Vector v); + +/** + * Bestimmt die Lönge des Vektors. + * + * @param v Vektor, dessen Länge bestimmt werden soll. + * @return die Länge des Vektors + */ +double vec_length(Vector v); + +/** + * Bestimmt den Einheitsvektor zum gegeben Vektor. + * + * @param result (out) Vektor für das Ergebnis + * @param v Vektor, für den die Norm bestimmt werden soll + * @return 0 bei Erfolg, -1 im Fehlerfall + */ +int vec_norm(Vector* result, Vector v); + +/** + * Testet, ob die beiden Vektoren kollinear sind. + * + * @param first Vektor, der verglichen werden soll + * @param second Vektor, der verglichen werden soll + * @return TRUE wenn die Vektoren kollinear sind, sonst FALSE + */ +bool vec_collinear(Vector first, Vector second); + +#endif /* VECTOR_STACK_H */ \ No newline at end of file diff --git a/Assignment_023/solution/vector_stack_benchmark.c b/Assignment_023/solution/vector_stack_benchmark.c new file mode 100644 index 0000000..d91232f --- /dev/null +++ b/Assignment_023/solution/vector_stack_benchmark.c @@ -0,0 +1,26 @@ +#include +#include +#include "vector_stack.h" +#include "benchmark.h" + +int main(int argv, char** argc) { + clock_t before, after; + + before = clock(); + + Vector v1, v2, v3; + + vec_init(&v1, 10, 20, 30); + vec_init(&v2, -20, 99, 38); + + for (long long i = 0; i < RUNS; i++) { + vec_mul_cross(&v3, v1, v2); + vec_mul_dot(v3, v2); + vec_mul_scalar(&v3, v3, 10.0); + vec_mul_scalar(&v3, v3, 0.1); + } + + after = clock(); + + printf("Runtime: %.3f seconds\n", (after - before) / (double) CLOCKS_PER_SEC); +} \ No newline at end of file diff --git a/Assignment_023/solution/vector_stack_test.c b/Assignment_023/solution/vector_stack_test.c new file mode 100644 index 0000000..5b143c4 --- /dev/null +++ b/Assignment_023/solution/vector_stack_test.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include "minitest.h" +#include "vector_stack.h" + +static char* test_creation() { + Vector vec; + vec_init(&vec, 3.0, 1.0, -5.0); + + mu_assert("Equal x", vec.x == 3.0); + mu_assert("Equal y", vec.y == 1.0); + mu_assert("Equal z", vec.z == -5.0); + + return 0; +} + +/* Weitere Testmethoden hier einfügen */ + +static int tests_run; + +static char* allTests() { + mu_run_test(test_creation); + /* Alle Testmethoden hier rufen */ + + return 0; +} + +int main() { + char *result = allTests(); + + if (result != 0) printf("%s\n", result); + else printf("ALL TESTS PASSED\n"); + + printf("Tests run: %d\n", tests_run); + + return result != 0; +} diff --git a/Assignment_023/vector_stack_test.c b/Assignment_023/vector_stack_test.c new file mode 100644 index 0000000..5b143c4 --- /dev/null +++ b/Assignment_023/vector_stack_test.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include "minitest.h" +#include "vector_stack.h" + +static char* test_creation() { + Vector vec; + vec_init(&vec, 3.0, 1.0, -5.0); + + mu_assert("Equal x", vec.x == 3.0); + mu_assert("Equal y", vec.y == 1.0); + mu_assert("Equal z", vec.z == -5.0); + + return 0; +} + +/* Weitere Testmethoden hier einfügen */ + +static int tests_run; + +static char* allTests() { + mu_run_test(test_creation); + /* Alle Testmethoden hier rufen */ + + return 0; +} + +int main() { + char *result = allTests(); + + if (result != 0) printf("%s\n", result); + else printf("ALL TESTS PASSED\n"); + + printf("Tests run: %d\n", tests_run); + + return result != 0; +} diff --git a/Assignment_024/readme.md b/Assignment_024/readme.md new file mode 100644 index 0000000..3d9cac5 --- /dev/null +++ b/Assignment_024/readme.md @@ -0,0 +1,12 @@ +# Datei auf der Konsole aufgeben. + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie eine Funktion `print_file`, der man einen Dateinamen bzw. Pfad zu einer Datei übergibt und die diese Datei dann auf der Konsole ausgibt. Denken Sie daran, Fehler abzufangen und entsprechende Fehlermeldungen auszugeben. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_024/solution/print_file.c b/Assignment_024/solution/print_file.c new file mode 100644 index 0000000..d156ebe --- /dev/null +++ b/Assignment_024/solution/print_file.c @@ -0,0 +1,42 @@ +/** + * Datei auf der Konsole aufgeben. + * + * Schreiben Sie eine Funktion `print_file`, der man einen Dateinamen + * bzw. Pfad zu einer Datei übergibt und die diese Datei dann auf der + * Konsole ausgibt. Denken Sie daran, Fehler abzufangen und entsprechende + * Fehlermeldungen auszugeben. + */ +#include +#include + +#define BUFFER_SIZE 255 + +void print_file(const char* filename) { + + FILE *fh = fopen(filename, "r+"); + + if (!fh) { + perror("Fehler: "); + exit(1); + } + + char buffer[BUFFER_SIZE]; + + size_t num_read; + + while ((num_read = fread(buffer, sizeof(char), BUFFER_SIZE, fh)) > 0) { + fwrite(buffer, sizeof(char), num_read, stdout); + } + + fclose(fh); +} + +int main(int argc, char** argv) { + if (argc < 2) { + puts("Dateiname fehlt!"); + exit(1); + } + + print_file(argv[1]); + return 0; +} diff --git a/Assignment_024/solution/readme.md b/Assignment_024/solution/readme.md new file mode 100644 index 0000000..442aedc --- /dev/null +++ b/Assignment_024/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Datei auf der Konsole aufgeben. + +Lösung: [print_file.c](print_file.c) \ No newline at end of file diff --git a/Assignment_025/readme.md b/Assignment_025/readme.md new file mode 100644 index 0000000..414efc7 --- /dev/null +++ b/Assignment_025/readme.md @@ -0,0 +1,14 @@ +# Datei auf der Konsole mit Zeilennummern aufgeben + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie eine Funktion `print_file_with_lineno`, der man einen Dateinamen bzw. Pfad zu einer Datei übergibt und die diese Datei dann auf der Konsole ausgibt. Jede Zeile der Datei soll mit der entsprechenden Zeilennummer ausgegeben werden. + +Denken Sie daran, Fehler abzufangen und entsprechende Fehlermeldungen auszugeben. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_025/solution/file_line_no.c b/Assignment_025/solution/file_line_no.c new file mode 100644 index 0000000..e2f3dc0 --- /dev/null +++ b/Assignment_025/solution/file_line_no.c @@ -0,0 +1,47 @@ +/** + * Datei auf der Konsole mit Zeilennummern aufgeben. + * + * Schreiben Sie eine Funktion `print_file_with_lineno`, der man einen + * Dateinamen bzw. Pfad zu einer Datei übergibt und die diese Datei + * dann auf der Konsole ausgibt. Jede Zeile der Datei soll mit der + * entsprechenden Zeilennummer ausgegeben werden. + * + * Denken Sie daran, Fehler abzufangen und entsprechende Fehlermeldungen + * auszugeben. + */ +#include +#include + +// Limitierung auf Zeilen mit maximal 255 Zeichen Länge +#define BUFFER_SIZE 255 + +void print_file_with_lineno(const char* filename) { + + FILE *fh = fopen(filename, "r+"); + + if (!fh) { + perror("Fehler: "); + exit(1); + } + + char buffer[BUFFER_SIZE]; + + char* line; + int line_number = 1; + + while ((line = fgets(buffer, BUFFER_SIZE, fh))) { + printf("%.3d: %s", line_number++, line); + } + + fclose(fh); +} + +int main(int argc, char** argv) { + if (argc < 2) { + puts("Dateiname fehlt!"); + exit(1); + } + + print_file_with_lineno(argv[1]); + return 0; +} diff --git a/Assignment_025/solution/readme.md b/Assignment_025/solution/readme.md new file mode 100644 index 0000000..b812c05 --- /dev/null +++ b/Assignment_025/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Datei auf der Konsole mit Zeilennummern aufgeben + +Lösung: [file_line_no.c](file_line_no.c) \ No newline at end of file diff --git a/Assignment_026/readme.md b/Assignment_026/readme.md new file mode 100644 index 0000000..25de35d --- /dev/null +++ b/Assignment_026/readme.md @@ -0,0 +1,15 @@ +# Datei lesen und schreiben. + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie eine Programm, das eine Datei `FILENAME` öffnet und +den Wert `0xcafebabe` hineinschreibt. Ohne die Datei zu schließen +soll dann im nächsten Schritt der Wert wieder eingelesen werden +und ausgegeben. Verwenden Sie I/O-Funktionen aus der C-Standardbibliothek. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_026/solution/read_write.c b/Assignment_026/solution/read_write.c new file mode 100644 index 0000000..a3608c9 --- /dev/null +++ b/Assignment_026/solution/read_write.c @@ -0,0 +1,35 @@ +/** + * Datei lesen und schreiben. + * + * Schreiben Sie eine Programm, das eine Datei `FILENAME` öffnet und + * den Wert `0xcafebabe` hineinschreibt. Ohne die Datei zu schließen + * soll dann im nächsten Schritt der Wert wieder eingelesen werden + * und ausgegeben. Verwenden Sie I/O-Funktionen aus der C-Standardbibliothek. + */ +#include +#include + +#define FILENAME "/tmp/data" + +int main(int argc, char const **argv) { + + FILE *fh = fopen(FILENAME, "w+"); + + if (!fh) { + perror(FILENAME); + exit(1); + } + + unsigned int magic_value = 0xcafebabe; + + fwrite(&magic_value, sizeof(int), 1, fh); + fseek(fh, 0, SEEK_SET); + + unsigned int read_back; + + fread(&read_back, sizeof(int), 1, fh); + + printf("Aus Datei %s: %x\n", FILENAME, read_back); + + return 0; +} diff --git a/Assignment_026/solution/readme.md b/Assignment_026/solution/readme.md new file mode 100644 index 0000000..1be8369 --- /dev/null +++ b/Assignment_026/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Datei lesen und schreiben. + +Lösung: [read_write.c](read_write.c) \ No newline at end of file diff --git a/Assignment_027/readme.md b/Assignment_027/readme.md new file mode 100644 index 0000000..64faf28 --- /dev/null +++ b/Assignment_027/readme.md @@ -0,0 +1,14 @@ +# Rechner mit Pipes + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie ein Programm, das über `fork` zwei Prozesse erzeugt, die über zwei Pipes miteinander verbunden sind. Die beiden Pipes dienen der bidirektionalen Kommunikation zwischen den beiden Prozessen. + +Der Elternprozess sendet zwei Integer-Werte über die Pipe und der Kindprozess berechnet die Summe der beiden Zahlen und sendet das Ergebnis an den Elternprozess zurück. Dieser empfängt das Ergebnis und gibt es auf der Konsole aus. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_027/solution/pipe_rechner.c b/Assignment_027/solution/pipe_rechner.c new file mode 100644 index 0000000..fa44574 --- /dev/null +++ b/Assignment_027/solution/pipe_rechner.c @@ -0,0 +1,69 @@ +/** + * Rechner mit Pipes. + * + * Schreiben Sie ein Programm, das über `fork` zwei Prozesse erzeugt, + * die über zwei Pipes miteinander verbunden sind. Die beiden Pipes + * dienen der bidirektionalen Kommunikation zwischen den beiden + * Prozessen. + * + * Der Elternprozess sendet zwei Integer-Werte über die Pipe und der + * Kindprozess berechnet die Summe der beiden Zahlen und sendet + * das Ergebnis an den Elternprozess zurück. Dieser empfängt das + * Ergebnis und gibt es auf der Konsole aus. + */ +#include +#include +#include +#include + +void write_num(int fd, int num) { + write(fd, &num, sizeof(num)); +} + +int read_num(int fd) { + int num; + read(fd, &num, sizeof(num)); + return num; +} + + +int main(int argc, char** argv) { + int pipefd_a[2]; + int pipefd_b[2]; + + // zwei Pipes anlegen + if (pipe(pipefd_a) == -1 || pipe(pipefd_b) == -1) { + perror("Keine Pipe"); + exit(1); + } + + // Variablen mit besseren Namen + int pc_r = pipefd_a[0]; + int pc_w = pipefd_a[1]; + int cp_r = pipefd_b[0]; + int cp_w = pipefd_b[1]; + + if (fork() > 0) { + // parent + close(pc_r); + close(cp_w); + write_num(pc_w, 42); + write_num(pc_w, 23); + int result = read_num(cp_r); + printf("Ergebnis: %d\n", result); + close(pc_w); + close(cp_r); + } + else { + // child + close(pc_w); + close(cp_r); + int a = read_num(pc_r); + int b = read_num(pc_r); + int a_b = a + b; + write_num(cp_w, a_b); + close(cp_w); + close(pc_r); + } + return 0; +} diff --git a/Assignment_027/solution/readme.md b/Assignment_027/solution/readme.md new file mode 100644 index 0000000..93d4cc3 --- /dev/null +++ b/Assignment_027/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: Rechner mit Pipes + +Lösung: [pipe_rechner.c](pipe_rechner.c) \ No newline at end of file diff --git a/Assignment_028/readme.md b/Assignment_028/readme.md new file mode 100644 index 0000000..da4d19e --- /dev/null +++ b/Assignment_028/readme.md @@ -0,0 +1,14 @@ +# Socket-Client und -Server programmieren + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Schreiben Sie einen Socket-Server, der auf 127.0.0.1 und Port 8080 lauscht. Wenn sich ein Client verbindet, liest der Server eine Zeichenfolge vom Client und sendet dann den Text "Hello, " + Zeichenfolge + "!" zurück an den Client. + +Schreiben Sie ein Programm, das sich per Socket mit einem Server unter der IP 127.0.0.1 und auf Port 8080 verbindet. Der Client schickt einen Namen zum Server und liest dann die Antwort des Servers und gibt diese auf stdout aus. + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_028/solution/readme.md b/Assignment_028/solution/readme.md new file mode 100644 index 0000000..eb1cf1f --- /dev/null +++ b/Assignment_028/solution/readme.md @@ -0,0 +1,6 @@ +# Lösung: Socket-Client und -Server programmieren + +Lösung: + + * [socket_client.c](socket_client.c) + * [socket_server.c](socket_server.c) \ No newline at end of file diff --git a/Assignment_028/solution/socket_client.c b/Assignment_028/solution/socket_client.c new file mode 100644 index 0000000..3922eb7 --- /dev/null +++ b/Assignment_028/solution/socket_client.c @@ -0,0 +1,63 @@ +/** + * Socket-Client programmieren. + * + * Schreiben Sie ein Programm, das sich per Socket mit einem + * Server unter der IP 127.0.0.1 und auf Port 8080 verbindet. + * Der Client schickt einen Namen zum Server und liest dann + * die Antwort des Servers und gibt diese auf stdout aus. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1024 +#define NAME "Thomas" +#define PORT 8080 +#define HOST "127.0.0.1" + +int main(int argc, char** argv) { + char buffer[BUFFER_SIZE]; + struct sockaddr_in server_addr; + + // Socket erstellen + int socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd == -1) { + perror("Fehler beim Erstellen des Sockets"); + exit(EXIT_FAILURE); + } + + // Serveradresse und Portnummer konfigurieren + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + server_addr.sin_addr.s_addr = inet_addr(HOST); + + // Verbindung zum Server herstellen + if (connect(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) { + perror("Fehler beim Verbinden mit dem Server"); + exit(EXIT_FAILURE); + } + + // Namen auf Socket schreiben + write(socket_fd, NAME, strlen(NAME) + 1); + + // Daten vom Socket lesen + ssize_t bytes_read = read(socket_fd, buffer, BUFFER_SIZE); + if (bytes_read == -1) { + perror("Fehler beim Lesen vom Socket"); + exit(EXIT_FAILURE); + } + + // Daten auf stdout schreiben + write(1, buffer, bytes_read); + write(1, "\n", 1); + + // Socket schließen + close(socket_fd); + + return 0; +} diff --git a/Assignment_028/solution/socket_server.c b/Assignment_028/solution/socket_server.c new file mode 100644 index 0000000..154075b --- /dev/null +++ b/Assignment_028/solution/socket_server.c @@ -0,0 +1,80 @@ +/** + * Socket-Server programmieren. + * + * Schreiben Sie einen Socket-Server, der auf 127.0.0.1 + * und Port 8080 lauscht. Wenn sich ein Client verbindet, + * liest der Server eine Zeichenfolge vom Client und sendet + * dann den Text "Hello, " + Zeichenfolge + "!" zurück an + * den Client. + */ +#include +#include +#include +#include +#include +#include +#include + +#define PORT 8080 +#define BUFFER_SIZE 1024 + +int main() { + int server_fd, new_socket; + struct sockaddr_in address; + int addrlen = sizeof(address); + char name[BUFFER_SIZE - 20]; + char answer[BUFFER_SIZE]; + + memset(name, 0, sizeof(name)); + + // Socket erstellen + server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_fd == -1) { + perror("Fehler beim Erstellen des Sockets"); + exit(EXIT_FAILURE); + } + + // Adresse konfigurieren + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(PORT); + + // Socket an Port binden + if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) == -1) { + perror("Fehler beim Binden des Sockets"); + exit(EXIT_FAILURE); + } + + // Auf Verbindungen lauschen + if (listen(server_fd, 1) == -1) { + perror("Fehler beim Lauschen auf Verbindungen"); + exit(EXIT_FAILURE); + } + + printf("Server läuft und lauscht auf Port %d\n", PORT); + + // Auf Verbindung warten und Nachricht senden + while ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen))) { + if (new_socket == -1) { + perror("Fehler beim Akzeptieren der Verbindung"); + exit(EXIT_FAILURE); + } + + // Namen lesen + ssize_t len = read(new_socket, name, BUFFER_SIZE - 20); + + if (len < 0) { + perror("Fehler beim Lesen"); + exit(EXIT_FAILURE); + } + + snprintf(answer, BUFFER_SIZE, "Hello, %s!\n", name); + write(new_socket, answer, strlen(answer)); + } + + // Verbindung schließen + close(new_socket); + close(server_fd); + + return 0; +} diff --git a/Assignment_029/readme.md b/Assignment_029/readme.md new file mode 100644 index 0000000..7f11fcb --- /dev/null +++ b/Assignment_029/readme.md @@ -0,0 +1,21 @@ +# POSIX-Threads + +📆 **Fällig: ----** 📆 [Musterlösung](solution/) + +Implementieren Sie eine Funktion mit dem Namen `task`, die einen Parameter vom Typ `void*` erhält. Diese Funktion soll eine einfache Aufgabe ausführen, z.B. eine Schleife von 1 bis 10 ausgeben. Jeder Thread soll diese Aufgabe unabhängig voneinander ausführen. Verwenden Sie `usleep` aus ``, um die Threads nach jeder Ausgabe 10 Mikrosekunden schlafen zu lassen. + +In der `main`-Funktion sollen drei Threads erstellt werden. Jeder Thread soll die Funktion `task` ausführen. Verwenden Sie die Funktionen `pthread_create`, `pthread_join` und `pthread_exit` zur Verwaltung der Threads. + +Beispiel: + +```console +1 1 2 1 3 2 2 4 3 3 5 4 4 6 5 5 7 6 8 6 7 9 7 8 10 8 9 9 +10 10 +``` + + +## Quellen + + * [Skript](https://smits-net.de/files/pr3_c/html/) zur Vorlesung + * [C-Tutorial](https://www.learn-c.org/) + * [C von A bis Z](https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/) \ No newline at end of file diff --git a/Assignment_029/solution/readme.md b/Assignment_029/solution/readme.md new file mode 100644 index 0000000..4043f1c --- /dev/null +++ b/Assignment_029/solution/readme.md @@ -0,0 +1,3 @@ +# Lösung: POSIX-Threads + +Lösung: [threads.c](threads.c) diff --git a/Assignment_029/solution/threads.c b/Assignment_029/solution/threads.c new file mode 100644 index 0000000..29cb5fd --- /dev/null +++ b/Assignment_029/solution/threads.c @@ -0,0 +1,33 @@ +#include +#include +#include + +#define NUM_THREADS 3 +#define TASK_SIZE 10 + +void* task(void* arg) { + for (int i = 1; i <= TASK_SIZE; i++) { + printf("%d ", i); + usleep(10); + } + printf("\n"); + pthread_exit(NULL); +} + +int main() { + pthread_t threads[NUM_THREADS]; + + for (int i = 0; i < NUM_THREADS; i++) { + int thread_create_result = pthread_create(&threads[i], NULL, task, NULL); + if (thread_create_result != 0) { + printf("Fehler beim Erstellen des Threads %d\n", i); + return 1; + } + } + + for (int i = 0; i < NUM_THREADS; i++) { + pthread_join(threads[i], NULL); + } + + return 0; +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..8485146 --- /dev/null +++ b/readme.md @@ -0,0 +1,39 @@ +# C-Programmierung + +Hier finden Sie Übungsaufgaben für den Kurs C-Programmierung. + +Die **Abgabedaten** haben keine Bedeutung, da der Kurs keine Prüfung beinhaltet. + +## Themenüberblick + +| # | Thema | Fällig am 📆 | +|----|----------------------------------------------------------------------------------------------|----------------| +| 1. | [Simples Hello-World-Programm](Assignment_001/readme.md) | **----** | +| 2. | [Simples Hello-World-Programm mit #define](Assignment_002/readme.md) | **----** | +| 3. | [Kommandozeilenargumente ausgeben](Assignment_003/readme.md) | **----** | +| 4. | [Hello-World-Programm, das den Namen von der Kommandozeile nimmt](Assignment_004/readme.md) | **----** | +| 5. | [Simples Hello-World-Programm mit externer Funktion](Assignment_005/readme.md) | **----** | +| 6. | [Zahlenraten](Assignment_006/readme.md) | **----** | +| 7. | [Verschlüsselung in C](Assignment_007/readme.md) | **----** | +| 8. | [Countdown](Assignment_008/readme.md) | **----** | +| 9. | [Größe von Datentypen](Assignment_009/readme.md) | **----** | +| 10. | [Vertauschen von zwei Integer-Werte](Assignment_010/readme.md) | **----** | +| 11. | [Leet Speak](Assignment_011/readme.md) | **----** | +| 12. | [Array ausgeben](Assignment_012/readme.md) | **----** | +| 13. | [Array mit Pointer-Arithmetik ausgeben](Assignment_013/readme.md) | **----** | +| 14. | [String-Verarbeitung](Assignment_014/readme.md) | **----** | +| 15. | [String umdrehen](Assignment_015/readme.md) | **----** | +| 16. | [Vararg Funktion schreiben](Assignment_016/readme.md) | **----** | +| 17. | [typedef verwenden](Assignment_017/readme.md) | **----** | +| 18. | [Dynamische Speicherverwaltung mit malloc und free](Assignment_018/readme.md) | **----** | +| 19. | [Funktionspointer benutzen](Assignment_019/readme.md) | **----** | +| 20. | [Struct verwenden](Assignment_020/readme.md) | **----** | +| 21. | [Union verwenden](Assignment_021/readme.md) | **----** | +| 22. | [Vektor (heap-basiert)](Assignment_022/readme.md) | **----** | +| 23. | [Vektor (stack-basiert)](Assignment_023/readme.md) | **----** | +| 24. | [Datei auf der Konsole aufgeben.](Assignment_024/readme.md) | **----** | +| 25. | [Datei auf der Konsole mit Zeilennummern aufgeben](Assignment_025/readme.md) | **----** | +| 26. | [Datei lesen und schreiben.](Assignment_026/readme.md) | **----** | +| 27. | [Rechner mit Pipes](Assignment_027/readme.md) | **----** | +| 28. | [Socket-Client und -Server programmieren](Assignment_028/readme.md) | **----** | +| 29. | [POSIX-Threads](Assignment_029/readme.md) | **----** |