diff options
author | zlg <zlg@zlg.space> | 2016-10-12 06:49:26 -0700 |
---|---|---|
committer | zlg <zlg@zlg.space> | 2016-10-12 06:49:26 -0700 |
commit | edf72affee48c3e6530d6f60142d834eecae8aa3 (patch) | |
tree | 9bb5cdb1ccf5bad45c9c3351bcd78efd3d049932 /ch7 | |
parent | Solve Exercise 7-4: minscanf() (diff) | |
download | knr-edf72affee48c3e6530d6f60142d834eecae8aa3.tar.gz knr-edf72affee48c3e6530d6f60142d834eecae8aa3.tar.bz2 knr-edf72affee48c3e6530d6f60142d834eecae8aa3.tar.xz knr-edf72affee48c3e6530d6f60142d834eecae8aa3.zip |
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.
Diffstat (limited to 'ch7')
-rw-r--r-- | ch7/7-05_postfix-calc-scanf.c | 114 |
1 files changed, 114 insertions, 0 deletions
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 <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <math.h> +#include <string.h> + +/* 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; + } +} |