Прокомментировать код вычисления факториала - 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;
- возврат нуля, указывающего на успешное выполнение программы.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д