Add files via upload

This commit is contained in:
StarFinger
2026-02-22 16:50:46 +03:00
committed by GitHub
commit 9f9f22f22c
8 changed files with 1349 additions and 0 deletions

427
main.c Normal file
View File

@@ -0,0 +1,427 @@
#include <stdio.h>
#include <stddef.h>
#include <time.h>
#include <string.h>
#include "dynamic_array.h"
#include "types.h"
#include "type_info.h"
static void clear_stdin(void) {
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
static int read_int(const char *prompt) {
int val;
printf("%s", prompt);
while (scanf("%d", &val) != 1) {
printf("Ошибка ввода. Повторите: ");
clear_stdin();
}
clear_stdin();
return val;
}
static void read_line(const char *prompt, char *buf, size_t size) {
printf("%s", prompt);
if (!fgets(buf, size, stdin))
buf[0] = '\0';
// Убираем перевод строки
size_t len = strlen(buf);
if (len > 0 && buf[len - 1] == '\n')
buf[len - 1] = '\0';
}
static const TypeInfo *choose_type(void) {
printf("\nВыберите тип элементов:\n");
printf(" 1. Вещественные числа (double)\n");
printf(" 2. Комплексные числа\n");
int choice = read_int("Ваш выбор: ");
switch (choice) {
case 1: return get_double_type();
case 2: return get_complex_type();
default:
printf("Неизвестный тип данных. Используется double.\n");
return get_double_type();
}
}
static bool input_element(const TypeInfo *type, void *dest) {
char buf[512];
if (type == get_double_type()) {
read_line("Введите вещественное число: ", buf, sizeof(buf));
} else if (type == get_complex_type()) {
read_line("Введите комплексное число: ", buf, sizeof(buf));
} else {
printf("Неизвестный тип\n");
return false;
}
return type->parse(dest, buf);
}
// --------------- MAP-функции (для демонстрации) ---------------
static void double_double(void *dest, const void *src) {
*(double *) dest = *(const double *) src * 2;
}
static void double_square(void *dest, const void *src) {
const double v = *(const double *) src;
*(double *) dest = v * v;
}
static void double_negate(void *dest, const void *src) {
*(double *) dest = -(*(const double *) src);
}
static void complex_double(void *dest, const void *src) {
Complex *c_dest = (Complex *) dest;
const Complex *c_src = (const Complex *) src;
c_dest->re = c_src->re * 2;
c_dest->im = c_src->im * 2;
}
static void complex_square(void *dest, const void *src) {
Complex *c_dest = (Complex *) dest;
const Complex *c_src = (const Complex *) src;
c_dest->re = (c_src->re * c_src->re) - (c_src->im * c_src->im);
c_dest->im = 2.0 * (c_src->re * c_src->im);
}
static void complex_negate(void *dest, const void *src) {
Complex *c_dest = (Complex *) dest;
const Complex *c_src = (const Complex *) src;
c_dest->re = -c_src->re;
c_dest->im = -c_src->im;
}
static MapFunc choose_map_func(const TypeInfo *type) {
printf("Выберите функцию для map:\n");
printf(" 1. Удвоить (x * 2)\n");
printf(" 2. Квадрат (x ^ 2)\n");
printf(" 3. Отрицание (-x)\n");
int choice = read_int("Ваш выбор: ");
if (type == get_double_type()) {
switch (choice) {
case 1: return double_double;
case 2: return double_square;
case 3: return double_negate;
default:
printf("Неизвестный тип. Используется 1.\n");
return double_double;
}
} else if (type == get_complex_type()) {
switch (choice) {
case 1: return complex_double;
case 2: return complex_square;
case 3: return complex_negate;
default:
printf("Неизвестный тип. Используется 1.\n");
return complex_double;
}
}
printf("Map не реализован для типа: %s\n", type->type_name);
return NULL;
}
// --------------- WHERE-предикаты (для демонстрации) ---------------
static bool double_is_positive(const void *e) { return *(const double *) e > 0; }
static bool complex_is_real(const void *e) {
const Complex *ce = (Complex *) e;
return ce->im == 0;
}
static Predicate choose_predicate(const TypeInfo *type) {
if (type == get_double_type()) {
printf("Фильтр: положительные числа (x > 0)\n");
return double_is_positive;
} else if (type == get_complex_type()) {
printf("Фильтр: действительные числа.\n");
return complex_is_real;
}
printf("Where не реализован для типа: %s\n", type->type_name);
return NULL;
}
// --------------- REDUCE-функции (для демонстрации) ---------------
static void double_sum(void *acc, const void *elem) {
*(double *) acc += *(const double *) elem;
}
static void complex_sum(void *acc, const void *elem) {
Complex *c_acc = (Complex *) acc;
const Complex *c_elem = (const Complex *) acc;
c_acc->re += c_elem->re;
c_acc->im += c_elem->im;
}
static ReduceFunc choose_reduce(const TypeInfo *type) {
if (type == get_double_type()) {
printf("Функция: сумма вещественных чисел\n");
return double_sum;
} else if (type == get_complex_type()) {
printf("Функция: сумма комплексных чисел.\n");
return complex_sum;
}
printf("Reduce не реализован для типа: %s\n", type->type_name);
return NULL;
}
static void auto_fill(DynamicArray *arr) {
int count = read_int("Количество элементов: ");
if (count <= 0 || count > 10000) {
printf("Некорректное количество.\n");
return;
}
const TypeInfo *type = arr->type; // random -> type
if (type == get_double_type()) {
for (int i = 0; i < count; i++) {
double v = (rand() % 2001 - 1000) / 10.0; // [-100, 100]
da_push_back(arr, &v);
}
} else if (type == get_complex_type()) {
for (int i = 0; i < count; i++) {
Complex c = {
.re = (rand() % 201 - 100) / 10.0,
.im = (rand() % 201 - 100) / 10.0
};
da_push_back(arr, &c);
}
} else {
printf("Автозаполнение не поддерживается для типа: %s\n", type->type_name);
return;
}
printf("Добавлено %d элементов.\n", count);
}
static void print_menu(void) {
printf("\n╔═══════════════════════════════════════╗\n");
printf("║ Полиморфный динамический массив ║\n");
printf("╠═══════════════════════════════════════╣\n");
printf("║ 1. Показать массив ║\n");
printf("║ 2. Добавить элемент (в конец) ║\n");
printf("║ 3. Вставить элемент (по индексу) ║\n");
printf("║ 4. Удалить элемент (по индексу) ║\n");
printf("║ 5. Изменить элемент (по индексу) ║\n");
printf("║ 6. Сортировка ║\n");
printf("║ 7. map (преобразование) ║\n");
printf("║ 8. where (фильтрация) ║\n");
printf("║ 9. reduce (свёртка) ║\n");
printf("║ 10. Конкатенация (создать второй) ║\n");
printf("║ 11. Автозаполнение случайными ║\n");
printf("║ 0. Выход ║\n");
printf("╚═══════════════════════════════════════╝\n");
}
int main(void) {
srand(time(NULL));
// Выбор типа
const TypeInfo *type = choose_type();
DynamicArray *arr = da_create(type, 0);
if (!arr) {
fprintf(stderr, "Не удалось создать массив.\n");
return 1;
}
printf("Создан массив типа: %s\n", type->type_name);
void *elem;
int index;
int choice = -1;
MapFunc map_f;
Predicate pred;
ReduceFunc reduce_f;
// Основной цикл
bool running = true;
while (running) {
print_menu();
choice = read_int(">>> ");
switch (choice) {
case 0:
running = false;
break;
case 1: // Показать
da_print(arr);
break;
case 2: // Добавить в конец
elem = malloc(type->element_size);
memset(elem, 0, type->element_size);
if (input_element(type, elem)) {
if (da_push_back(arr, elem))
printf("Элемент добавлен. Размер: %zu\n", da_size(arr));
else
printf("Ошибка добавления элемента\n");
} else {
printf("Ошибка разбора значения.\n");
}
if (type->destroy)
type->destroy(elem);
free(elem);
break;
case 3: // Вставить
index = read_int("Индекс: ");
elem = malloc(type->element_size);
memset(elem, 0, type->element_size);
if (input_element(type, elem)) {
if (da_insert(arr, index, elem))
printf("Элемент вставлен.\n");
else
printf("Ошибка вставки.\n");
} else {
printf("Ошибка разбора значения.\n");
}
if (type->destroy)
type->destroy(elem);
free(elem);
break;
case 4: // Удалить
index = read_int("Индекс: ");
if (da_remove(arr, index))
printf("Элемент удалён. Размер: %zu\n", da_size(arr));
else
printf("Ошибка удаления.\n");
break;
case 5: // Изменить
index = read_int("Индекс: ");
elem = malloc(type->element_size);
memset(elem, 0, type->element_size);
if (input_element(type, elem)) {
if (da_set(arr, index, elem))
printf("Элемент изменён.\n");
else
printf("Ошибка изменения.\n");
} else {
printf("Ошибка разбора значения.\n");
}
if (type->destroy)
type->destroy(elem);
free(elem);
break;
case 6: // Сортировка
da_sort(arr);
printf("Массив отсортирован.\n");
da_print(arr);
break;
case 7: // map
map_f = choose_map_func(type);
if (!map_f) break;
DynamicArray *mapped = da_map(arr, map_f);
if (!mapped) break;
printf("Результат map:\n");
da_print(mapped);
da_destroy(mapped);
break;
case 8: // where
pred = choose_predicate(type);
if (!pred) break;
DynamicArray *filtered = da_where(arr, pred);
if (!filtered) break;
printf("Результат where:\n");
da_print(filtered);
da_destroy(filtered);
break;
case 9: // reduce
reduce_f = choose_reduce(type);
if (!reduce_f) break;
if (type == get_double_type()) {
double init = 0.0, result = 0.0;
da_reduce(arr, reduce_f, &init, &result);
printf("Результат reduce: ");
type->print(&result);
printf("\n");
} else if (type == get_complex_type()) {
Complex init = {
.re = 0.0,
.im = 0.0
};
Complex result = {
.re = 0.0,
.im = 0.0
};
da_reduce(arr, reduce_f, &init, &result);
printf("Результат reduce: ");
type->print(&result);
printf("\n");
}
break;
case 10: // Конкатенация
printf("Создание второго массива с типом: %s\n", type->type_name);
DynamicArray *b = da_create(type, 0);
int n = read_int("Сколько элементов добавить во второй массив? ");
for (int i = 0; i < n; i++) {
elem = malloc(type->element_size);
memset(elem, 0, type->element_size);
printf("Элемент %d: ", i + 1);
if (input_element(type, elem))
da_push_back(b, elem);
if (type->destroy)
type->destroy(elem);
free(elem);
}
printf("Второй массив:\n");
da_print(b);
DynamicArray *c = da_concat(arr, b);
if (c) {
printf("Результат конкатенации:\n");
da_print(c);
da_destroy(c);
}
da_destroy(b);
break;
case 11: // Автозаполнение
auto_fill(arr);
da_print(arr);
break;
default:
printf("Неизвестная команда.\n");
}
}
da_destroy(arr);
printf("До свидания!\n");
return 0;
}