首页 > 解决方案 > 计算错误,用+代替-

问题描述

出于培训原因,我想编写一个小计算器。为什么计算 10-6 = 16 而不是 10-6 = 4?

我得到了错误:

Assertion Failed!
Expression: calc("10-6") == 4 && "could not do substraction"

这是我的代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <ctype.h>

double calc(char * input);
double extract_first_integer(char * input);
double extract_last_integer(char * input);
char extract_operand(char * input);

int main()
{
   assert(calc("10-6") == 4 && "could not do substraction");

   return 0;
}

double calc(char * input){
   double num1 = extract_first_integer(input);
   double num2 = extract_last_integer(input);
   char operand = extract_operand(input);
   printf("operand is %c\n", operand);
   switch (operand)
   {
   case '-':
      printf("num1 - num2: %f\n", num1-num2);  // output: 16 instead of 4
      return num1 - num2;
      break;
   }
}

double extract_first_integer(char * input){
   char *str = input, *p = str;
   double val;
   while (*p) { // While there are more characters to process...
      if ( isdigit(*p) || ( (*p=='-'||*p=='+') && isdigit(*(p+1)) )) {
         // Found a number
         val = strtol(p, &p, 10); // Read number
         return val;
      } else {
         // Otherwise, move on to the next character.
         p++;
      }
   }
}

double extract_last_integer(char * input){
   char *str = input, *p = str;
   double val;
   while (*p) { // While there are more characters to process...
      if ( isdigit(*p) || ( (*p=='-'||*p=='+') && isdigit(*(p+1)) )) {
         // Found a number
         val = strtol(p, &p, 10); // Read number
      } else {
         // Otherwise, move on to the next character.
         p++;
      }
   }
   return val;
}

char extract_operand(char * input){
   if (strstr(input, "-")) return '-';
}

标签: cmath

解决方案


extract_last_integer()你有

while (*p) { // While there are more characters to process...
  if ( isdigit(*p) || ( (*p=='-'||*p=='+') && isdigit(*(p+1)) )) {
     // Found a number
     val = strtol(p, &p, 10); // Read number
  } else {
     // Otherwise, move on to the next character.
     p++;
  }
}

它增加p直到它遇到第一个数字或-/+后跟一个数字。所以它会匹配第一个10数字。但是请注意,您并没有像早期那样打破循环。当您继续匹配下一个数字时,将匹配in 。显然是 16return val;extract_first_integer()-6"10-6"10 - (-6)

您也可能有未定义的行为

  • 将相同的指针传递给strtol. 该变量str未使用,应改为在str_end参数中传递
  • const char*( "10-6") 传递给期望的函数char*

这 3 个extract...函数的性能也不好,因为它们都需要从输入字符串的开头进行迭代。要解决此问题,您应该返回当前数字的位置并从该位置启动下一个函数。这样,您可以使用相同的函数来解析整数,而不是编写两个

此外,你的名字倒了。这两个整数称为操作数,连接两个操作数的东西称为运算符,而不是操作数。double当你只读取整数时为什么要返回?

因此,在修复了这些点之后,我们将拥有

int extract_operand(char * input, size_t *lastChar);
char extract_operator(char * input, size_t *lastChar);

size_t lastPos;
int num1 = extract_operand(input, &lastPos);
char operand = extract_operator(input + lastPos, &lastPos);
int num2  = extract_operand(input + lastPos, &lastPos);

但这仅适用于具有二元运算符和这样的 2 个操作数的简单情况。对于更复杂的情况,您需要一个标记器将输入流拆分为标记列表


推荐阅读