简体   繁体   English

C中的计算器使用堆栈

[英]Calculator in C using stack

I'm trying to create a calculator in c, which can calculate with priority and get right results for examples like these: 我正在尝试在c中创建一个计算器,它可以优先计算并获得如下示例的正确结果:

((5+5)/3)*3) -- > 9

((1+2) * 3) -- > 9

These examples my code below can calculate. 这些例子我的代码可以计算出来。 But for something like this 但对于这样的事情

(2+5) * (2+5) , my program gives wrong answer. (2+5) * (2+5) ,我的程序给出了错误的答案。

I'm using 2 stacks. 我正在使用2个堆栈。 One for operators and one for numbers. 一个用于操作员,一个用于数字。 It works on this principle: 它的工作原理如下:
follows: 如下:

((4 - 2) * 5) + 3 --> normal infix expression: ((4 - 2) * 5) + 3 - > 正常中缀表达式:
+ * - 4 2 5 3

Pseudo code: 伪代码:

Read + (an operation), push it onto the stack,  
Read * (an operation), push it onto the stack,  
Read - (an operation), push it onto the stack,  
Read 4 (a number), the top of the stack is not a number, so push it onto the     stack.  
Read 2 (a number), the top of the stack is a number, so pop from the stack     twice, you get 4 - 2, calculate it (2), and push the result (2) onto the stack.      
Read 5 (a number), the top of the stack is a number, so pop from the stack twice, you get 2 * 5, push the result (10) onto the stack.  
Read 3 (a number), the top of the stack is a number, so pop from the stack twice, you get 3 + 10, push the result (13) onto the stack.  
Nothing left to read, pop from the stack and return the result (13).  

Actual code: 实际代码:

#include <stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 102

typedef struct
{
    char stk[MAXSIZE];
    int top;
}STACK;

typedef struct stack
{
    int stk[MAXSIZE];
    int itop;
}INT_STACK;

STACK s;
INT_STACK a;
void push(char);
char  pop(void);
void display(void);

int main()
{
  a.itop = 0;
  char string[MAXSIZE],vyb,vyb2;
  int cislo1,cislo2,vysledok;

  while (gets(string) != NULL){
    for(int j = strlen(string); j > 0; j--){
      if(string[j] == '*' || string[j] == '/' || string[j] == '+' || string[j] == '-')
        push(string[j]);
    }

    //display();
    for(int j = 0; j < strlen(string); j++){
      if(isdigit(string[j])&&!(a.itop)){
        //display();
        char pomoc[2];
        pomoc[0] = string[j];
        pomoc[1] = '\0';
        int_push(atoi(pomoc));
      }
      else if(isdigit(string[j])&&(a.itop)){
         cislo1 = int_pop();
         vyb2 = pop();
         char pomoc[2];
         pomoc[0] = string[j];
         pomoc[1] = '\0';
         cislo2 =  atoi(pomoc);
         if(vyb2 == '+')
            vysledok = cislo1+cislo2;
         else if(vyb2 == '-')
            vysledok = cislo1-cislo2;
         else if(vyb2 == '*')
            vysledok = cislo1*cislo2;
         else if(vyb2 == '/')
            vysledok = cislo1 / cislo2;
         //printf("  v   %d",vysledok);
         int_push(vysledok);
      }
    }
    printf("%d\n",int_pop());
  }
}

/*  Function to add an element to the stack */
void push (char c)
{
    s.top++;
    s.stk[s.top] = c;
    //printf ("pushed element is = %c \n", s.stk[s.top]);
}

/*  Function to delete an element from the stack */
char pop ()
{
    char num = s.stk[s.top];
   // printf ("poped element is = %c\n", s.stk[s.top]);
    s.top--;
    return(num);
}

int empty()
{
    if (s.top == - 1)
    {
        printf ("Stack is Empty\n");
        return (s.top);
    }
    return 1;
}

