Прокомментировать код вычисления факториала - C (СИ)
Формулировка задачи:
Здравствуйте, прокомментируйте пожалуйста пример задачи,если можно конечно, я его совсем не поняла(
ну и расскажите алгоритм,умоляю)
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int fact(int a);
int main(int argv, char *args[])
{
int n = atoi(args[1]);
int k = atoi(args[2]);
int nk = n-k;
char* nc = args[1];
char* kc = args[2];
char nkc[10];
sprintf(nkc, "%i", nk);
char temp1[10], temp2[10], temp3[10];
int p1,p2,p3;
int *st;
int fd1[2], fd2[2], fd3[2];
pipe(fd1);
pipe(fd2);
pipe(fd3);
if(p1=fork())
{
if(p2=fork())
{
if(p3=fork())
{
read(fd1[0], temp1, 20);
read(fd2[0], temp2, 20);
read(fd3[0], temp3, 20);
n = atoi(temp1);
k = atoi(temp2);
nk = atoi(temp3);
int ret = n/(k*nk);
printf("%i\n", ret);
return 0;
}
else
{
dup2(fd3[1], 1);
close(fd3[1]);
execl("fact", "", nkc, NULL);
}
}
else
{
dup2(fd2[1], 1);
close(fd2[1]);
execl("fact", "", kc, NULL);
}
}
else
{
dup2(fd1[1], 1);
close(fd1[1]);
execl("fact", "", nc, NULL);
}
return 0;
}Решение задачи: «Прокомментировать код вычисления факториала»
textual
Листинг программы
#include <stdio.h>
#include <stdlib.h>
/* Программа рабоатет только под линукс, об этом говорят эти два хедера */
#include <sys/types.h>
#include <sys/wait.h>
int fact(int a);
int main(int argv, char *args[])
{
/*
* args[1] и args[2] - это параметры, которые передаются программе из командной строки
* допустим программа называется FACTORIAL. Если в командной строке вызвать программу
* так - anon@anon:./FACT 3 5, то
* args[1] будет равнятся 3, args[2] - 0. Нумерация идет с 0 конечно же, но 0 в нашем случае
* это само имя программы (FACTORIAL). args[3] - соответственно четвертый параметр.
*/
/*
* args[] - это массив строк (вверху в main можно увидеть char *args[]),
* точнее указатель на массив символов. То есть передавая значения в программу,
* способом, который я указал выше, мы передаем символы, а не целочисленные
* значения. Чтобы присвоить эти символы целому числу, мы применяем к параметрам
* функцию atoi. Она конвертирует строку в число !
*/
/*
* Итак, в n у нас первый параметр, в k второй.
* Очевидно что nk - это разность передаваемых параметров :)
*/
int n = atoi(args[1]);
int k = atoi(args[2]);
int nk = n-k;
/*
* Далее создаются указатели nc,kc на 1 и 2 параметры
*/
char* nc = args[1];
char* kc = args[2];
char nkc[10];
/* sprintf - это тоже самое что и printf
* только вывод делается не в консоль, а в строку
* В данном случае, в строку nkc запишется разность
* передаваемых параметров
*/
sprintf(nkc, "%i", nk);
/* Судя по названию, временные массивы*/
char temp1[10], temp2[10], temp3[10];
int p1,p2,p3;
int *st;
int fd1[2], fd2[2], fd3[2];
/*
* pipe - это функция, которая создает pipe :)
* Pipe - это механизм межпроцессорного взаимодействия (IPC)
* гуглите и будет вам чудо
* в кратце: pipe позволяет обмениваться данными
* двум запущенным программам,так же как сокеты
* позволяют общаться двум компьютерам в сети
* (они тоже относятся к IPC)
* функция pipe() создает канал для обмена данными.
* Ниже в коде, ей передается массив из двух элементов
* в который по окончанию работы функции, будут записаны
* два файловых дескриптора. Файловый дескриптор - это
* идентификатор файла в системе линукс, обычное число.
* В этой программе, пайпы созданы для того, чтобы
* ОБМЕНИВАТЬСЯ ДАННЫМИ С ДОЧЕРНИМИ ПРОЦЕССАМИ
* далее станет ясно
*/
pipe(fd1);
pipe(fd2);
pipe(fd3);
/*
* Весь код выше был подготовкой
* сама логика программы ниже
*/
/*
* Функция fork() создает дочерний процесс
* Тут их создается три. То есть наша программа
* порождает 3 дополнительных процесса, вложенные друг в друга.
*/
if(p1=fork())
{
/* Породили один процесс*/
if(p2=fork())
{
/* Он породил другой процесс*/
if(p3=fork())
{
/*второй породил третий процесс*/
/*
* Здесь мы окажемся, если
* успешно созданы все три процесса
*/
/*
* У пайпа есть два конца. fd1[0] и fd[1] например,
* первый конец канала (fd1[0]) относится к стороне с который
* СЧИТЫВАЮТ ДАННЫЕ, второй конец (fd1[1]) - КУДА ЗАПИСЫВАЮТСЯ
* Во временные массивы записываются данные из первых
* концов pipe'а. Ровно 20 элементов.
*/
read(fd1[0], temp1, 20);
read(fd2[0], temp2, 20);
read(fd3[0], temp3, 20);
/*
* temp - это строки, они конвертируются в числа
*/
n = atoi(temp1);
k = atoi(temp2);
nk = atoi(temp3);
/*
* ret - это походу конечный результат
*
*/
int ret = n/(k*nk);
printf("%i\n", ret);
return 0;
}
/* В else запускается программа fact с разными паарметрами
*/
else
{
dup2(fd3[1], 1);
close(fd3[1]);
execl("fact", "", nkc, NULL);
}
}
else
{
dup2(fd2[1], 1);
close(fd2[1]);
execl("fact", "", kc, NULL);
}
}
else
{
dup2(fd1[1], 1);
close(fd1[1]);
execl("fact", "", nc, NULL);
}
return 0;
}
Объяснение кода листинга программы
Код выполняет вычисление факториала с помощью рекурсии.
int fact(int a);- объявление функции fact, которая вычисляет факториал числа a.int main(int argv, char *args[])- объявление функции main, которая является точкой входа в программу.args[1]иargs[2]- это параметры, передаваемые программе из командной строки.int n = atoi(args[1]);иint k = atoi(args[2]);- присваивание значения первого и второго параметров функции main переменным n и k соответственно.int nk = n-k;- вычисление разности между n и k и присвоение результата переменной nk.char* nc = args[1];иchar* kc = args[2];- присваивание адреса первого и второго параметров функции main переменным nc и kc соответственно.char nkc[10];- объявление временного массива строкового типа nkc размером 10 символов.sprintf(nkc,%i, nk);- использование функции sprintf для записи разности n и k в переменную nkc в виде строки.int p1,p2,p3;- объявление переменных p1, p2 и p3 для хранения результатов fork.int *st;- объявление указателя st на целочисленный массив.pipe(fd1);- создание pipe с помощью функции pipe и сохранение его в переменной fd1.pipe(fd2);- создание pipe с помощью функции pipe и сохранение его в переменной fd2.pipe(fd3);- создание pipe с помощью функции pipe и сохранение его в переменной fd3.if(p1=fork())- вызов функции fork для создания дочернего процесса. Если p1 не равно нулю, это означает, что родительский процесс.if(p2=fork())- вызов функции fork для создания дочернего процесса. Если p2 не равно нулю, это означает, что родительский процесс.if(p3=fork())- вызов функции fork для создания дочернего процесса. Если p3 не равно нулю, это означает, что родительский процесс.read(fd1[0], temp1, 20);- чтение данных из первого конца pipe, сохраненного в fd1[0], во временный массив temp1.read(fd2[0], temp2, 20);- чтение данных из первого конца pipe, сохраненного в fd2[0], во временный массив temp2.read(fd3[0], temp3, 20);- чтение данных из первого конца pipe, сохраненного в fd3[0], во временный массив temp3.n = atoi(temp1);- конвертация временного массива temp1 в целое число и присвоение результата переменной n.k = atoi(temp2);- конвертация временного массива temp2 в целое число и присвоение результата переменной k.nk = atoi(temp3);- конвертация временного массива temp3 в целое число и присвоение результата переменной nk.int ret = n/(k*nk);- вычисление результата и присвоение его переменной ret.printf(%i\n, ret);- вывод результата на консоль.return 0;- возврат нуля, указывающего на успешное выполнение программы.