aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ch7/7-05_postfix-calc-scanf.c114
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, &ltr) == 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;
+ }
+}
722de5512a4770d91d718194c01bc77844687&follow=1'>Bump to 0.3alpha5 for PyPIzlg1-1/+1 2018-09-29cli: Add pretty printing to 'list' commandzlg3-17/+107 2018-09-08setup.py: Bump to alpha4 for PyPIzlg1-1/+1 2018-09-08cli: add '--raw' option to list commandzlg2-9/+45 2018-09-08Add remaining filters to vgstash packagezlg1-2/+11 2018-09-04Update LICENSE to match setup.pyzlg1-80/+67 2018-09-03Branch off from master with pytest, tox, clickzlg16-778/+779 2018-03-18Flesh out filter types and ownership statuszlg3-82/+144 2018-03-18README.mdown: break line correctlyzlg1-1/+1 2018-03-18add 'playlog' list filterzlg2-2/+9 2018-03-13Update helpers a bitzlg1-2/+9 2018-03-13Make VGSTASH_DB_LOCATION point to a filezlg2-21/+20 2016-11-18Remove settings from helpers.shZe Libertine Gamer1-5/+0 2016-11-15Correct phrasing in README.Ze Libertine Gamer1-4/+4 2016-11-13DerpZe Libertine Gamer1-0/+1 2016-11-03Improve error handling in shell scriptsZe Libertine Gamer4-3/+23 2016-10-24Correct run_again, add recursionZe Libertine Gamer1-0/+4 2016-10-21Add quotes to correct behavior for arglistZe Libertine Gamer1-1/+1 2016-10-14updater.sh: add recursion, error handlingZe Libertine Gamer1-43/+101 2016-10-14Correct pipe-handling behaviorZe Libertine Gamer1-1/+9 2016-10-12Clarify a method to move between platformsZe Libertine Gamer1-2/+5