使用有限的工具,没有数组且没有库函数来评估简单的数学表达式

问题描述

这是去年我大学的第一次“编程入门”考试中的一个问题:

使用getchar()函数读取包含以下内容的输入序列: 数字,+和-号。输出应该是那些的结果 算术运算。

例如,如果输入为10+13-12+25-5+100,则输出应为131

现在,考虑到我在参加uni之前有一点C的经验,使用指针,数组等似乎很容易解决这个问题。

但这是要注意的地方:在考试中,您只能使用到目前为止学生所教过的内容。并且鉴于此考试就像学年开始后一个月一样,您的选项是相当有限的。

您只能使用变量,基本输入/输出内容,运算符(逻辑和按位),条件语句和循环,函数

这意味着没有:数组,字符串,指针,递归,结构,或者基本上是其他任何可以简化此过程的东西。

该怎么办?今天是我第二次花3个小时来解决这个问题。我已经成功解决了它,但是只有在“作弊”并使用数组,字符串函数(strtol)和指针之后才能解决。对我来说,重要的是要知道如何按照规则解决问题,因为我即将参加的考试也有类似的内容。

编辑:到目前为止,我的尝试总计是将while循环与getchar()组合在一起进行输入,之后我被卡住了。如果不使用更多的“工具”,我对应该怎么做一无所知。

解决方法

解决方案非常简单,但对于初学者而言可能并不明显。我不会提供完整的程序,而是概述了仅需几个变量即可实现该程序的步骤。

首先,请注意以下两点很重要:

  1. 您的输入只能包含-+或任何数字(0123456789)之一。
  2. getchar()函数一次将读取一个字符,并在到达输入末尾或发生错误时返回EOF

