Add Final Project: Todo-App in C

This commit is contained in:
2026-04-15 00:18:50 +02:00
parent 46fd5ce627
commit 01790a0f39

View File

@@ -0,0 +1,263 @@
// ============================================
// Final-Projekt: Todo-App in C
// Ein vollständiges CLI-Programm mit CRUD-Operationen
// ============================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#define MAX_TODOS 100
#define MAX_TITLE 100
#define MAX_DESC 500
#define DATA_FILE "todos.dat"
// Datenstruktur für ein Todo
typedef struct {
int id;
char title[MAX_TITLE];
char description[MAX_DESC];
bool completed;
time_t created_at;
} Todo;
// Datenstruktur für die Todo-Liste
typedef struct {
Todo items[MAX_TODOS];
int count;
} TodoList;
// Funktionsprototypen
void todo_init(TodoList* list);
void todo_add(TodoList* list, const char* title, const char* description);
void todo_list(const TodoList* list);
void todo_complete(TodoList* list, int id);
void todo_delete(TodoList* list, int id);
void todo_save(const TodoList* list);
void todo_load(TodoList* list);
void print_menu(void);
void clear_input_buffer(void);
// ============================================
// IMPLEMENTATION
// ============================================
void todo_init(TodoList* list) {
list->count = 0;
for (int i = 0; i < MAX_TODOS; i++) {
list->items[i].id = 0;
list->items[i].title[0] = '\0';
list->items[i].description[0] = '\0';
list->items[i].completed = false;
list->items[i].created_at = 0;
}
}
void todo_add(TodoList* list, const char* title, const char* description) {
if (list->count >= MAX_TODOS) {
printf("Fehler: Maximale Anzahl erreicht!\n");
return;
}
Todo* new_todo = &list->items[list->count];
new_todo->id = list->count + 1;
strncpy(new_todo->title, title, MAX_TITLE - 1);
new_todo->title[MAX_TITLE - 1] = '\0';
strncpy(new_todo->description, description, MAX_DESC - 1);
new_todo->description[MAX_DESC - 1] = '\0';
new_todo->completed = false;
new_todo->created_at = time(NULL);
list->count++;
printf("Todo #%d hinzugefügt!\n", new_todo->id);
}
void todo_list(const TodoList* list) {
if (list->count == 0) {
printf("Keine Todos vorhanden.\n");
return;
}
printf("\n=== DEINE TODOS ===\n");
printf("%-4s | %-10s | %-30s | %-20s\n", "ID", "Status", "Titel", "Erstellt");
printf("-----+------------+--------------------------------+--------------------\n");
for (int i = 0; i < list->count; i++) {
const Todo* todo = &list->items[i];
char date_str[26];
ctime_r(&todo->created_at, date_str);
date_str[24] = '\0'; // Remove newline
const char* status = todo->completed ? "[✓] Done " : "[ ] Open ";
printf("%-4d | %s | %-30s | %.20s\n",
todo->id, status, todo->title, date_str);
if (strlen(todo->description) > 0) {
printf(" | | %s\n", todo->description);
}
}
printf("\n");
}
void todo_complete(TodoList* list, int id) {
for (int i = 0; i < list->count; i++) {
if (list->items[i].id == id) {
list->items[i].completed = !list->items[i].completed;
printf("Todo #%d %s!\n", id,
list->items[i].completed ? "abgeschlossen" : "wieder geöffnet");
return;
}
}
printf("Fehler: Todo #%d nicht gefunden!\n", id);
}
void todo_delete(TodoList* list, int id) {
int found_index = -1;
for (int i = 0; i < list->count; i++) {
if (list->items[i].id == id) {
found_index = i;
break;
}
}
if (found_index == -1) {
printf("Fehler: Todo #%d nicht gefunden!\n", id);
return;
}
// Array komprimieren
for (int i = found_index; i < list->count - 1; i++) {
list->items[i] = list->items[i + 1];
list->items[i].id = i + 1; // ID neu zuweisen
}
list->count--;
printf("Todo #%d gelöscht!\n", id);
}
void todo_save(const TodoList* list) {
FILE* file = fopen(DATA_FILE, "wb");
if (!file) {
printf("Fehler: Konnte Datei nicht öffnen!\n");
return;
}
fwrite(&list->count, sizeof(int), 1, file);
fwrite(list->items, sizeof(Todo), list->count, file);
fclose(file);
printf("Todos gespeichert!\n");
}
void todo_load(TodoList* list) {
FILE* file = fopen(DATA_FILE, "rb");
if (!file) {
printf("Keine gespeicherte Daten gefunden. Starte neu...\n");
return;
}
fread(&list->count, sizeof(int), 1, file);
fread(list->items, sizeof(Todo), list->count, file);
fclose(file);
printf("%d Todos geladen!\n", list->count);
}
void print_menu(void) {
printf("\n=== TODO-APP ===\n");
printf("1. Todo hinzufügen\n");
printf("2. Todos anzeigen\n");
printf("3. Todo abschließen/öffnen\n");
printf("4. Todo löschen\n");
printf("5. Speichern\n");
printf("6. Beenden\n");
printf("Wahl: ");
}
void clear_input_buffer(void) {
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
// ============================================
// HAUPTPROGRAMM
// ============================================
int main(void) {
TodoList list;
todo_init(&list);
todo_load(&list);
int choice;
char title[MAX_TITLE];
char description[MAX_DESC];
int id;
printf("\n📝 Willkommen zur Todo-App!\n");
while (true) {
print_menu();
if (scanf("%d", &choice) != 1) {
clear_input_buffer();
printf("Ungültige Eingabe!\n");
continue;
}
clear_input_buffer();
switch (choice) {
case 1:
printf("Titel: ");
fgets(title, MAX_TITLE, stdin);
title[strcspn(title, "\n")] = '\0'; // Remove newline
printf("Beschreibung (optional): ");
fgets(description, MAX_DESC, stdin);
description[strcspn(description, "\n")] = '\0';
todo_add(&list, title, description);
break;
case 2:
todo_list(&list);
break;
case 3:
printf("Todo-ID: ");
if (scanf("%d", &id) == 1) {
todo_complete(&list, id);
}
clear_input_buffer();
break;
case 4:
printf("Todo-ID: ");
if (scanf("%d", &id) == 1) {
todo_delete(&list, id);
}
clear_input_buffer();
break;
case 5:
todo_save(&list);
break;
case 6:
printf("Speichern vor Beenden? (j/n): ");
char save_choice;
scanf(" %c", &save_choice);
if (save_choice == 'j' || save_choice == 'J') {
todo_save(&list);
}
printf("Auf Wiedersehen!\n");
return 0;
default:
printf("Ungültige Wahl!\n");
}
}
return 0;
}