Where to place printf to avoid multiple printouts in my rpn calculator?

85 views Asked by At

My rpn-calculator works, but it has a problem. The problem is that it prints out every consecutive calculation that it makes along the way.

I have tried different ways of fixing this, the latest one being adding an integer that goes up by every calculation and a printf that prints if this integer is above 0 as well as there only being one number on the stack.

However, this causes problems when there is more than one calculation going on (for example writing 5 5 + 10 5 * *) will cause 10 500 being printed out because there is only one item on the stack after the first calculation.

How can I solve this?

#define MAX_STACK_SIZE 100
#define MAX_BUFFER_SIZE 100

char buff[MAX_BUFFER_SIZE];
     double x, stack[MAX_STACK_SIZE];
     double t;
     int i, k=0, num_operand=0;


int main(void) {

while(x != 'q') {
    if( scanf("%s", buff) < 1 )
             { return 0;
}
if(isdigit(buff[0]) || isdigit(buff[1])) {
    sscanf(buff, "%lf", &x);

if (num_operand < MAX_STACK_SIZE)
                     {
                             stack[num_operand]=x;
                             num_operand ++;
                     } else { printf("Make stack bigger\n");}

} else {
switch(buff[0]) {
    case '+': stack[num_operand - 2] = stack[num_operand - 1] + stack[num_operand - 2];
                                                num_operand --;
                                                num_operand --;
                                                t = stack[num_operand];
                                                k++;
                                                num_operand ++;
                                                break;
    case '-': stack[num_operand - 2] = stack[num_operand - 2] - stack[num_operand - 1];
                                                num_operand --;
                                                num_operand --;
                                                t = stack[num_operand];
                                                k++;
                                                num_operand ++;
                                                break;
    case '/': stack[num_operand - 2] = stack[num_operand - 2] / stack[num_operand - 1];
                                                num_operand --;
                                                num_operand --;
                                                t = stack[num_operand];
                                                k++;
                                                num_operand ++;
                                                break;
    case '*': stack[num_operand - 2] = stack[num_operand - 1] * stack[num_operand - 2];
                                                num_operand --;
                                                num_operand --;
                                                t = stack[num_operand];
                                                k++;
                                                num_operand ++;
                                                break;
    } }
    if (num_operand == 1 && k !=0) {
        k = 0;
        printf("%lf \n", t); }
}
}
2

There are 2 answers

1
chux - Reinstate Monica On

"%s" consumes leading white-spaces like ' ' and '\n' alike - so the distinction between end of line and the space separator is lost.

To distinguish between lines of input use fgets() and process the line. Then print the result. @molbdnilo

It test for q, code needs to test the textual contents of the line, not double x. @BLUEPIXY

int main(void) {
  char line[MAX_BUFFER_SIZE];

  // read line
  while (fgets(line, sizeof line, stdin) && line[0] != 'q') {
    // Set up these variables per each line.
    double x, stack[MAX_STACK_SIZE];
    double t;
    int i, k = 0, num_operand = 0;

    const char *p = line;
    char buff[MAX_BUFFER_SIZE];
    int n;  // # of characters scanned

    // process tokens
    while (sscanf(p, "%s %n", buff, &n) == 1) {
      ...

      // next token
      p += n;
    } // endwhile

    // print
    if (num_operand == 1 && k != 0) {
      k = 0;
      printf("%lf \n", t);
      fflush(stdout);
    }
  } // endwhile
0
BLUEPIXY On

Instead of displaying by the number of stacked on the stack, make sure to display the stack top explicitly with the command.


Specific example.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include <ctype.h>

#define MAX_STACK_SIZE  100
#define MAX_BUFFER_SIZE 100

char   buff[MAX_BUFFER_SIZE];
char   *curr_buff = buff;
double stack[MAX_STACK_SIZE];
int sp = -1;

#define prompt " ok>"

char *getToken(void);
bool IsNumber(const char *token, double *value);
char *strlwr(char *s);
int cmp_charpp(const void *, const void *);
void push(double value);
double pop(void);
void add(void);
void sub(void);
void mul(void);
void Div(void);
void dot(void);
void Exit(void);
void quit(void);
void bye(void);
void cr(void);

struct command {
    const char *name;
    void (*func)(void);
} op_table[] = {
    {"*"   ,  mul},
    {"+"   ,  add},
    {"-"   ,  sub},
    {"."   ,  dot},
    {"/"   ,  Div},
    {"="   ,  dot},
    {"add" ,  add},
    {"bye" ,  bye},
    {"cr" ,    cr},
    {"div" ,  Div},
    {"exit", Exit},
    {"mul" ,  mul},
    {"quit", quit},
    {"sub" ,  sub},
};

int main(void) {
    while(true){
        char *token;

        fputs(prompt, stdout);fflush(stdout);
        while(token = getToken()){
            double value = 0;
            if(IsNumber(token, &value)){
                push(value);
            } else if(*token){
                strlwr(token);
                struct command *op = 
                    bsearch(&token, op_table,
                        sizeof(op_table)/sizeof(*op_table), sizeof(*op_table),
                        cmp_charpp);
                if(op){
                    op->func();
                } else {
                    fprintf(stderr, "\ncommand '%s' not found!!\n", token);
                    curr_buff = buff;
                    *buff = 0;
                    break;
                }
            }
        }
    }
}

char *getToken(void){
    static char token[MAX_BUFFER_SIZE] = "";

    if(curr_buff){
        if(*curr_buff || curr_buff == buff && (curr_buff = fgets(buff, sizeof buff, stdin))){
            int n = 0;
            if(sscanf(curr_buff, "%s %n", token, &n) == 1){
                curr_buff += n;
                return token;
            }
        }
        *(curr_buff = buff) = 0;
    }
    return NULL;
}

bool IsNumber(const char *token, double *value){
    char ch = 0;

    *value = FP_NAN;

    return sscanf(token, "%lf%c", value, &ch)==1;
}

void push(double value){
    if(sp+1 == MAX_STACK_SIZE){
        fprintf(stderr, "\nstack overflow!!\n");
        return;
    }
    stack[++sp] = value;
}

bool IsEmpty(void){
    return sp == -1;
}

double pop(void){
    if(IsEmpty()){
        fprintf(stderr, "\nstack is empty!!\n");
        return nan(NULL);//FP_NAN;
    }
    return stack[sp--];
}

bool pop2(double *top, double *second){
    return !isnan(*top = pop()) && !isnan(*second = pop());
}
void add(void){
    double top, second;
    if(pop2(&top, &second))
        push(second+top);
}
void sub(void){
    double top, second;
    if(pop2(&top, &second))
        push(second-top);
}
void mul(void){
    double top, second;
    if(pop2(&top, &second))
        push(second*top);
}
void Div(void){
    double top, second;
    if(pop2(&top, &second))
        push(second/top);
}
void dot(void){
    double top = pop();
    if(!isnan(top)){
        printf("%g", top);fflush(stdout);
    }
}
void cr(void){
    putchar('\n');
}
void Exit(void){
    double top = pop();
    if(isnan(top))
        exit(EXIT_FAILURE);
    else
        exit((int)top);
}
void quit(void){
    char yn[4];
    if(!IsEmpty()){
        printf("The stack is not empty but will it end?\n");
        scanf(" %3[NYny]", yn);
        if(*yn == 'y' || *yn == 'Y')
            exit(EXIT_SUCCESS);
        else
            while(getchar()!='\n');
    }else {
        exit(EXIT_SUCCESS);
    }
}
void bye(void){
    exit(EXIT_SUCCESS);
}
char *strlwr(char *s){
    for(char *p = s; *p; ++p)
        *p = tolower(*p);
    return s;
}
int cmp_charpp(const void *a, const void *b){
    return strcmp(*(const char **)a, *(const char **)b);
}

Example of execution.

 ok>5 5 + 10 5 * * = CR
500
 ok>bye