Небольшой бит «робустифицированного» * 1002 * сложения, которое захватывает конечную точку данных, может выглядеть примерно так (использование целочисленного математического выражения намеренно, при желании изменить на число с плавающей запятой):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#define MAX_LINE_LENGTH 200
int main()
{
size_t n = MAX_LINE_LENGTH,
offset = 0;
int oper = 0, v1 = INT_MIN;
char *line = malloc(n);
if (!line) { /* validate every allocation */
perror ("malloc-line");
return 1;
}
printf("Enter equation: ");
if (getline (&line, &n, stdin) == -1) { /* validate every input */
fputs ("stream error or user canceled.\n", stderr);
return 1;
}
for (; line[offset];) { /* loop while not end of line */
int nchar = 0, v2;
if (sscanf (line + offset, "%d%n", &v2, &nchar) == 1) { /* read int? */
if (v1 == INT_MIN) /* if v1 not set, set v1 to value */
v1 = v2;
else { /* otherwise its v2 */
int vsave = v1;
switch (oper) { /* switch on operator, save result in v1 */
case '+': v1 += v2; break;
case '-': v1 -= v2; break;
case '*': v1 *= v2; break;
case '/': v1 /= v2; break;
default: fputs ("error: invalid operator.\n", stderr);
break;
}
/* output results of calculation */
printf ("calculated %d%c%d as %d\n", vsave, oper, v2, v1);
}
offset += nchar; /* update offset with nchars read */
}
else { /* read of int failed, must be oper or end */
size_t used = strcspn (&line[offset], "+-*/"); /* chars to oper */
offset += used; /* update offset */
if (line[offset] == '\n' || line[offset] == 0) /* end of line? */
break;
oper = line[offset++]; /* set oper advance to next char */
}
}
free (line); /* don't forget to free line */
}
( примечание: вы выделили с malloc
и даже пропустили прямое выделение, если line = NULL;
и n = 0;
getline
выделят достаточно места самостоятельно, поэтомуне забудьте free(line);
освободить выделенную вами память (да, здесь это происходит при выходе, но, надеюсь, вы напишете программы, использующие getline
в более чем main()
, так что вырабатывайте хорошие привычки сейчас .. .)
Использование описанного выше спецификатора "%n"
помещает количество символов, потребляемых sscanf
, при чтении в переменную nchars
, которая затем используется для обновления offset
в line
. .
Пример использования / вывода
$ ./bin/calculate
Enter equation: 3 + 4 / 7 + 4 * 2
calculated 3+4 as 7
calculated 7/7 as 1
calculated 1+4 as 5
calculated 5*2 as 10
fork()
Для обработки вычислений
По сути,только изменения, необходимые после того, как ваши v1, v2
и oper
относятся к fork()
процессуЗатем обработайте оператор switch()
в дочернем элементе, а затем в родительском wait()
, пока дочерний элемент не выйдет, прежде чем выйти и захватить ваш следующий набор значений. Как указано в моем комментарии, пример в man 2 wait
дает хорошее представление о процессе.
Исходя из вашего комментария, вы установили fork()
в правильном месте после успешного вызова sscanf
. Там все, что вы делаете, это добавляете вызов к fork()
и проверки и определения которого является дочерним и родительским. Затем переместите существующий расчет в дочерний процесс и добавьте вызов к getpid()
, чтобы добавить его к своему выводу. В родительском процессе зарегистрируйте ваш wait()
и выйдите из него после того, как ваш ребенок закончил.
Вы можете реализовать следующие изменения, внеся указанные выше изменения:
if (sscanf (line + offset, "%d%n", &v2, &nchar) == 1) { /* read int? */
if (v1 == INT_MIN) /* if v1 not set, set v1 to value */
v1 = v2;
else { /* otherwise its v2 */
int status;
pid_t w, pid = fork(); /* fork to compute values */
if (pid == -1) { /* validate fork succeeded */
perror ("fork");
return 1;
}
if (pid == 0) { /* if pid == 0 in child process */
int vsave = v1;
switch (oper) { /* switch on operator, save result in v1 */
case '+': v1 += v2; break;
case '-': v1 -= v2; break;
case '*': v1 *= v2; break;
case '/': v1 /= v2; break;
default: fputs ("error: invalid oper.\n", stderr);
break;
} /* output child PID with results of calculation */
printf ("PID %ld calculated %d%c%d as %d\n",
(long)getpid(), vsave, oper, v2, v1);
}
else { /* in the parent process */
do { /* wait on child PID */
w = waitpid(pid, &status, WUNTRACED | WCONTINUED);
if (w == -1) { /* validate waitpid return */
perror("waitpid");
exit (EXIT_FAILURE);
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit (EXIT_SUCCESS); /* child exited, exit parent */
}
}
offset += nchar; /* update offset with nchars read */
}
Полный пример просто добавляетнеобходимые заголовочные файлы с оставшейся частью кода без изменений. Например:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <sys/wait.h>
#include <unistd.h>
int main (void)
{
size_t n = 0,
offset = 0;
int oper = 0, v1 = INT_MIN;
char *line = NULL;
printf("Enter equation: ");
if (getline (&line, &n, stdin) == -1) { /* validate every input */
fputs ("stream error or user canceled.\n", stderr);
return 1;
}
for (; line[offset];) { /* loop while not end of line */
int nchar = 0, v2;
if (sscanf (line + offset, "%d%n", &v2, &nchar) == 1) { /* read int? */
if (v1 == INT_MIN) /* if v1 not set, set v1 to value */
v1 = v2;
else { /* otherwise its v2 */
int status;
pid_t w, pid = fork(); /* fork to compute values */
if (pid == -1) { /* validate fork succeeded */
perror ("fork");
return 1;
}
if (pid == 0) { /* if pid == 0 in child process */
int vsave = v1;
switch (oper) { /* switch on operator, save result in v1 */
case '+': v1 += v2; break;
case '-': v1 -= v2; break;
case '*': v1 *= v2; break;
case '/': v1 /= v2; break;
default: fputs ("error: invalid oper.\n", stderr);
break;
} /* output child PID with results of calculation */
printf ("PID %ld calculated %d%c%d as %d\n",
(long)getpid(), vsave, oper, v2, v1);
}
else { /* in the parent process */
do { /* wait on child PID */
w = waitpid(pid, &status, WUNTRACED | WCONTINUED);
if (w == -1) { /* validate waitpid return */
perror("waitpid");
exit (EXIT_FAILURE);
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit (EXIT_SUCCESS); /* child exited, exit parent */
}
}
offset += nchar; /* update offset with nchars read */
}
else { /* read of int failed, must be oper or end */
size_t used = strcspn (&line[offset], "+-*/"); /* chars to oper */
offset += used; /* update offset */
if (line[offset] == '\n' || line[offset] == 0) /* end of line? */
break;
oper = line[offset++]; /* set oper advance to next char */
}
}
free (line); /* don't forget to free line */
}
Пример использования / Вывод
Выполнение вышеуказанного с тем же входом даст одинаковый вывод с дочерним PID перед каждым отдельным расчетом, например
$ ./bin/calculate_fork
Enter equation: 3 + 4 / 7 + 4 * 2
PID 18746 calculated 3+4 as 7
PID 18747 calculated 7/7 as 1
PID 18748 calculated 1+4 as 5
PID 18749 calculated 5*2 as 10
Дайте ему знать и дайте мне знать, если у вас есть дополнительные вопросы.