Initial commit
commit
9aa80fb772
|
@ -0,0 +1,12 @@
|
|||
# Simples Hello-World-Programm
|
||||
|
||||
📆 **Fällig: ----** 📆 [Musterlösung](solution/)
|
||||
|
||||
Schreiben Sie ein Programm, das unter Verwendung von `printf` aus `<stdio.h>` 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/)
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* Simples Hello-World-Programm.
|
||||
*
|
||||
* Schreiben Sie ein Programm, das unter Verwendung von
|
||||
* `printf` aus `<stdio.h>` den Text `Hello, World`
|
||||
* ausgibt.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
printf("%s\n", "Hello, World!");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Simples Hello-World-Programm
|
||||
|
||||
Lösung: [hello.c](hello.c)
|
|
@ -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/)
|
|
@ -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 <stdio.h>
|
||||
#define GREETING "Hello, World."
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
printf("%s\n", GREETING);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Simples Hello-World-Programm mit #define
|
||||
|
||||
Lösung: [hello_define.c](hello_define.c)
|
|
@ -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/)
|
|
@ -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 <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
printf("Argument %d: %s\n", i, argv[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -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)
|
|
@ -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 `<unknown>` 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/)
|
|
@ -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 `<unknown>` begrüßt werden.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printf("Hello, %s.\n", "<unknown>");
|
||||
}
|
||||
else {
|
||||
printf("Hello, %s.\n", argv[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Hello-World-Programm, das den Namen von der Kommandozeile nimmt
|
||||
|
||||
Lösung: [hello_cmdline.c](hello_cmdline.c)
|
|
@ -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 `<unknown>` 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/)
|
|
@ -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 $@ $^
|
|
@ -0,0 +1,6 @@
|
|||
#include "greeter.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void greet(const char* name) {
|
||||
printf("Hello, %s.\n", name);
|
||||
}
|
|
@ -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
|
|
@ -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 `<unknown>` begrüßt werden.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "greeter.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
greet("<unknown>");
|
||||
}
|
||||
else {
|
||||
greet(argv[1]);
|
||||
}
|
||||
}
|
|
@ -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)
|
|
@ -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/)
|
|
@ -0,0 +1,54 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Zahlenraten
|
||||
|
||||
Lösung: [numberguess.c](numberguess.c)
|
|
@ -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/)
|
|
@ -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 "---------------------"
|
||||
$<
|
|
@ -0,0 +1,91 @@
|
|||
#include "crypto.h"
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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__ */
|
|
@ -0,0 +1,72 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "crypto.h"
|
||||
#include <errno.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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)
|
|
@ -0,0 +1,3 @@
|
|||
DIESXISTXEINXTEXTXZUMXTESTEN
|
||||
DERXVERSCHLUESSEKUNG
|
||||
MITXMEHRERENXZEILEN
|
|
@ -0,0 +1,74 @@
|
|||
#include "crypto.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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 ´<stdio.h>`.
|
||||
|
||||
```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/)
|
|
@ -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 ´<stdio.h>`.
|
||||
*
|
||||
* ```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 <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
for (int i = 10; i > 0; i--) {
|
||||
printf("%2d\n", i);
|
||||
}
|
||||
printf("%s\n", "Launch!");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
# Lösung: Countdown
|
||||
|
||||
Lösung:
|
||||
|
||||
* [countdown.c](countdown.c)
|
|
@ -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/)
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Größe von Datentypen
|
||||
|
||||
Lösung: [sizeof.c](sizeof.c)
|
|
@ -0,0 +1,22 @@
|
|||
#include <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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/)
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Vertauschen von zwei Integer-Werte
|
||||
|
||||
Lösung: [swap.c](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 <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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/)
|
|
@ -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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Leet Speak
|
||||
|
||||
Lösung: [leet.c](leet.c)
|
|
@ -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/)
|
|
@ -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 <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Array ausgeben
|
||||
|
||||
Lösung: [print_array.c](print_array.c)
|
|
@ -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/)
|
|
@ -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 <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Array mit Pointer-Arithmetik ausgeben
|
||||
|
||||
Lösung: [print_array_pointer.c](print_array_pointer.c)
|
|
@ -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/)
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: String-Verarbeitung
|
||||
|
||||
Lösung: [strings.c](strings.c)
|
|
@ -0,0 +1,31 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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/)
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: String umdrehen
|
||||
|
||||
Lösung: [reverse.c](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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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/)
|
|
@ -0,0 +1,5 @@
|
|||
# Lösung: Vararg Funktion schreiben
|
||||
|
||||
Lösung:
|
||||
|
||||
* [vararg_sum.c](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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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/)
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: typedef verwenden
|
||||
|
||||
Lösung: [typedef.c](typedef.c)
|
|
@ -0,0 +1,18 @@
|
|||
#include <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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/)
|
|
@ -0,0 +1,39 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Dynamische Speicherverwaltung mit malloc und free
|
||||
|
||||
Lösung: [malloc_free.c](malloc_free.c)
|
|
@ -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/)
|
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// 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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Funktionspointer benutzen
|
||||
|
||||
Lösung: [function_pointer.c](function_pointer.c)
|
|
@ -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/)
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Struct verwenden
|
||||
|
||||
Lösung: [struct_book.c](struct_book.c)
|
|
@ -0,0 +1,39 @@
|
|||
#include <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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/)
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Union verwenden
|
||||
|
||||
Lösung: [union.c](union.c)
|
|
@ -0,0 +1,48 @@
|
|||
#include <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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 `<time.h>` 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
|
|
@ -0,0 +1 @@
|
|||
obj/
|
|
@ -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
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef BENCHMARK_H
|
||||
#define BENCHMARK_H
|
||||
|
||||
#define RUNS 100000000
|
||||
|
||||
#endif /* BENCHMARK_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 */
|
|
@ -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)
|
|
@ -0,0 +1,104 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
|
@ -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 */
|
|
@ -0,0 +1,36 @@
|
|||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -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 */
|
|
@ -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)
|
|
@ -0,0 +1 @@
|
|||
obj/
|
|
@ -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
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef BENCHMARK_H
|
||||
#define BENCHMARK_H
|
||||
|
||||
#define RUNS 100000000
|
||||
|
||||
#endif /* BENCHMARK_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 */
|
|
@ -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)
|
|
@ -0,0 +1,100 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
|
@ -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 */
|
|
@ -0,0 +1,26 @@
|
|||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#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);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
|
@ -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/)
|
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Lösung: Datei auf der Konsole aufgeben.
|
||||
|
||||
Lösung: [print_file.c](print_file.c)
|
|
@ -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/)
|
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// 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;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue