1.4 to prod
This commit is contained in:
ada-dmitry
2023-12-08 12:59:45 +03:00
parent fd68d8046e
commit 4e08a3ad71
19 changed files with 636 additions and 11 deletions
+92
View File
@@ -0,0 +1,92 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
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 <filename> <number of lines> <placeholder>\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;
}
BIN
View File
Binary file not shown.
+34
View File
@@ -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-й версии);
+36
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
1.4 Добавлен вывод графиков функций, добавлена проприетарная функция выхода с возвратом значений настроек системы по умолчанию.
1.5 Добавлен второй обработчик сигналов для комбинации Ctrl+Z - переход в exit_777(выход из программы с возвратом настроек по умолчанию.)
+35
View File
@@ -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]
@@ -17,4 +17,4 @@ void newton_method();
double numerical_derivative(double x);
void exit_777();
void show_grapgh();
void input_diap();
void input_diap();
@@ -2,7 +2,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <signal.h>
// #include <signal.h>
#include <termios.h>
#include <stdio_ext.h>
@@ -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();
+5 -5
View File
@@ -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;
Binary file not shown.
+26
View File
@@ -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
+2 -1
View File
@@ -16,7 +16,8 @@
b - ПРАВАЯ граница отрезка, eps > 0 - точность вычисления корня(до 10^-6).
## Замечания
1. Для корректной работы программы, необходимо вводить отрезок, на котором есть лишь один корень.
1. Для корректной работы программы, необходимо вводить отрезок, на котором есть лишь один корень
(это можно проверить благодаря графику).
2. После вызова меню выбора действий (Ctrl+C) можно использовать как верхний регистр, так и нижний.
3. Не рекомендуется бесконечно вызывать Ctrl+C без выбора действия, это может повлечь ошибки
вследствие переполнения памяти.
+21
View File
@@ -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();
+305
View File
@@ -0,0 +1,305 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
// #include <signal.h>
#include <termios.h>
#include <stdio_ext.h>
#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;
}
+71
View File
@@ -0,0 +1,71 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <stdio_ext.h>
#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
BIN
View File
Binary file not shown.
Binary file not shown.