写一个忽略操作顺序的C程序?

问题描述 投票:-1回答:2

我想编写一个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()。预先谢谢大家。

c parsing io stdin getline
2个回答
1
投票

捕获了最终数据点的“ 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 */
}

[note:

您已经分配了malloc,甚至没有直接分配,如果line = NULL;n = 0; getline会自己分配足够的空间,所以请不要忘记[ C0]释放已分配的内存(是的,这是在退出时发生的,但是希望您编写的程序中使用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 */
        }

示例使用/输出

例如,在每次进行单独计算之前,使用相同的输入运行上述操作将与子PID产生相同的输出

#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 */
}

试一下,如果您还有其他问题,请告诉我。


3
投票

这不能完全回答问题,但是是一个有趣的小玩具。这不能处理最终数据点,并且无疑需要进行鲁棒化(“ robustification”一词吗?应该是!)。作为读者的练习,重构代码以处理最终输出,并处理非整数值。

© www.soinside.com 2019 - 2024. All rights reserved.