编写忽略操作顺序的 C 程序?
Writing a C program that ignores the order of operations?
我想编写一个 C 程序,从用户那里获取一个简单的数学问题,并使用不同的进程来解决每个部分,然后将值发送回父进程。这个程序不要讲究操作顺序。例如,如果我有问题:
3 + 4 / 7 + 4 * 2
我希望我的程序输出以下内容:
Enter problem: 3 + 4 / 7 + 4 * 2
PID 20419 calculated 3+4 as 7
PID 20420 calculated 7/7 as 1
PID 20421 calculated 1+4 as 5
PID 20422 calculated 5*2 as 10
Final result: 10
我在解析输入的方程式时遇到了一些问题。我正在考虑使用 C 中的 getline()
方法来帮助我解析输入。这是我目前所拥有的:
#include <stdio.h>
#define MAX_LINE_LENGTH 200
int main()
{
printf("Enter equation: ");
//getline(&buffer, &size, stdin)
//&buffer is the address of the first character
//&size is the address of the variable that holds the size of the input buffer
//stdin is the input file handle
size_t n = MAX_LINE_LENGTH;
//Line becomes a pointer to 200 bytes of memory for you to use
char *line = malloc(n)
while ((getline(&line, &n, stdin)) {
//Parse numbers and operators here
}
return 0;
}
有人对如何解析我将从标准输入输入的数字和运算符有任何建议吗?一旦我认为我读入了数字、运算符和数字,我想使用 fork()
。提前谢谢大家。
这并没有完全回答问题,但它是一个有趣的小玩具。这不处理最终数据点,无疑需要加强("robustification" 是一个词吗?应该是!)。作为 reader 的练习,重构代码以处理最终输出,并处理非整数值。
#include <stdio.h>
#include <ctype.h>
int main(void) {
int c;
int last_op = 0;
float a[2] = {0};
while( ( c = getchar()) != EOF ) {
if(isspace(c)) {
continue;
}
if(isdigit(c)) {
a[1] = 10 * a[1] + c - '0';
} else {
float tmp = a[1];
if( last_op ) {
switch(last_op) {
case '+': tmp = a[0] + a[1]; break;
case '/': tmp = a[0] / a[1]; break;
case '*': tmp = a[0] * a[1]; break;
case '-': tmp = a[0] - a[1]; break;
default: fprintf( stderr, "invalid input: %c", last_op );
}
printf ("calculated %f %c %f = %f\n", a[0], last_op, a[1], tmp);
}
a[0] = tmp;
a[1] = 0;
last_op = c;
}
}
}
一点点 "robustified" 确实获取最终数据点的加法可能类似于以下内容(有意使用整数数学,更改为浮动-如果需要点):
#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
会自己分配足够的 space,所以不要忘记 free(line);
释放你分配的内存。(是的,这里发生在退出时,但希望你会编写使用的程序getline
多于 main()
,所以现在要养成好习惯...)
上面 "%n"
说明符的使用将 sscanf
在读取中消耗的字符数放入 nchars
变量中,然后用于更新 offset
在 line
.
例子Use/Output
$ ./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
中的示例很好地概述了该过程。
根据您的评论,您在 sscanf
调用成功后将 fork()
设置在了正确的位置。您所做的就是添加对 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 */
}
例子Use/Output
运行 以上具有相同输入的内容将在每次单独计算之前产生与子 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
试一试,如果您还有其他问题,请告诉我。
我想编写一个 C 程序,从用户那里获取一个简单的数学问题,并使用不同的进程来解决每个部分,然后将值发送回父进程。这个程序不要讲究操作顺序。例如,如果我有问题:
3 + 4 / 7 + 4 * 2
我希望我的程序输出以下内容:
Enter problem: 3 + 4 / 7 + 4 * 2
PID 20419 calculated 3+4 as 7
PID 20420 calculated 7/7 as 1
PID 20421 calculated 1+4 as 5
PID 20422 calculated 5*2 as 10
Final result: 10
我在解析输入的方程式时遇到了一些问题。我正在考虑使用 C 中的 getline()
方法来帮助我解析输入。这是我目前所拥有的:
#include <stdio.h>
#define MAX_LINE_LENGTH 200
int main()
{
printf("Enter equation: ");
//getline(&buffer, &size, stdin)
//&buffer is the address of the first character
//&size is the address of the variable that holds the size of the input buffer
//stdin is the input file handle
size_t n = MAX_LINE_LENGTH;
//Line becomes a pointer to 200 bytes of memory for you to use
char *line = malloc(n)
while ((getline(&line, &n, stdin)) {
//Parse numbers and operators here
}
return 0;
}
有人对如何解析我将从标准输入输入的数字和运算符有任何建议吗?一旦我认为我读入了数字、运算符和数字,我想使用 fork()
。提前谢谢大家。
这并没有完全回答问题,但它是一个有趣的小玩具。这不处理最终数据点,无疑需要加强("robustification" 是一个词吗?应该是!)。作为 reader 的练习,重构代码以处理最终输出,并处理非整数值。
#include <stdio.h>
#include <ctype.h>
int main(void) {
int c;
int last_op = 0;
float a[2] = {0};
while( ( c = getchar()) != EOF ) {
if(isspace(c)) {
continue;
}
if(isdigit(c)) {
a[1] = 10 * a[1] + c - '0';
} else {
float tmp = a[1];
if( last_op ) {
switch(last_op) {
case '+': tmp = a[0] + a[1]; break;
case '/': tmp = a[0] / a[1]; break;
case '*': tmp = a[0] * a[1]; break;
case '-': tmp = a[0] - a[1]; break;
default: fprintf( stderr, "invalid input: %c", last_op );
}
printf ("calculated %f %c %f = %f\n", a[0], last_op, a[1], tmp);
}
a[0] = tmp;
a[1] = 0;
last_op = c;
}
}
}
一点点 "robustified" 确实获取最终数据点的加法可能类似于以下内容(有意使用整数数学,更改为浮动-如果需要点):
#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
会自己分配足够的 space,所以不要忘记 free(line);
释放你分配的内存。(是的,这里发生在退出时,但希望你会编写使用的程序getline
多于 main()
,所以现在要养成好习惯...)
上面 "%n"
说明符的使用将 sscanf
在读取中消耗的字符数放入 nchars
变量中,然后用于更新 offset
在 line
.
例子Use/Output
$ ./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
中的示例很好地概述了该过程。
根据您的评论,您在 sscanf
调用成功后将 fork()
设置在了正确的位置。您所做的就是添加对 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 */
}
例子Use/Output
运行 以上具有相同输入的内容将在每次单独计算之前产生与子 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
试一试,如果您还有其他问题,请告诉我。