From edf72affee48c3e6530d6f60142d834eecae8aa3 Mon Sep 17 00:00:00 2001 From: zlg Date: Wed, 12 Oct 2016 06:49:26 -0700 Subject: Solve Exercise 7-5: RPN calculator with scanf() This exercise was deceptively simple, and ended up simpler than the original! The *scanf series of functions is very useful, but you also have to be careful or you'll run into segfaults. --- ch7/7-05_postfix-calc-scanf.c | 114 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 ch7/7-05_postfix-calc-scanf.c (limited to 'ch7/7-05_postfix-calc-scanf.c') diff --git a/ch7/7-05_postfix-calc-scanf.c b/ch7/7-05_postfix-calc-scanf.c new file mode 100644 index 0000000..161f5f0 --- /dev/null +++ b/ch7/7-05_postfix-calc-scanf.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include + +/* The C Programming Language: 2nd Edition + * + * Exercise 7-5: Rewrite the postfix calculator of Chapter 4 to use scanf + * and/or sscanf to do the input and number conversion. + * + * Notes: + * scanf wants allocated memory of some sort, meaning you're either going + * to pass it a pointer (with malloc()'d memory) or you're passing a variable + * with the unary & (address-of) operator. Failing to use scanf correctly + * _will_ create runtime problems! gcc won't tell you what happens without + * -Wall and -Wextra, but scanf segfaults by trying to access an uninitialized + * pointer. + * + * Thus there are two ways to use scanf: + * + * int foo = 0; + * scanf("%d", &foo); + * // do stuff + * + * -- or -- + * + * int *foo = malloc(sizeof(int)); + * scanf("%d", foo); + * // do stuff + * free(foo); + * + * For the sake of sanity in an easy exercise, I'll be using the former form + * since a few values on the stack won't hurt anything. + */ + +#define MAXOP 100 +#define MAXVAL 100 +#define BUFSIZE 100 + +void push(double); +double pop(void); + +int sp = 0; // Next free stack position +double val[MAXVAL]; // Value stack +char buf[BUFSIZE]; // buffer +int bufp = 0; // next free position in buf +double vars[27]; + +/* Reverse Polish calculator: + * + * Binary operations (+-*\) + * operand operand operator + * + * Example: 6 minus 2 in Reverse Polish Notation is "6 2 -" + */ +int main() { + char *c; + double a = 0, op2; + char s[MAXOP]; + char ltr = '\0'; + while (scanf("%s%c", s, <r) == 2) { + if (sscanf(s, "%lf", &a) == 1) { + push(a); + } else if (sscanf(s, "%s", buf)) { + for (c = buf; *c; c++) { + switch (*c) { + 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: Cannot divide by zero.\n"); + } + break; + default: + printf("Error: Unknown command %s\n", s); + break; + } + } + if (ltr == '\n') { + printf("%.8f\n", pop()); + } + } + } + return 0; +} + +void push(double f) { + if (sp < MAXVAL) { + val[sp++] = f; + } else { + printf("Error: Stack full. Cannot push %g\n", f); + } +} + +double pop(void) { + if (sp > 0) { + return val[--sp]; + } else { + printf("Error: Stack empty.\n"); + return 0.0; + } +} -- cgit v1.2.3-54-g00ecf