Initial commit

master
Thomas Smits 2023-05-21 21:10:46 +02:00
commit 9aa80fb772
115 changed files with 3343 additions and 0 deletions

View File

@ -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/)

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
# Lösung: Simples Hello-World-Programm
Lösung: [hello.c](hello.c)

View File

@ -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/)

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
# Lösung: Simples Hello-World-Programm mit #define
Lösung: [hello_define.c](hello_define.c)

View File

@ -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/)

View File

@ -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;
}

View File

@ -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)

View File

@ -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/)

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
# Lösung: Hello-World-Programm, das den Namen von der Kommandozeile nimmt
Lösung: [hello_cmdline.c](hello_cmdline.c)

View File

@ -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/)

View File

@ -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 $@ $^

View File

@ -0,0 +1,6 @@
#include "greeter.h"
#include <stdio.h>
void greet(const char* name) {
printf("Hello, %s.\n", name);
}

View File

@ -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

View File

@ -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]);
}
}

View File

@ -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)

View File

@ -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/)

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
# Lösung: Zahlenraten
Lösung: [numberguess.c](numberguess.c)

View File

@ -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/)

View File

@ -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 "---------------------"
$<

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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)

View File

@ -0,0 +1,3 @@
DIESXISTXEINXTEXTXZUMXTESTEN
DERXVERSCHLUESSEKUNG
MITXMEHRERENXZEILEN

View File

@ -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;
}

View File

@ -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/)

View File

@ -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;
}

View File

@ -0,0 +1,5 @@
# Lösung: Countdown
Lösung:
* [countdown.c](countdown.c)

View File

@ -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/)

View File

@ -0,0 +1,3 @@
# Lösung: Größe von Datentypen
Lösung: [sizeof.c](sizeof.c)

View File

@ -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;
}

View File

@ -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/)

View File

@ -0,0 +1,3 @@
# Lösung: Vertauschen von zwei Integer-Werte
Lösung: [swap.c](swap.c)

View File

@ -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;
}

View File

@ -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/)

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
# Lösung: Leet Speak
Lösung: [leet.c](leet.c)

View File

@ -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/)

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
# Lösung: Array ausgeben
Lösung: [print_array.c](print_array.c)

View File

@ -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/)

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
# Lösung: Array mit Pointer-Arithmetik ausgeben
Lösung: [print_array_pointer.c](print_array_pointer.c)

View File

@ -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/)

View File

@ -0,0 +1,3 @@
# Lösung: String-Verarbeitung
Lösung: [strings.c](strings.c)

View File

@ -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;
}

View File

@ -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/)

View File

@ -0,0 +1,3 @@
# Lösung: String umdrehen
Lösung: [reverse.c](reverse.c)

View File

@ -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;
}

View File

@ -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/)

View File

@ -0,0 +1,5 @@
# Lösung: Vararg Funktion schreiben
Lösung:
* [vararg_sum.c](vararg_sum.c)

View File

@ -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;
}

View File

@ -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/)

View File

@ -0,0 +1,3 @@
# Lösung: typedef verwenden
Lösung: [typedef.c](typedef.c)

View File

@ -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;
}

View File

@ -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/)

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
# Lösung: Dynamische Speicherverwaltung mit malloc und free
Lösung: [malloc_free.c](malloc_free.c)

View File

@ -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/)

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
# Lösung: Funktionspointer benutzen
Lösung: [function_pointer.c](function_pointer.c)

View File

@ -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/)

View File

@ -0,0 +1,3 @@
# Lösung: Struct verwenden
Lösung: [struct_book.c](struct_book.c)

View File

@ -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;
}

View File

@ -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/)

View File

@ -0,0 +1,3 @@
# Lösung: Union verwenden
Lösung: [union.c](union.c)

View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1 @@
obj/

View File

@ -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

View File

@ -0,0 +1,6 @@
#ifndef BENCHMARK_H
#define BENCHMARK_H
#define RUNS 100000000
#endif /* BENCHMARK_H */

View File

@ -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 */

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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)

View File

@ -0,0 +1 @@
obj/

View File

@ -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

View File

@ -0,0 +1,6 @@
#ifndef BENCHMARK_H
#define BENCHMARK_H
#define RUNS 100000000
#endif /* BENCHMARK_H */

View File

@ -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 */

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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/)

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
# Lösung: Datei auf der Konsole aufgeben.
Lösung: [print_file.c](print_file.c)

View File

@ -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/)

View File

@ -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