void display ()
{
    int i;
    if (!empty)
    {
        printf ("Stack is empty\n");
        return;
    }
    else
    {
        printf ("\n The status of the stack is \n");
        for (i = s.top; i >= 0; i--)
        {
            printf ("%c\n", s.stk[i]);
        }
    }
    printf ("\n");
}

void int_push (int c)
{
    a.itop++;
    a.stk[a.itop] = c;
    //printf ("pushed element is = %d \n", a.stk[a.itop]);
}

/*  Function to delete an element from the stack */
int int_pop ()
{
    int num = a.stk[a.itop];
   // printf ("poped element is = %d\n", a.stk[a.itop]);
    a.itop--;
    return(num);
}

Is there any other way to create a calculator with priority, which can give good answers? 有没有其他方法来创建一个优先级的计算器,这可以给出好的答案?
Thanks for your respond 谢谢你的回复

Put breakpoints - you'll get the following expression: + + * 2 5 2 5 . 放置断点 - 您将得到以下表达式: + + * 2 5 2 5 The problem with that, is your interpreter is interpeting this as (2+5+2)*5 instead of (2+5) * (2+5) . 问题是,你的翻译是将(2+5+2)*5代替(2+5) * (2+5)

Well then, you might be wondering how to solve this. 那么,你可能想知道如何解决这个问题。 There's no simple single solution - you could either fix your own interpreter or build a whole new mechanic, because the way you build expressions just can't handle more then one pair of parthesises. 没有简单的单一解决方案 - 您可以修复自己的解释器或构建一个全新的机制,因为构建表达式的方式不能处理超过一对的parthesises。

For example, you may want to calculate all the values in parnthesises before even building the expression seperatley, possibly using recursion in the case of parenthesiseception - however if you actually choose to use that method, you might want to change the way you work with the expressions entirely, because that's a different approach. 例如,您可能希望在构建表达式seperatley之前计算parnthesises中的所有值,可能在使用括号的情况下使用递归 - 但是如果您实际选择使用该方法,则可能需要更改使用该方法的方式表达完全,因为这是一种不同的方法。

If you need me to show actual code examples to explain this further using parts of the code you made, just ask for it and i'll edit and provide what you need. 如果您需要我展示实际的代码示例,使用您所制作的代码的一部分进一步解释这一点,只需要求它,我将编辑并提供您所需的内容。

Either way, I really advise you to look up working with interpreters in general - you could really learn a lot about analysing strings and working with different inputs, and people even did similar stuff to yours with calculators before 无论哪种方式,我真的劝你查找与一般的口译工作-你真的可以学到很多有关分析字符串,并与不同的输入工作,人们甚至没有类似的东西你用计算器之前

EDIT : you asked for examples, so here you go - this is an example of a completely different method using recursion. 编辑 :你问了一些例子,所以在这里 - 这是一个使用递归的完全不同的方法的例子。 This way, you handle a single pair of parenthesises at a time, and thus you won't have the problem you currently do. 这样,您一次只能处理一对括号,因此您不会遇到当前的问题。 Note - the source i'm basing this on ( pretty much copy-pasted with edits from the thread and some personal comments ) is from codereview on stack exchange, you can see it here if you're intrested. 注意 - 我基于此的源代码(几乎通过线程编辑和一些个人注释进行了复制粘贴)来自堆栈交换中的codereview,如果您感兴趣,可以在此处查看。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void getInput(char * in) {
 printf("> ");
 fgets(in, 256, stdin);
}

int isLeftParantheses(char p) {
if (p == '(') return 1;
else return 0;
}

int isRightParantheses(char p) {
if (p == ')') return 1;
else return 0;
}

int isOperator(char p) {
if (p == '+' || p == '-' || p == '*' || p == '/') return p;
else return 0;
}

