diff --git a/other/Vova`s Proj/main.c b/other/Vova`s Proj/main.c new file mode 100644 index 0000000..18b5dd7 --- /dev/null +++ b/other/Vova`s Proj/main.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int linesWritten = 0; + +void signalHandler(int signal) +{ + printf("Number of lines written: %d\n", linesWritten); +} + +void writeFile(const char *fileName, int numLines, const char *placeholder) +{ + int fd = open(fileName, O_CREAT | O_WRONLY | O_TRUNC, 0666); + + if (fd == -1) + { + printf("Failed to open the file\n"); + exit(EXIT_FAILURE); + } + + if (flock(fd, LOCK_EX) == -1) + { + printf("Failed to lock file for exclusive use\n"); + exit(EXIT_FAILURE); + } + + signal(SIGINT, signalHandler); + + // lseek(fd, 0, SEEK_END); + + for (int i = 0; i < numLines; i++) + { + dprintf(fd, "%s\n", placeholder); + linesWritten++; + + usleep(100000); + } + + if (flock(fd, LOCK_UN) == -1) + { + printf("Failed to unlock file\n"); + exit(EXIT_FAILURE); + } + + close(fd); +} + +int main(int argc, char *argv[]) +{ + if (argc != 4) + { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + const char *fileName = argv[1]; + if (strstr(fileName, ".txt") == NULL) + { + printf("The provided file must be ended with .txt\n"); + exit(EXIT_FAILURE); + } + + int numLines = atoi(argv[2]); + if (numLines <= 0) + { + printf("The number of lines must be a positive integer\n"); + exit(EXIT_FAILURE); + } + + char *placeholder = argv[3]; + while (*placeholder) + { + if (!isalnum(*placeholder) && !isspace(*placeholder)) + { + printf("The placeholder must consist of letters and numbers\n"); + exit(EXIT_FAILURE); + } + placeholder++; + } + + writeFile(fileName, numLines, argv[3]); + + return 0; +} \ No newline at end of file diff --git a/other/Vova`s Proj/out/app b/other/Vova`s Proj/out/app new file mode 100755 index 0000000..6d7c039 Binary files /dev/null and b/other/Vova`s Proj/out/app differ diff --git a/other/Vova`s Proj/readme b/other/Vova`s Proj/readme new file mode 100644 index 0000000..3286ae6 --- /dev/null +++ b/other/Vova`s Proj/readme @@ -0,0 +1,34 @@ +Руководство для пользователя: + +1. Что делают функции: +Функция writeFile отвечает за запись определяемого пользователем количества строк в указанный файл, используя указанную строку в качестве заполнителя. +Обратите внимание: при записи в файл одним процессом другие процессы не будут иметь к нему (к файлу) доступа - они начнут заполнять его только лишь после окончания работы первого. +Файл не перезаписывается новым процессом, а продолжает пополняться новыми строками со следующей после +последней строки. + +Функция signalHandler используется для обработки прерывания программы через сигнал, который подаётся при помощи комбинации клавиш Ctrl+C. + + +2. Как компилировать программу: +Для компиляции программы необходимо использовать компилятор языка C, например gcc. +Пример команды для компиляции программы: открываем терминал, в строке пишем +gcc program.c -o program. +Здесь "program" - название скомпилированного файла, а "program.c" - название файла с исходным кодом программы. + + +4. Как выводить промежуточный результат программы: +Промежуточный результат программы будет выводиться автоматически при нажатии клавиш Ctrl+C. + + +5. Пример использования программы: +Программа принимает три аргумента командной строки: название файла, количество строк для записи и строку-заполнитель. +Например, для записи 10 строк в файл "test.txt" с использованием строки "Hello", необходимо выполнить следующую команду: +./program test.txt 10 Hello. +При этом, промежуточный результат будет выводиться при нажатии клавиш Ctrl+C. + + +6. Предостережения или что НЕ нужно делать, чтобы программа работала корректно: +- использовать для заполнения файлы только с расширением .txt; +- использовать в строке-заполнителе цифры и буквы латинского алфавита, для использования специальных символов (это - &, ', \, |) +именно как элементов строки-заполнителя необходимо для правильной работы программы экранировать их, т.е. использовать \ перед ними; +- использование данной программы предполагается на машинах с предустановленной ОС Debian (12-й версии); \ No newline at end of file diff --git a/other/Vova`s Proj/text.txt b/other/Vova`s Proj/text.txt new file mode 100644 index 0000000..2cf66c7 --- /dev/null +++ b/other/Vova`s Proj/text.txt @@ -0,0 +1,36 @@ +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia +mia diff --git a/patch_note.md b/patch_note.md new file mode 100644 index 0000000..7b2e784 --- /dev/null +++ b/patch_note.md @@ -0,0 +1,3 @@ +1.4 Добавлен вывод графиков функций, добавлена проприетарная функция выхода с возвратом значений настроек системы по умолчанию. + +1.5 Добавлен второй обработчик сигналов для комбинации Ctrl+Z - переход в exit_777(выход из программы с возвратом настроек по умолчанию.) diff --git a/test/ver1.4/Makefile b/project/ver1.4/Makefile similarity index 100% rename from test/ver1.4/Makefile rename to project/ver1.4/Makefile diff --git a/project/ver1.4/README.md b/project/ver1.4/README.md new file mode 100644 index 0000000..344d4d1 --- /dev/null +++ b/project/ver1.4/README.md @@ -0,0 +1,35 @@ +# Function Zeros Calculator + +## Описание +Эта программа предназначена для вычисления нулей функции на языке C в среде Linux. + +## Установка +1. Склонируйте репозиторий: git clone https://github.com/ada-dmitry/tmp_project.git +2. Перейдите в каталог проекта: cd /Project_1.2 + +## Использование +0. Для нормальной работы программы необходимо установить программу GNU PLot + (sudo apt install gnuplot) +1. Соберите программу: make +2. Запустите программу: ./out/function_zeros_calculator +3. Введите необходимые параметры для вычисления нуля функции: a - ЛЕВАЯ граница отрезка + b - ПРАВАЯ граница отрезка, eps > 0 - точность вычисления корня(до 10^-6). + +## Замечания +1. Для корректной работы программы, необходимо вводить отрезок, на котором есть лишь один корень + (это можно проверить благодаря графику). +2. После вызова меню выбора действий (Ctrl+C) можно использовать как верхний регистр, так и нижний. +3. Не рекомендуется бесконечно вызывать Ctrl+C без выбора действия, это может повлечь ошибки + вследствие переполнения памяти. + + +## Обработка сигнала SIGINT + Программа обрабатывает сигнал SIGINT, что позволяет давать пользователю выбор действия +при нажатии сочетания клавиш Ctrl+C. + +## Авторы +Антипенко Дмитрий Андреевич [C22-712] - https://github.com/ada-dmitry/ +Кузнецов Даниил Евгеньевич [C22-712] +Никитин Михаил Андреевич [C22-712] +Ускова Екатерина Александровна [C22-712] + diff --git a/test/ver1.4/declare.h b/project/ver1.4/declare.h similarity index 96% rename from test/ver1.4/declare.h rename to project/ver1.4/declare.h index 7b60d34..572de16 100644 --- a/test/ver1.4/declare.h +++ b/project/ver1.4/declare.h @@ -17,4 +17,4 @@ void newton_method(); double numerical_derivative(double x); void exit_777(); void show_grapgh(); -void input_diap(); \ No newline at end of file +void input_diap(); diff --git a/test/ver1.4/functions.c b/project/ver1.4/functions.c similarity index 97% rename from test/ver1.4/functions.c rename to project/ver1.4/functions.c index f3177b3..c325363 100644 --- a/test/ver1.4/functions.c +++ b/project/ver1.4/functions.c @@ -2,7 +2,7 @@ #include #include #include -#include +// #include #include #include @@ -159,8 +159,9 @@ R - начать поиск на другом отрезке: \n"); if (f(*pa) * f(*pb) > 0) { - printf("В указанных границах нуля функции не существует.\n"); - printf("Нажмите Ctrl+C и поменяйте границы\n"); + printf("\nВ указанных границах нуля функции не существует.\n"); + printf("Поменяйте границы\n"); + choose_path(); } if (*pa == *pb) { @@ -255,7 +256,7 @@ void input_diap() } __fpurge(stdin); - printf("Выберите метод вычисления корня:\ + printf("Выберите метод вычисления корня и нажмите Enter:\ 0 - метод вилки, 1 - метод хорд, 2 - метод касательных\n(По умолчанию: 0): "); *mth = getchar(); diff --git a/test/ver1.4/main.c b/project/ver1.4/main.c similarity index 66% rename from test/ver1.4/main.c rename to project/ver1.4/main.c index ba324ed..bf5954b 100644 --- a/test/ver1.4/main.c +++ b/project/ver1.4/main.c @@ -18,13 +18,13 @@ int main() pb = &b; px = &x; - struct sigaction sig; // Инициализация структуры, отвечающей за обработку сигнала. + struct sigaction sig_int; // Инициализация структуры, отвечающей за обработку сигнала. // Замена стандартного алгоритма на необходимый для вызова меню действий. - sig.sa_handler = ctrlc_handler; - sig.sa_flags = 0; // Очистка флагов "на всякий случай". - sigemptyset(&sig.sa_mask); // Очистка маски "на всякий случай". + sig_int.sa_handler = ctrlc_handler; + sig_int.sa_flags = 0; // Очистка флагов "на всякий случай". + sigemptyset(&sig_int.sa_mask); // Очистка маски "на всякий случай". - if (sigaction(SIGINT, &sig, NULL) == -1) // Обработчик ошибок и инициализация сигнала SIGINT. + if (sigaction(SIGINT, &sig_int, NULL) == -1) // Обработчик ошибок и инициализация сигнала SIGINT. { perror("sigaction"); return 1; diff --git a/test/ver1.4/out/function_zeros_calculator b/project/ver1.4/out/app similarity index 76% rename from test/ver1.4/out/function_zeros_calculator rename to project/ver1.4/out/app index f06347b..84ae7f9 100755 Binary files a/test/ver1.4/out/function_zeros_calculator and b/project/ver1.4/out/app differ diff --git a/project/ver1.4/out/function_zeros_calculator b/project/ver1.4/out/function_zeros_calculator new file mode 100755 index 0000000..75b4bd6 Binary files /dev/null and b/project/ver1.4/out/function_zeros_calculator differ diff --git a/test/ver1.5/Makefile b/test/ver1.5/Makefile new file mode 100644 index 0000000..92fa3cb --- /dev/null +++ b/test/ver1.5/Makefile @@ -0,0 +1,26 @@ +# Это комментарий, который говорит, что переменная CC указывает компилятор, используемый для сборки +CC= gcc +#Это еще один комментарий. Он поясняет, что в переменной CFLAGS лежат флаги, которые передаются компилятору +CFLAGS= -c -Wall + +default: build + +general: main.o functions.o + killall -9 function_zeros_calculator + $(CC) ./out/main.o ./out/functions.o -o ./out/function_zeros_calculator -lm + +main.o: main.c + $(CC) $(CFLAGS) main.c -o ./out/main.o + +functions.o: functions.c + + $(CC) $(CFLAGS) functions.c -o ./out/functions.o + +clean: + rm -rf ./out/main.o ./out/functions.o + + +build: general clean + +run: + ./out/function_zeros_calculator \ No newline at end of file diff --git a/test/ver1.4/README b/test/ver1.5/README similarity index 94% rename from test/ver1.4/README rename to test/ver1.5/README index 50a1fba..344d4d1 100644 --- a/test/ver1.4/README +++ b/test/ver1.5/README @@ -16,7 +16,8 @@ b - ПРАВАЯ граница отрезка, eps > 0 - точность вычисления корня(до 10^-6). ## Замечания -1. Для корректной работы программы, необходимо вводить отрезок, на котором есть лишь один корень. +1. Для корректной работы программы, необходимо вводить отрезок, на котором есть лишь один корень + (это можно проверить благодаря графику). 2. После вызова меню выбора действий (Ctrl+C) можно использовать как верхний регистр, так и нижний. 3. Не рекомендуется бесконечно вызывать Ctrl+C без выбора действия, это может повлечь ошибки вследствие переполнения памяти. diff --git a/test/ver1.5/declare.h b/test/ver1.5/declare.h new file mode 100644 index 0000000..6a9a50a --- /dev/null +++ b/test/ver1.5/declare.h @@ -0,0 +1,21 @@ +extern double a, b, eps, x, *pa, *pb, *px; +extern short method, *mth, sig_flag; + +// Декларирование глобальных переменных, +// как внешних для последующего использования их во всей программе. +#define H 0.000001 +#define A 0 +#define B 100000000 +#define EPS 0.001 + +double f(double x); +void ctrlc_handler(int signum); +void ctrlz_handler(int signum); +void choose_path(); +void fork_method(); +void chord_method(); +void newton_method(); +double numerical_derivative(double x); +void exit_777(); +void show_grapgh(); +void input_diap(); diff --git a/test/ver1.5/functions.c b/test/ver1.5/functions.c new file mode 100644 index 0000000..86cef3e --- /dev/null +++ b/test/ver1.5/functions.c @@ -0,0 +1,305 @@ +#include +#include +#include +#include +// #include +#include +#include + +#include "declare.h" + +double f(double x) // Функция, заданная пользователем, для которой происходит поиск корней. +{ + return x - x * x + 1349; +} + +void show_grapgh() +{ + struct termios old_term, new_term; + + tcgetattr(STDIN_FILENO, &old_term); + new_term = old_term; + new_term.c_lflag &= ~(ECHO | ICANON); + tcsetattr(STDIN_FILENO, TCSANOW, &new_term); + + char func[100] = "x - x * x + 1349"; + + // Подключение GNU Plot + FILE *gp = popen("gnuplot -persist", "w"); + + if (gp == NULL) + { + printf("GNUerror\n"); + exit(3); + } + fprintf(gp, "set xrange [-500:500]\n"); + fprintf(gp, "set yrange [0:500]\n"); + fprintf(gp, "plot %s\n", func); + fflush(gp); // очищение буфера вывода + sig_flag = 1; + printf("Нажмите любую клавишу, чтобы продолжить...\n"); + getchar(); + sig_flag = 0; + fprintf(gp, "exit\n"); + tcsetattr(STDIN_FILENO, TCSANOW, &old_term); + return; +} + +// Приближенное вычисление производной по методу конечных разностей +double numerical_derivative(double x) +{ + return (f(x + H) - f(x)) / H; +} + +void newton_method() +{ + *pb = *pa; + do + { + printf("%lf %lf\n", *pa, *pb); + *pa = *pb; + *pb = *pa - f(*pa) / numerical_derivative(*pa); + // Используем численно вычисленную производную + *px = *pb; + sleep(1); + } while (fabs(*pb - *pa) > eps && f(x) != 0); + return; +} + +void chord_method() +{ + *px = *pa; + while ((*pb - *pa) > eps && f(x) != 0) + { + // Находим точку пересечения хорды с осью x + *px = (*pa * f(*pb) - *pb * f(*pa)) / (f(*pb) - f(*pa)); + printf("%lf %lf\n", *pa, *pb); + // Проверяем знаки функции в точках a и x + if (f(*px) == 0) + break; + else if (f(*px) * f(*pa) < 0) + *pb = *px; + else + *pa = *px; + sleep(1); + } + return; +} + +void fork_method() // Функция поиска корней, использующая метод вилки. +{ + do + { + *px = (*pa + *pb) / 2; // метод деления отрезка пополам + + // Печать границ для отладки и для отслеживания хода вычислений + printf("%lf %lf\n", *pa, *pb); + + // Проверка, какой из отрезков [a, x] или [x, b] подходит под условие существования корня, + // т.е. различие знаков на границе. + + if (f(*pa) * f(x) <= 0) + *pb = x; + else if (f(*pb) * f(x) <= 0) + *pa = x; + + sleep(1); // Принудительное ожидание программой, для возможности прерывания пользователем. + + } while (fabs(*pb - *pa) > eps && f(x) != 0); + return; +} + +void choose_path() // Функция выбора действия после вызова сигнала. +{ + sig_flag = 1; + + char choice; + + struct termios default_term, modif_term; // Задание структуры, определяющей терминал Linux. + + // Получение текущих настроек терминала + tcgetattr(0, &default_term); + modif_term = default_term; + // Отключение символа ECHO + modif_term.c_lflag &= ~(ECHO | ICANON); + // Применение новых настроек терминала + tcsetattr(0, TCSANOW, &modif_term); + + printf("\nПродолжить поиск корня?\n"); + printf("\nC - продолжить, A - закончить работу программы, \ +R - начать поиск на другом отрезке: \n"); + + do + { + // Очистка стандартного потока ввода от "лишних" + __fpurge(stdin); + choice = getchar(); + // scanf("%c", &choice); // Запись буквы, введенной пользователем в переменную choice. + switch (choice) + { + case 'C': // Выбор вида "Продолжить вычисление". + case 'c': + sig_flag = 0; + return; // Выход из функции без каких-либо изменений. + + case 'A': // Выбор вида "Завершить вычисление". + case 'a': + printf("\nКорень уравнения: %lf\n", *px); + printf("Работа программы завершена.\n"); + exit_777(); // Принудительное завершение программы с выводом текущего приближения корня. + + case 'R': // Выбор вида "Продолжить вычисления с новым отрезком". + case 'r': + // Возврат к обычному выводу + tcsetattr(0, TCSANOW, &default_term); + + printf("Введите новые значения границ a и b: "); + + scanf("%lf%lf", pa, pb); + + if (f(*pa) * f(*pb) > 0) + { + printf("\nВ указанных границах нуля функции не существует.\n"); + printf("Поменяйте границы\n"); + choose_path(); + } + if (*pa == *pb) + { + if (f(*pa) == 0) + { + printf("\nКорень уравнения: %lf\n", *pa); + printf("Работа программы завершена.\n"); + exit_777(); + } + else + { + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + } + + sig_flag = 0; + return; + + default: + printf("Ошибка ввода, повторная попытка...\n"); + __fpurge(stdin); + } + } while (choice != 'A' || choice != 'R' || choice != 'C' || choice != 'a' || choice != 'r' || choice != 'c' || choice != 'M' || choice != 'm'); + + // Применение новых настроек терминала + tcsetattr(0, TCSANOW, &default_term); + + sig_flag = 0; +} + +void ctrlc_handler(int signum) // Функция, заменяющая стандартный алгоритм для сигнала SIGINT. +{ + if (sig_flag == 0) + { + printf("\nТекущее приближение: %lf\n", *px); + choose_path(); + } + return; +} + +void ctrlz_handler(int signum) +{ + printf("Аварийное завершение программы, возврат к настройкам по умолчанию..."); + exit_777(); +} + +void exit_777() +{ + struct termios term; + tcgetattr(0, &term); + term.c_lflag |= ~ECHO; + tcsetattr(0, TCSANOW, &term); + exit(1); +} + +void input_diap() +{ + double tmp; + char input[50]; + sig_flag = 1; + printf("\nПоочередно вводите через Enter: левую границу, правую и точность\n\ +(или нажимайте Enter для значений по умолчанию: -10000/10000/0.0001): "); + + // printf("Введите левую границу отрезка (или нажмите Enter для значения по умолчанию): "); + fgets(input, sizeof(input), stdin); + + if (input[0] == '\n') + { + *pa = A; // значение по умолчанию + } + else + { + sscanf(input, "%lf", pa); + } + + // printf("Введите правую границу отрезка (или нажмите Enter для значения по умолчанию): "); + fgets(input, sizeof(input), stdin); + + if (input[0] == '\n') + { + *pb = B; // значение по умолчанию + } + else + { + sscanf(input, "%lf", pb); + } + + // printf("Введите точность вычисления (или нажмите Enter для значения по умолчанию): "); + fgets(input, sizeof(input), stdin); + + if (input[0] == '\n') + { + eps = EPS; // значение по умолчанию + } + else + { + sscanf(input, "%lf", &eps); + } + + __fpurge(stdin); + printf("Выберите метод вычисления корня и нажмите Enter:\ + 0 - метод вилки, 1 - метод хорд, 2 - метод касательных\n(По умолчанию: 0): "); + *mth = getchar(); + + if (*pa > *pb) // Если пользователь перепутал границы + { + printf("Границы указаны неверно, запуск задачи с исправленным условием\n"); + tmp = *pa; + *pa = *pb; + *pb = tmp; + } + + if (f(*pa) * f(*pb) > 0) + { + sig_flag = 0; + printf("В указанных границах нуля функции не существует.\n"); + printf("Поменяйте границы\n"); + choose_path(); + } + if (eps < 0) // Если пользователь указал отрицательную точность + { + eps = eps * (-1); + printf("Точность отрицательна, условие приведено в порядок, запуск решения...\n"); + } + + if (*pa == *pb) + { + if (f(*pa) == 0) + { + printf("\nКорень уравнения: %lf\n", *pa); + printf("Работа программы завершена.\n"); + exit_777(); + } + else + { + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + } + sig_flag = 0; + return; +} \ No newline at end of file diff --git a/test/ver1.5/main.c b/test/ver1.5/main.c new file mode 100644 index 0000000..dfbd1dd --- /dev/null +++ b/test/ver1.5/main.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include + +#include "declare.h" + +double a, b, eps, x, *pa, *pb, *px; +short method, *mth, sig_flag; + +int main() +{ + sig_flag = 0; + method = 0; + mth = &method; + pa = &a; + pb = &b; + px = &x; + + struct sigaction sig_int, sig_tstp; // Инициализация структуры, отвечающей за обработку сигнала. + // Замена стандартного алгоритма на необходимый для вызова меню действий. + sig_int.sa_handler = ctrlc_handler; + sig_int.sa_flags = 0; // Очистка флагов "на всякий случай". + sigemptyset(&sig_int.sa_mask); // Очистка маски "на всякий случай". + sig_tstp.sa_handler = ctrlz_handler; + sig_tstp.sa_flags = 0; + sigemptyset(&sig_tstp.sa_mask); + + if (sigaction(SIGINT, &sig_int, NULL) == -1) // Обработчик ошибок и инициализация сигнала SIGINT. + { + perror("sigaction"); + return 1; + } + if (sigaction(SIGTSTP, &sig_tstp, NULL) == -1) // Обработчик ошибок и инициализация сигнала SIGTSTP. + { + perror("sigaction"); + return 1; + } + + show_grapgh(); + input_diap(); + + if (*mth == 0) + { + printf("Fork\n"); + fork_method(); + } + else if (*mth == 1) + { + printf("Chord\n"); + chord_method(); + } + else if (*mth == 2) + { + printf("Newton\n"); + newton_method(); + } + else + { + printf("Fork\n"); + fork_method(); + } + + printf("\nКорень уравнения: %lf\n", *px); + printf("Работа программы завершена.\n"); + + return 0; +} + +// MEEEEEEEOW \ No newline at end of file diff --git a/test/ver1.5/out/app b/test/ver1.5/out/app new file mode 100755 index 0000000..84ae7f9 Binary files /dev/null and b/test/ver1.5/out/app differ diff --git a/test/ver1.5/out/function_zeros_calculator b/test/ver1.5/out/function_zeros_calculator new file mode 100755 index 0000000..75b4bd6 Binary files /dev/null and b/test/ver1.5/out/function_zeros_calculator differ