现在,进入解决方案:

  1. 从循环中一次读取一个字符开始。您只有在达到输入结尾或发生错误时才会停止:

    int c;
    
    while ((c = getchar()) != EOF) {
        // logic here
    }
    
  2. 从将累加器设置为0开始,并在每次遇到数字时向其“添加”数字。

    // outside the loop
    int acc = 0;
    
    // inside the loop
    if (/* c is a digit */)
            acc = acc * 10 + (c = '0');
    

    提示:/* c is a digit */条件可能并不简单,您可以将其放在检查else-的{​​{1}}中。

  3. 每次遇到+-时,请记住该操作,并且每次遇到操作员时,请首先执行上一个操作并重置累加器。

    +
  4. 到达输入的末尾(即退出循环)时,请执行最后一个操作(与// outside the loop int op = 0; int result = 0; // inside the loop if (c == '+' || c == '-') { if (op) { // there already is a previous operation to complete,do it if (op == '+') result += acc; else result -= acc; } else { // first operation encountered,don't do anything yet result = acc; } acc = 0; // reset op = c; // remember the current operation for the future } 中的点3相同的逻辑)。

  5. 输出结果:

    您通常会写类似:

    if

    但是,如果不能使用字符串文字(printf("%d\n",result); )或"%d\n"函数,则必须使用printf()手动进行。这基本上与我们之前将数字扫描到累加器中相反。

    1. 如果需要,请先打印符号,然后将值设置为正值:

      putchar()
    2. 找到小于您的数字的最大乘方10:

      if (result < 0) {
          putchar('-');
          result = -result;
      }
      
    3. 使用幂除法并以10为模对每个数字进行提取和打印:

      int div = 1;
      
      while (result / div / 10)
          div *= 10;        
      

      注意:开头的while (div) { putchar('0' + ((result / div) % 10)); div /= 10; } 用于将数字(从0到10)转换为相对的ASCII字符。

    4. 以换行符结尾:

      '0' +
,

编写解析器时,通常会发现自己“缓冲”了“将要完成的下一个操作”。当输入更改状态时-您正在读取数字,但随后读取了一个操作-然后执行“缓冲”操作并缓冲将来将要执行的下一个操作。

示例:

10+13-12
^^        - we read 10
  ^       - result=10  - we buffer that we *will* have to do + in the future
   ^^     - reading 13
     ^    - och we stopped reading numbers!
            we execute _buffered_ operation `+`,so we do result += 13
            and buffer `-` to be done in the future
      ^^  - we read 12
        ^ - och,EOF! we execute buffered operation `-`,so we do result -= 12
          - etc.

代码:

#include <stdio.h>
int main() {
    int result = 0; // represents current result
    int temp = 0; // the temporary number that we read into
    int op = 0; // represents the _next_ operation that _will_ be done
    while (1) {
        int c = getchar();
        switch (c) {
        // we read an operation,so we should calculate _the previous_ operation
        // or this is end of our string
        case '+': case '-': case EOF:
            if (op == 0) {
                // we have nothing so far,so start with first number
                result = temp;
            } else if (op == '+') {
                result += temp;
            } else if (op == '-') { 
                result -= temp;
            }
            // the next operation we will do in future is stored in op
            op = c;
            // current number starts from 0
            temp = 0;
            break;
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
            // read a digit - increment temporary number
            temp *= 10;
            temp += c - '0';
            break;
        }
        // we quit here,the result for last operation is calculated above
        if (c == EOF) {
            break;
        }
    }
    printf("%d\n",result);
   
    // As I see it was mentioned that "%d\n" is a string,// here's the simplest algorithm for printing digits in a number.
    // Extract one digit from the greatest position and continue up
    // to the last digit in a number.

    // Take negative numbers and throw them out the window.
    if (result < 0) {
         putchar('-');
         result = -result;
    }
    // Our program currently supports printing numbers up to 10000.
    int divisor = 10000;
    // 000100 should print as 100 - we need to remember we printed non-zero
    int was_not_zero = 0;
    while (divisor != 0) {
        // extract one digit at position from divisor
        int digit = result / divisor % 10;
        // if the digit is not zero,or
        // we already printed anything
        if (digit != 0 || was_not_zero) {
            // print the digit
            putchar(digit + '0');
            was_not_zero = 1;
        }
        // the next digit will be to the right
        divisor /= 10;
    }
    putchar('\n');
}
,
#include <string.h>
#include <stdio.h>

void operate(int * sum,int * n,char todo) {
    if (todo == 1)        *sum += *n;
    else if (todo == -1)  *sum -= *n;
    printf("%s %d\n",todo == 1 ? "ADD :" : "SUB :",*n); 
    *n = 0; 
}

int main()
{
    char * problem = "10+13-12+25-5+100";
    int len = strlen(problem);
    int i=0;
    char c;
    int n = 0;
    int sum = 0;
    char todo = 1;
    while(i < len)
    {
        c = problem[i++];
        if (c < 48 || c >= 58) 
        {
            // Adds or subtracts previous and prepare next
            operate(&sum,&n,todo);
            if (c == '+') todo = 1; 
            else if  (c == '-') todo = -1; 
        } 
        else
        {
            // Collects an integer
            if (n) n *= 10;
            n += c - 48;
        } 
    }
    operate(&sum,todo); // Last pass

    printf("SUM => %d\n",sum); // => 131
    return 0;
}
,
#include <stdio.h>

void do_operation(char next_operation,int * result,int * number){
    if (next_operation == '+'){
        *result += *number;
        *number = 0;
    } else if (next_operation == '-'){
        *result -= *number;
        *number = 0;
    } else {
        printf("Unknown operation error.");   
    }
}

int main(int argc,char *argv[]){

    char c;
    int number = 0;
    int result = 0;
    char next_operation = '+';

    do {
        c = getchar();
        if( c >= '0' && c <= '9' ){
            number = number * 10 + c - 48;
        } else if (c == '+'){
            do_operation(next_operation,&result,&number);
            next_operation = '+';
        } else if (c == '-'){
            do_operation(next_operation,&number);
            next_operation = '-';
        } else {
            do_operation(next_operation,&number);
        }
    } while (c != '\n');

    printf("%d",result);
}

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...