Files
dynamic-array/main.c
2026-02-22 16:50:46 +03:00

428 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
}