int performOperator(int a, int b, char p) {
 switch(p) {
    case '+': return a+b;
    case '-': return a-b;
    case '*': return a*b;
    case '/':
        if (b == 0) { printf("Can't divide by 0, aborting...\n"); exit(1); }  // now we dont want the world to expload here do we.
        return a/b;
    default:
       puts("Bad value in switch.\n"); // A replacement which was mentioned in the thread- better have a default response just in case something goes wrong.
       break;
 }
return 0;
 }


char isDigit(char p) {
if (p >= '0' && p <= '9') return 1;
else return 0;
}

int charToDigit(char p) {
if (p >= '0' && p <= '9') return p - '0';
else return 0;
}

int isNumber(char * p) {
while(*p) {
    if (!isDigit(*p)) return 0;
    p++;
}
return 1;
}

int len(char * p)
{
 return (int) strlen(p); // This was bugged in the source, so I fixed it like the thread advised.
}

int numOfOperands(char * p) {
int total = 0;
while(*p) {
    if (isOperator(*p)) total++;
    p++;
}
return total+1;
}

int isMDGRoup(char *p)
{

for(; *p; p++) // used to be a while loop in the source, but this is better imho. more readable, also mentioned on the thread itself.
{
    if (!isDigit(*p) && *p != '/' && *p != '*') return 0;
}
return 1;
}
int getLeftOperand(char * p, char * l) {
// Grab the left operand in p, put it in l,
//and return the index where it ends.
int i = 0;

// Operand is part of multi-*/ group
if (isMDGRoup(p)) {
    while(1) {
        if (*p == '*' || *p == '/') break;
        l[i++] = *p++;
    }
    return i;
}

// Operand is in parantheses (so that's how you write it! sorry for my bad english :)
if(isLeftParantheses(*p)) {
    int LeftParantheses = 1;
    int RightParantheses= 0;
    p++;
    while(1) {
        if (isLeftParantheses(*p))  LeftParantheses++;
        if (isRightParantheses(*p)) RightParantheses++;

        if (isRightParantheses(*p) && LeftParantheses == RightParantheses)
            break;
        l[i++] = *p++;
    }
    // while (!isRightParantheses(*p)) {
    //  l[i++] = *p++;
    // }
    l[i] = '\0';
    return i+2;
}

// Operand is a number
while (1) {
    if (!isDigit(*p)) break;
    l[i++] = *p++;
}
l[i] = '\0';
return i;
}

int getOperator(char * p, int index, char * op) {
*op = p[index];
return index + 1;
}

int getRightOperand(char * p, char * l) {
// Grab the left operand in p, put it in l,
//and return the index where it ends.
while(*p && (isDigit(*p) || isOperator(*p) ||
             isLeftParantheses(*p) || isRightParantheses(*p))) {
    *l++ = *p++;
}
*l = '\0';

return 0;
}

int isEmpty(char * p) {
// Check if string/char is empty
if (len(p) == 0) return 1;
else return 0;
}

int calcExpression(char * p) {
// if p = #: return atoi(p)
//
// else:
//  L = P.LeftSide
//  O = P.Op
//  R = P.RightSide
//  return PerformOp(calcExpression(L), calcExpression(R), O)

// ACTUAL FUNCTION

// if p is a number, return it
if (isNumber(p)) return atoi(p);

// Get Left, Right and Op from p.
char leftOperand[256] = ""; char rightOperand[256]= "";
char op;

int leftOpIndex   = getLeftOperand(p, leftOperand);
int operatorIndex = getOperator(p, leftOpIndex, &op);
int rightOpIndex  = getRightOperand(p+operatorIndex, rightOperand);

printf("%s, %c, %s", leftOperand, op, rightOperand);
getchar();

if (isEmpty(rightOperand)) return calcExpression(leftOperand);

return performOperator(
    calcExpression(leftOperand),
    calcExpression(rightOperand),
    op
);
}

int main()
{
char in[256];
while(1) {
    // Read input from user
    getInput(in);
    if (strncmp(in, "quit", 4) == 0) break;

    // Perform calculations
    int result = calcExpression(in);
    printf("%d\n", result);
}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM