How can I put sin cos function into this RPN calculator - c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#define MAXVAL 100
#define MAXOP 100
#define NUMBER '0'
#define BUFSIZE 100
#define sinn 'sin'
int sp = 0;
double val[MAXVAL];
char buf[BUFSIZE];
int bufp = 0;
double aatof(char []);
void push(double);
double pop(void);
int ggetop(char []);
int ggetch(void);
void unggetch(int);
int main()
{
int type;
double op2;
int op3;
char s[MAXOP];
while ((type = ggetop(s)) != EOF)
{
switch (type)
{
case NUMBER:
push(aatof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-': // negative number
if (isdigit(ggetop(s))){
push(0-aatof(s));
break;}
case '--': // minus
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if (op2 != 0.0)
push(pop() / op2);
else
printf("error: zero divisor\n");
break;
case '%':
op3 = (int)pop();
if (op3 != 0)
push((int)pop() % op3);
else
printf("error: zero divisor\n");
break;
case 'sin':
push(sin(pop()));
break;
case '\n':
printf("\t%.8g\n", pop());
break;
default:
printf("error: unknown command %s\n", s);
break;
}
}
return 0;
}
int ggetop(char s[])
{
int i, c;
while ((s[0] = c = ggetch()) == ' ' || c == '\t')
;
s[1] = '\0';
if (!isdigit(c) && c != '.')
i = 0;
if (isdigit(c))
while (isdigit(s[++i] = c = ggetch()))
;
if (c == '.')
while (isdigit(s[++i] = c = ggetch()))
;
s[i] = '\0';
if (c != EOF)
unggetch(c);
return NUMBER;
}
int ggetch(void)
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void unggetch(int c)
{
if (bufp >= BUFSIZE)
printf("unggetch: too many characters\n");
else
buf[bufp++] = c;
}
double aatof(char s[])
{
double val, power;
int i, sign;
for (i = 0; isspace(s[i]); i++)
;
sign = (s[i] == '-') ? -1 : 1;
if (s[i] == '+' || s[i] == '-')
i++;
for (val = 0.0; isdigit(s[i]); i++)
val = 10.0 * val + (s[i] - '0');
if (s[i] == '.')
i++;
for (power = 1.0; isdigit(s[i]); i++)
{
val = 10.0 * val + (s[i] - '0');
power *= 10.0;
}
return sign * val / power;
}
void push(double f)
{
if (sp < MAXVAL)
val[sp++] = f;
else
printf("error: stack full, can't push %g\n", f);
}
double pop(void)
{
if (sp > 0)
return val[--sp];
else
{
printf("error: stack empty\n");
return 0.0;
}
}
I am not sure how can I put the sin cos pow function into different cases. I've tried to use isalpha() in ggetop(char s[]) and turn letters into integer but it doesn't seem to work. what I want to do is process the letter and give back the ASCII number, and add them into type. I wonder how to process the letters altogether at once and not individually.
if(isalpha(c)){
s[++i] = c = ggetch();
return c;}
are there other ways to add sin cos and pow functions into the programs?

Related

K&R Exercise 4-10: Segmentation fault while implementing getline

I tried to figure out why I always get a segmentation fault in my program which is part of an exercise, number 4-10, in The C Programming Language book of K&R.
I've implemented every function as it was teached by the book itself. I want to stick as much to it as possible.
Could anyone give me a hint? Would be very appreciated. Thanks!
/* An alternate organization uses getline to read an entire input line;
this makes getch and ungetch unnecessary. Revise the calculator to use
this approach. */
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h> // for atof()
#define MAXLINE 100 // max size of input
#define MAXOP 100 // max size of operand or operator
#define MAXVAL 100 // maximum depth of val stack
#define NUMBER '0' // signal that a number was found
int getop(char[]);
int getl(char[], int);
void push(double);
double pop(void);
int li = 0; // input line index
char line[MAXLINE]; // one input line
int sp = 0; // next free stack position
double val[MAXVAL]; // value stack
/* reverse Polish calculator */
int main(void) {
int type;
double op2;
char s[MAXOP];
while ((type = getop(s)) != EOF) {
switch (type) {
case NUMBER:
push(atof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if (op2 != 0.0)
push(pop() / op2);
else
printf("Error: Zero Divisor\n");
break;
case '\n':
printf("\t%.8g\n", pop());
break;
default:
printf("Error: Unknown Command %s\n", s);
break;
}
}
return 0;
}
/* getop: get next operator or numeric operand */
int getop(char s[]) {
int c, i;
if (line[li] == '\0') {
if (getl(line, MAXLINE) == 0)
return EOF;
else
li = 0;
}
while ((s[0] = c = line[li++]) == ' ' || c == '\t')
;
s[1] = '\0';
if (!isdigit(c) && c != '.') return c; // not a number
if (isdigit(c)) // collect integer part
while (isdigit(s[++i] = c = line[li++]))
;
if (c == '.')
while (isdigit(s[++i] = c = line[li++]))
;
s[i] = '\0';
li--;
return NUMBER;
}
/* getl: get line into s, return length */
int getl(char s[], int lim) {
int c, i;
i = 0;
while (--lim > 0 && (c = getchar()) != EOF && c != '\n')
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0';
return i;
}
/* push: push f onto value stack */
void push(double f) {
if (sp < MAXVAL)
val[sp++] = f;
else
printf("Error: Stack full, can't push %g\n", f);
}
/* pop: pop and return top value from stack */
double pop(void) {
if (sp > 0)
return val[--sp];
else {
printf("Error: Stack empty\n");
return 0.0;
}
}
Thanks to MikeCAT the program is now fully working. Here the source code:
/* An alternate organization uses getline to read an entire input line;
this makes getch and ungetch unnecessary. Revise the calculator to use
this approach. */
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h> // for atof()
#define MAXLINE 100 // max size of input
#define MAXOP 100 // max size of operand or operator
#define MAXVAL 100 // maximum depth of val stack
#define NUMBER '0' // signal that a number was found
int getop(char[]);
int getl(char[], int);
void push(double);
double pop(void);
int li = 0; // input line index
char line[MAXLINE]; // one input line
int sp = 0; // next free stack position
double val[MAXVAL]; // value stack
/* reverse Polish calculator */
int main(void) {
int type;
double op2;
char s[MAXOP];
while ((type = getop(s)) != EOF) {
switch (type) {
case NUMBER:
push(atof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if (op2 != 0.0)
push(pop() / op2);
else
printf("Error: Zero Divisor\n");
break;
case '\n':
printf("\t%.8g\n", pop());
break;
default:
printf("Error: Unknown Command %s\n", s);
break;
}
}
return 0;
}
/* getop: get next operator or numeric operand */
int getop(char s[]) {
int c, i;
if (line[li] == '\0') {
if (getl(line, MAXLINE) == 0)
return EOF;
else
li = 0;
}
while ((s[0] = c = line[li++]) == ' ' || c == '\t')
;
s[1] = '\0';
if (!isdigit(c) && c != '.') return c; // not a number
i = 0;
if (isdigit(c)) // collect integer part
while (isdigit(s[++i] = c = line[li++]))
;
if (c == '.')
while (isdigit(s[++i] = c = line[li++]))
;
s[i] = '\0';
li--;
return NUMBER;
}
/* getl: get line into s, return length */
int getl(char s[], int lim) {
int c, i;
i = 0;
while (--lim > 0 && (c = getchar()) != EOF && c != '\n')
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0';
return i;
}
/* push: push f onto value stack */
void push(double f) {
if (sp < MAXVAL)
val[sp++] = f;
else
printf("Error: Stack full, can't push %g\n", f);
}
/* pop: pop and return top value from stack */
double pop(void) {
if (sp > 0)
return val[--sp];
else {
printf("Error: Stack empty\n");
return 0.0;
}
}
You used an indeterminate value of uninitialized non-static local variable i at the line
while (isdigit(s[++i] = c = line[li++]))
of the function getop. You have to initialize i before using its value.
You should learn to use a debugger to determine at which line your program failed and the value of which variables is not expected.
For example, I used GDB in this way:
D:\Temp>gcc -Wall -Wextra -g3 -o a a.c
D:\Temp>gdb a
GNU gdb (GDB) 7.6.1
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "mingw32".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from D:\Temp\a.exe...done.
(gdb) r
Starting program: D:\Temp/a.exe
[New Thread 9144.0x6d24]
[New Thread 9144.0x2f1c]
22+22-/
Program received signal SIGSEGV, Segmentation fault.
0x004015fe in getop (s=0x61feac "2") at a.c:79
79 while (isdigit(s[++i] = c = line[li++]))
(gdb) p s
$1 = 0x61feac "2"
(gdb) p line
$2 = "22+22-/\n", '\000' <repeats 91 times>
(gdb) p i
$3 = 14027921
(gdb) p li
$4 = 2
(gdb)

Postfix Expression - Checking for Spaces

So I am trying to add an if statement in my main function to check if there is some whitespace. If so it would just go on to the next number/operator in line. So for example, if I would type 2 3 4 * +, I should get 14. However, when I run the code I would get a random number. When I do it with no spaces such as 234*+, then I would get 14. Could anyone tell me what I'm doing wrong and how I would fix this?
#include <ctype.h>
#include <stdio.h>
#define MAX 20
typedef struct stack {
int data[MAX];
int top;
} stack;
int evaluate(char x, int op1, int op2) {
if (x == '+')
return (op1 + op2);
if (x == '-')
return (op1 - op2);
if (x == '*')
return (op1 * op2);
if (x == '/')
return (op1 / op2);
if (x == '%')
return (op1 % op2);
}
void init(stack *s) {
s->top = -1;
}
void push(stack *s, int x) {
s->top = s->top + 1;
s->data[s->top] = x;
}
int pop(stack *s) {
int x;
x = s->data[s->top];
s->top = s->top - 1;
return (x);
}
int main() {
stack s;
char x;
int op1, op2, val;
init(&s);
printf("Enter a Postfix Expression: ");
while ((x = getchar()) != '\n') {
if (isdigit(x))
push(&s, x - 48); //x-48 for removing the effect of ASCII
if (isspace(x))
continue;
else {
op2 = pop(&s);
op1 = pop(&s);
val = evaluate(x, op1, op2);
push(&s, val);
}
}
val = pop(&s);
printf("\nValue of expression=%d",val);
return 0;
}
First of all, char x needs to be replaced with int x. The value returned by getchar won't always fit in a char. But that's not the problem you asked about.
If the character is a digit, you treat it as a digit and a operator. This
if(isdigit(x))
push(&s,x-48); //x-48 for removing the effect of ASCII
if (isspace(x))
continue;
else
{
op2=pop(&s);
op1=pop(&s);
val=evaluate(x,op1,op2);
push(&s,val);
}
should be
if (isdigit(x)) {
push(&s, x-48);
}
else if (isspace(x)) {
continue;
}
else {
int op2 = pop(&s);
int op1 = pop(&s);
int val = evaluate(x, op1, op2);
push(&s, val);
}
or just
if (isdigit(x)) {
push(&s, x-48);
}
else if (!isspace(x)) {
int op2 = pop(&s);
int op1 = pop(&s);
int val = evaluate(x, op1, op2);
push(&s, val);
}
You shouldn't count on a trailing line feed. So you should really have the following:
while ( ( x = getchar() ) != EOF ) {
if (isspace(x))
continue;
if (isdigit(x)) {
push(&s, x-48);
} else {
int op2 = pop(&s);
int op1 = pop(&s);
int val = evaluate(x, op1, op2);
push(&s, val);
}
}
Finally, you should handle someone entering 23++, 234+ or 23!.

How do I use free to deallocate heap allocations made using malloc?

I've encountered an issue with heap deallocation using free() in my tokenizer. The tokenizer is part of a recursive descent parsing calculator, which works flawlessly otherwise. But upon incorporation of a call to the deallocation function, it behaves erratically. While realistically, the calculator will likely never come close to exhausting its heap, writing a program with a memory leak is just poor practice.
tokenize.h
#define OPERAND 0
#define OPERATOR 1
#define PARENTHESIS 2
#define TERMINAL 3
#define ADD '+'
#define SUBTRACT '-'
#define MULTIPLY '*'
#define DIVIDE '/'
#define EXPONENT '^'
#define L_PARENTHESIS '('
#define R_PARENTHESIS ')'
typedef struct {
int id;
char *value;
} token;
int token_count();
token *tokenize();
void deallocate();
tokenize.c
#include <stdio.h>
#include <stdlib.h>
#include "tokenize.h"
int token_count(char string[]) {
int i = 0;
int count = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
while (1) {
i++;
if (string[i] >= '0' && string[i] <= '9') {
continue;
} else {
break;
}
}
count++;
continue;
}
switch (string[i]) {
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
count++;
i++;
continue;
default:
return 0;
break;
}
}
return count;
}
token *tokenize(char string[]) {
int i = 0;
token *ret;
int count = token_count(string);
if (!count) {
return ret;
}
ret = malloc((count + 1) * sizeof(token));
ret[count].id = TERMINAL;
int ret_ind = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
ret[ret_ind].id = OPERAND;
int size = 0;
int j = i;
while (1) {
size++;
j++;
if (string[j] >= '0' && string[j] <= '9') {
continue;
} else {
break;
}
}
ret[ret_ind].value = malloc(size * sizeof(char) + 1);
ret[ret_ind].value[size + 1] = '\0';
for(int k = 0; k < size; k++) {
ret[ret_ind].value[k] = string[i + k];
}
i = j;
ret_ind++;
continue;
}
switch (string[i]) {
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
ret[ret_ind].id = OPERATOR;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case L_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = L_PARENTHESIS;
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case R_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = R_PARENTHESIS;
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
default:
break;
}
break;
}
return ret;
}
void deallocate(token *in) {
int i = 0;
while (1) {
free(in[i].value);
i++;
if (in[i].id == TERMINAL) {
break;
}
}
free(in);
return;
}
There are multiple problems in your code:
in case the input line has no tokens or a syntax error, you return ret uninitialized from tokenize. You should return NULL instead.
ret[ret_ind].value[size + 1] = '\0'; stores the null terminator one step too far in the allocated array. It should be ret[ret_ind].value[size] = '\0';
malloc(size * sizeof(char) + 1) is inconsistent: if you insist on using sizeof(char), which is 1 by definition, you should write malloc((size + 1) * sizeof(char)), but it is idiomatic to use malloc(size + 1) in C and you could also replace multiple lines of code with a simple ret[ret_ind].value = strndup(string + i, k);
the cases for L_PARENTHESIS and R_PARENTHESIS could be merged into a single block.
the deallocation loop should stop when you reach the TERMINAL token. As currently coded, you cannot handle an empty list, which you should not produce, but it is better to make utility functions more resilient to later changes.
void deallocate(token *in) {
if (in) {
for (int i = 0; in[i] != TERMINAL; i++)
free(in[i].value);
free(in);
}
}
the prototypes in token.h should include the typed argument lists.
Here is a simplified version:
#include <stdio.h>
#include <stdlib.h>
#include "tokenize.h"
int token_count(const char *string) {
int count = 0;
int i = 0;
while (string[i] != '\0') {
switch (string[i++]) {
case ' ':
continue;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
i += strspn(string + i, "0123456789");
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
count++;
continue;
default:
return -1;
}
}
return count;
}
token *tokenize(const char *string) {
int count = token_count(string);
if (count <= 0)
return NULL;
token *ret = malloc((count + 1) * sizeof(token));
int i = 0;
int ret_ind = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
int size = strspn(string + i, "0123456789");
ret[ret_ind].id = OPERAND;
ret[ret_ind].value = strndup(string + i, size);
ret_ind++;
i += size;
continue;
}
switch (string[i]) {
case ' ':
i++;
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
ret[ret_ind].id = OPERATOR;
ret[ret_ind].value = malloc(2);
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case L_PARENTHESIS:
case R_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2);
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
default:
break;
}
break;
}
ret[ret_ind].id = TERMINAL;
return ret;
}
void deallocate(token *in) {
if (in) {
for (int i = 0; in[i] != TERMINAL; i++)
free(in[i].value);
free(in);
}
}
Here are additional remarks for the rest of the code:
why clear the screen on entry and exit?
you should test for end of file in the main loop:
if (!fgets(user_in, 1024, stdin))
break;
you should strip the newline efficiently:
#include <string.h>
user_in[strcspn(user_in, "\n")] = '\0';
then you can simplify the test for exit:
if (!strcmp(user_in, "exit"))
break;
no need to clear user_in after solve()
you could simplify testing by solving the command line arguments:
for (int i = 1; i < argc; i++)
solve(argv[i]);
you should ignore white space and accept empty lines
you should use "%.17g instead of %lf. Note that the l is mandatory
for scanf() for a double type, but ignored for printf, because
float arguments are converted to double when passed to vararg
functions like printf.
you should use a context structure and pass a pointer to it
to parse and its helper functions to avoid global variables
as you can see in try_add_sub and try_mul_div, it would simplify
the switch to unify token types and avoid the OPERATOR classification.
the parser is too complicated: you should use recursive descent more
directly: try_add_sub should first call try_mul_div and iterate on
additive operators, calling try_mul_div for each subsequent operand.
Similarly, try_mul_div should first call try_exp and try_exp would
call try_primitive which would handle parentheses and constants.
this approach consumes one token at a time, which can be read from
the expression source on the fly, bypassing the need for tokenizing the whole string.
you should accept the full number syntax for constants, which is easy with strtod().
Here is a simplified version along these directions:
//---- tokenize.h ----
#define TERMINAL 0
#define OPERAND 1
#define ERROR 2
#define ADD '+'
#define SUBTRACT '-'
#define MULTIPLY '*'
#define DIVIDE '/'
#define EXPONENT '^'
#define L_PARENTHESIS '('
#define R_PARENTHESIS ')'
#define SYNTAX_ERROR 1
#define PAREN_ERROR 2
typedef struct context {
char *p;
char *nextp;
int parenthesis_balance;
int error_code;
double value;
} context;
int this_token(context *cp);
void skip_token(context *cp);
//---- tokenize.c ----
#include <stdlib.h>
//#include "tokenize.h"
int this_token(context *cp) {
char *p = cp->p;
for (;;) {
switch (*p) {
case '\0':
cp->nextp = p;
return TERMINAL;
case ' ':
case '\t':
case '\n':
/* ignore white space */
p++;
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
/* single character operators */
cp->nextp = p + 1;
return *p;
default:
/* try and parse as a number constant */
cp->value = strtod(p, &cp->nextp);
if (cp->nextp > p)
return OPERAND;
return ERROR;
}
}
}
void skip_token(context *cp) {
cp->p = cp->nextp;
}
//---- parse.h ----
int parse(char expression[], double *result);
void solve(char expression[]);
//---- parse.c ----
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//#include "tokenize.h"
//#include "parse.h"
/* expression parsers return non zero upon error */
int try_add_sub(context *cp, double *result);
int try_mul_div(context *cp, double *result);
int try_exp(context *cp, double *result);
int try_primary(context *cp, double *result);
int try_add_sub(context *cp, double *result) {
if (try_mul_div(cp, result))
return 1;
for (;;) {
double operand;
switch (this_token(cp)) {
case ADD:
skip_token(cp);
if (try_mul_div(cp, &operand))
return 1;
*result += operand;
continue;
case SUBTRACT:
skip_token(cp);
if (try_mul_div(cp, &operand))
return 1;
*result -= operand;
continue;
}
return 0;
}
}
int try_mul_div(context *cp, double *result) {
if (try_exp(cp, result))
return 1;
for (;;) {
double operand;
switch (this_token(cp)) {
case MULTIPLY:
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result *= operand;
continue;
case DIVIDE:
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result /= operand;
continue;
}
return 0;
}
}
int try_exp(context *cp, double *result) {
if (try_primary(cp, result))
return 1;
if (this_token(cp) == EXPONENT) {
double operand;
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result = pow(*result, operand);
}
return 0;
}
int try_primary(context *cp, double *result) {
switch (this_token(cp)) {
case OPERAND:
skip_token(cp);
*result = cp->value;
return 0;
case L_PARENTHESIS:
skip_token(cp);
cp->parenthesis_balance++;
if (try_add_sub(cp, result))
return 1;
cp->parenthesis_balance--;
if (this_token(cp) != R_PARENTHESIS) {
cp->error_code = PAREN_ERROR;
return 1;
}
skip_token(cp);
return 0;
}
cp->error_code = SYNTAX_ERROR;
return 1;
}
/* parse and evaluate an expression, return error code, update result */
int parse(char expression[], double *result) {
context cc;
cc.nextp = cc.p = expression;
cc.parenthesis_balance = 0;
cc.error_code = 0;
cc.value = 0;
if (try_add_sub(&cc, result))
return cc.error_code;
if (this_token(&cc) != TERMINAL)
return SYNTAX_ERROR;
return 0;
}
void solve(char expression[]) {
double result = 0;
switch (parse(expression, &result)) {
case 0:
printf(" %.17g\n", result);
break;
case SYNTAX_ERROR:
printf("ERROR: Syntax\n");
break;
case PAREN_ERROR:
printf("ERROR: Unbalanced parenthesis\n");
break;
}
}
//---- calculator.c ----
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include "parse.h"
int main(int argc, char **argv) {
for (int i = 1; i < argc; i++)
solve(argv[i]);
if (argc == 1) {
char user_in[1024];
char *p;
printf("Terminal Calculator\n");
printf("Type 'exit' to terminate\n\n");
for (;;) {
printf("=> ");
if (!fgets(user_in, sizeof user_in, stdin)) {
printf("\n");
break;
}
/* strip trailing newline */
user_in[strcspn(user_in, "\n")] = '\0';
/* skip initial white space */
p = user_in + strspn(user_in, " \t");
/* ignore empty and comment lines */
if (*p == '\0' || *p == '#')
continue;
/* trap exit command */
if (!strcmp(p, "exit"))
break;
solve(p);
}
}
return 0;
}

Puzzle on the second stack in postfix calculator

I'm reading "TCPL" recently.There exist a classic case "postfix calculator" in section 4.3. I have a question on the case:
See the case code(copy from the book):
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define MAXOP 100
#define NUMBER '0'
#define MAXVAL 100 /* maxmium depth of val stack */
#define BUFFSIZE 100
int sp = 0;
double val[MAXVAL];
int bufp = 0; /* next free size in buf*/
char buf[BUFFSIZE]; /* buffer in ungetch */
int getch(void);
void ungetch(int);
int getop(char []);
void push(double);
double pop(void);
int main()
{
int type;
double op2;
char s[MAXOP];
while ((type = getop(s)) != EOF) {
switch (type) {
case NUMBER:
push(atof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if (op2 != 0.0) {
push(pop() / op2);
}
else
{
printf("error: zero divisor. \n");
}
break;
default:
printf("\t%.8g\n", pop());
break;
}
}
return 0;
}
/* push: push value f onto value stack */
void push(double f)
{
if (sp < MAXVAL) {
val[sp++] = f;
}
else {
printf("error: stack full, can't push.\n");
}
}
/* pop: pop and return value on the top of the stack */
double pop(void)
{
if (sp > 0) {
return val[--sp];
}
else {
printf("error: stack empty.\n");
return 0.0;
}
}
/* getop: get next character or numeric operand */
int getop(char s[])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t') {
;
}
s[1] = '\0';
if (!isdigit(c) && c != '.' ) { /* operator */
return c;
}
i = 0;
if (isdigit(c)) { /* collect integer part */
while (isdigit(s[++i] = c = getch())) {
;
}
}
if (c == '.') { /* collect fraction part */
while (isdigit(s[++i] = c = getch())) {
;
}
}
s[i] = '\0';
if (c != EOF) {
ungetch(c);
}
return NUMBER;
}
/* getch: get a (possibly pushed-back) character */
int getch(void)
{
return (bufp > 0)? buf[--bufp] : getchar();
}
/* ungetch: push character back on input */
void ungetch(int c)
{
if (bufp >= BUFFSIZE) {
printf("ungetch: too many characters in buufer.\n");
}
else {
buf[bufp++] = c;
}
}
There is a global char array buf, It is like a stack and the last two function are to 'pop' and 'push' on buf.
My question is in which case does the stack buf contains more than one element?
The only chance can the ungetch() be called is in function getop(), however in getop() the function getch() is called at least once.
My question is in which case does the stack buf contains more than one element?
never, buf can be just a char, it is only used to memorize the char placed just after a number to not lost it
The code can be modified to not use it :
/* getch: get a (possibly pushed-back) character */
int getch(void)
{
return getchar();
}
/* ungetch: push character back on input */
void ungetch(int c)
{
ungetc(c, stdin);
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc pf.c
pi#raspberrypi:/tmp $ ./a.out
1 2 3 4 + + +
10
Or using the fact only one char can be saved :
int SavedChar = EOF;
/* getch: get a (possibly pushed-back) character */
int getch(void)
{
if (SavedChar == EOF)
return getchar();
int r = SavedChar;
SavedChar = EOF;
return r;
}
/* ungetch: push character back on input */
void ungetch(int c)
{
SavedChar = c;
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc pf.c
pi#raspberrypi:/tmp $ ./a.out
1 2 3 4 + + +
10

Seriously What's wrong in my code

I am trying to solve one problem from spoj http://www.spoj.com/problems/ARITH2/
But every time i am getting 'WA' Wrong Answer.I've tried every possible Test Case and it's giving me expected results.I've written the code mentioned below:
#include <stdio.h>
int main() {
int t,s=0;char operator;
scanf("%d",&t);
while(t--)
{
signed long long int s=0,c=0;
scanf("%lld",&s);
while(1)
{
operator=0;
operator=getc(stdin);
if(operator=='=')
break;
scanf("%lld",&c);
switch(operator)
{
case '+' : s=s+c;
break;
case '-' : s=s-c;
break;
case '*' : s=s*c;
break;
case '/' : s=s/c;
break;
}
}
printf("%lld\n",s);
}
return 0;
}
Please check the requirement, you should not use scanf instead, using sscanf cos the input is whole expression such 50 * 40 * 250 + 791 =. You can create a simple parser as below code to walkthrough whole expression.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char ch = 0;
int state = 0;
char buff[128];
char ops = 0;
unsigned int result = 0;
int i = 0, idx = 0;
char expr[1024];
int cnt = 0;
if (scanf("%[^=]=%n", expr, &cnt) <= 0)
return 0;
while(idx < cnt) {
ch = expr[idx++];
printf("state %d ch %c\n", state, ch);
switch(state) {
case 0:
if ((ch <= '9') && (ch >= '0')) {
state++;
buff[i++] = ch;
}
break;
case 1:
if ((ch <= '9') && (ch >= '0')) {
buff[i++] = ch;
} else {
buff[i] = '\0';
if (i > 0) {
unsigned int num = atoi(buff);
switch (ops) {
case '-':
result -= num;
break;
case '+':
result += num;
break;
case '*':
result *= num;
break;
case '/':
result /= num;
break;
default:
result = num;
break;
}
printf("> found fact %d, result %u\n", num, result);
}
i = 0;
if ((ch == '-') || (ch == '+') || (ch == '*') || (ch == '/')) {
state = 0;
ops = ch;
printf("> found ops %c\n", ch);
} else if ((ch == ' ') || (ch == '\t')) {
continue;
} else if (ch == '=') {
break;
} else {
// expression end
break;
}
}
break;
default:
break;
}
}
printf("> result '%u' ", result);
return 0;
}
Quick glance, it doesn't look like you are respecting the spacing outlined in the spec. For example, 1 + 1 * 2 = is going to read the wrong character for operator. 1+1*2= looks like it'll work, but that's not what was asked for.
Also, you're reading in unsigned integers and will instantly fail any test cases with signed numbers.

Resources