K&R possible bug in polish calculator - c

I'm not sure where to post this but I think I found a pretty major bug in K&R's polish calculator program. Basically, when you perform an operation, two values get popped while only the result gets pushed. The problem is that the result isn't getting pushed to the top of the stack! Here's an illustration:
The full code for the polish calculator provided by the textbook is shown below:
#include <stdio.h>
#include <stdlib.h> /* for atof() */
#define MAXOP 100 /* max size of operand or operator */
#define NUMBER '0' /* signal that a number was found */
int getop(char []);
void push(double);
double pop(void);
/* reverse Polish calculator */
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;
case '\n':
printf("\t%.8g\n", pop());
break;
default:
printf("error: unknown command %s\n", s);
break;
}
}
system("Pause");
return 0;
}
#define MAXVAL 100 /* maximum depth of val stack */
int sp = 0; /* next free stack position */
double val[MAXVAL]; /* value stack */
/* 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;
}
}
#include <ctype.h>
int getch(void);
void ungetch(int);
/* getop: get next operator or numeric operand */
int getop(char s[])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || 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 = getch()))
;
if (c == '.') /*collect fraction part*/
while (isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}
#define BUFSIZE 100
char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */
int getch(void) /* get a (possibly pushed back) character */
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c) /* push character back on input */
{
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
If you want to check for yourself, all I did was add
static int pass = 0;
int i, check;
i = check = 0;
inside the while loop in main() and
if(!check) {
printf("pass #%d\n",pass++);
while(val[i] != '\0') {
printf("val[%d]: %.2f\n",i,val[i]);
++i;
}
}
at the end of the while loop, just after the switch statement. I also put check = 1; in the case for '\n'.
As a possible workaround I re-wrote the pop function such that popped values are removed from the val array as soon as they are accessed. So instead of
double pop(void)
{
if (sp > 0)
return val[--sp];
else {
printf("error: stack empty\n");
return 0.0;
}
}
you'd have something like
double pop(void)
{
if (sp > 0) {
double temp = val[--sp];
val[sp] = '\0';
return temp;
}
else {
printf("error: stack empty\n");
return 0.0;
}
}
I also re-wrote the push function to ensure that values are always pushed to the end of the val array. So instead of
void push(double f)
{
if ( sp < MAXVAL)
val[sp++] = f;
else
printf("error: stack full. can't push %g\n", f);
}
you'd have
void push(double f)
{
if ( sp < MAXVAL) {
while (val[sp] != '\0')
++sp;
val[sp++] = f;
}
else
printf("error: stack full. can't push %g\n", f);
}
Even with these changes, I still had to re-write
case '\n':
printf("\t%.8g\n", pop());
break;
to retrieve the value at the top of the stack without popping it, which required replacing the printf statement with a simple function like
void print_top(void)
{
int i = 0;
while( val[i] != '\0' )
++i;
--i;
printf("\t%.8g\n",val[i]);
}
Only then does the polish calculator seem to function as intended, at least in terms of what the stack is doing behind the scenes. You can try it out for yourself with the modified code:
#include <stdio.h>
#include <stdlib.h> /* for atof() */
#include <ctype.h>
#define MAXOP 100 /* max size of operand or operator */
#define NUMBER '0' /* signal that a number was found */
#define MAXVAL 100 /* maximum depth of val stack */
int getop(char []);
void push(double);
double pop(void);
void print_top(void);
int sp = 0; /* next free stack position */
double val[MAXVAL]; /* value stack */
/* reverse Polish calculator */
main()
{
int type;
double op2;
char s[MAXOP];
while ((type= getop(s)) != EOF) {
static int pass = 0;
int i, check;
i = check = 0;
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':
print_top();
check = 1;
break;
default:
printf("error: unknown command %s\n", s);
break;
}
if(!check) {
printf("pass #%d\n",pass++);
while(val[i] != '\0') {
printf("val[%d]: %.2f\n",i,val[i]);
++i;
}
}
}
system("Pause");
return 0;
}
/* push: push f onto value stack */
void push(double f)
{
if ( sp < MAXVAL) {
while (val[sp] != '\0')
++sp;
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) {
double temp = val[--sp];
val[sp] = '\0';
return temp;
}
else {
printf("error: stack empty\n");
return 0.0;
}
}
int getch(void);
void ungetch(int);
/* getop: get next operator or numeric operand */
int getop(char s[])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || 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 = getch()))
;
if (c == '.') /*collect fraction part*/
while (isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}
#define BUFSIZE 100
char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */
int getch(void) /* get a (possibly pushed back) character */
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c) /* push character back on input */
{
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
void print_top(void)
{
int i = 0;
while( val[i] != '\0' )
++i;
--i;
printf("\t%.8g\n",val[i]);
}
Note that I had to move most of my #define statements and prototype declarations to the beginning in order to accommodate for the debugging printfstatement at the end of main().
*Edited out some of my audacious claims :P

You're thinking of the stack backwards - the top of the stack is in the highest valid index, not in val[0]. This behaviour is evident when you look at the pushes of the operands. Your output:
3 4 +
pass #0
val[0]: 3.00
pass #1
val[0]: 3.00
val[1]: 4.00
First, the 3 is pushed - going onto the top of the (previously empty) stack - it's in slot 0. Next 4 is pushed. As you can see, it goes into val[1], clearly showing that val[0] is not the top of the stack in this case.
You're printing the stack incorrectly, which is confusing you further. Change your print loop to:
while (i < sp) {
printf("val[%d]: %.2f\n",i,val[i]);
++i;
}
That is, print only the valid entries in the stack, and you'll see your error.
Your current comparison is looking for a 0 entry on the stack, which isn't how the program is identifying the free entries. That's what the sp variable is used for. In addition to looking for the wrong thing, it's doing it in a bizarro way - val is a an array of floating-point numbers - why are you comparing to a character literal \0?
Here's the complete corrected output:
3 4 +
pass #0
val[0]: 3.00
pass #1
val[0]: 3.00
val[1]: 4.00
pass #2
val[0]: 7.00
7
Now, you see the correct output - both the 3.00 and 4.00 are popped, and 7.00 is pushed back onto the stack. It's now the only valid entry.

Nah. It's just that the stack grows upwards, i. e. val[0] is the bottom (and the top too if there's only one element). And at the time you print the result, val[1] is invalid, it has already been popped.

There is no bug in the code given in K&R for reverse polish calculator.
It works only when the input is given in a single line.
If you press the enter then compiler will read '\n',which results in (case '\n':) of the code and the pop function will be called.
Code result is in the given image:

Related

Expression Tree - Operations with Characters

The user enters a string with an operation such as 4*5+2/3 and the code is supposed to make an expression tree out of it and the calculate said expression tree. I am having a problem where the program is making the expression tree with the decimal values of the ascii table instead of the actual numbers.
For example instead of 4*5+2/3, the program is storing and using 52 42 53 43 50 47 51 for the calculations. My desired run screen would be:
1 //this is the number of strings
4*5+2/3 //this is the string itself
20 //this is the result
However what I am getting is:
1 //this is the number of strings
4*5+2/3 //this is the string itself
2756 //this is the result
That is because the code is doing 52*53+50/51(because it is using the ascii values) and not 4*5+2/3.
I believe the reason for this is because I am storing 4*5+2/3 in a string of char and not in an array of int. I do not know if this is the case and would like some help.
You will not be able to run the following code as it is not complete but the whole program is five files and I do not know if I should put all of it here. I am new to both trees and StackOverflow.
This is my Make Expression Tree function and my Calculate Expression Tree function:
BTreeNode* MakeExpTree(char* exp, int len)
{
Stack stack;
BTreeNode * node, *right_node, *left_node;
InitStack(&stack);
for(int i = 0; i < len; i++){
if('0' <= exp[i] && exp[i] <= '9'){
node = CreateNode(exp[i]);
}
else{
right_node = PeekNode(&stack), Pop(&stack);
left_node = PeekNode(&stack), Pop(&stack);
node = CreateNode(exp[i]);
CreateRightSubtree(node, right_node);
CreateLeftSubtree(node, left_node);
}
PushNode(&stack, node);
}
return PeekNode(&stack);
}
int CalculateExpTree(BTreeNode* root)
{
int ret, op1, op2;
if(root == NULL){
return 0;
}
if(root->left_child == NULL && root->right_child == NULL){
return root->item;
}
op1 = CalculateExpTree(root->left_child);
op2 = CalculateExpTree(root->right_child);
switch(root->item){
case '+':
ret = op1 + op2;
break;
case '-':
ret = op1 - op2;
break;
case '*':
ret = op1 * op2;
break;
case '/':
ret = op1 / op2;
break;
case '#':
ret = op1 * pow( 2, op2);
break;
case '#':
ret = op1 / pow( 2, op2);
break;
}
return ret;
}
This is how I store the string from stdin in main function:
int main()
{
int num_exp, result, len = 0;
char input[10];
char IDK[129];
fgets(input, 9, stdin); //user enters number of strings
int m = sscanf(input, "%d", &num_exp);
char string[100][129] = { 0 };
char postfix[100][129] = { 0 };
for(int i = 0; i < num_exp; i++){
fgets(IDK, 129, stdin); //user enters string
int mm = sscanf(IDK, "%s", string[i]); //is this where the problem lies?
} //should I not be storing it in a char string?
for(int x = 0; x < num_exp; x++){
InfixToPostfix(string[x], postfix[x]); //converts strings from infix to postfix
}
BTreeNode* tree;
for(int k = 0; k < 129; k++){ //calculates length of string
if(postfix[0][k] == '\0'){
break;
}
len++;
}
tree = MakeExpTree(postfix[0], len); //makes expression tree
result = CalculateExpTree(tree); //calculates expression tree
//or is the problem in this function?
printf("%d \n", result);
return 0;
}
I am not understanding clearly what you are doing and it would help my learning too if you shared from what source are you learning these (we can chat in chat room) but I also tried to do similar thing and in my style it works partially (that is, sometimes when I insert larger number the answer is wrong but for small numbers generally correct).So you might get some help form my style of this code that calculates given string (A little help for me also would be appreciated commenters!!). My code:
#include <stdio.h>
#include <string.h>
#include "stackforcalc.h"
int isOperand(char b){
if(b>='0' && b<='9'){
return 1;
}else{
return 0;
}
}
int isOperator(char b){
if(b=='+' || b=='-' || b=='*' || b=='/'){
return 1;
}
return 0;
}
int getwt(char b){
int g=-1;
switch (b)
{
case '+':
case '-':
g=1;
break;
case '/':
case '*':
g=28787868;
break;
}
return g;
}
int higherprecedence(char a,char b){
int c=getwt(a);
int d=getwt(b);
return (c>=d)?1:0;
}
int infToPost(char *b,char *str){
int j=0;
for(int i=0;i<strlen(b);i++){
if(b[i]== ' ' || b[i]== ',' ){
continue;
}
else if(isOperator(b[i])){
str[j]=' ';
j++;
while(!empty() && gettop() != '(' && higherprecedence(gettop(),b[i])){
str[j]=gettop();
j++;
pop();
}
push(b[i]);
}
else if(isOperand(b[i])){
str[j]=b[i];
j++;
}
else if(b[i]=='('){
push(b[i]);
}
else if(b[i] ==')'){
while(!empty() && gettop() != '('){
str[i]=gettop();
j++;
pop();
}
pop();
}
}
while(!empty()){
str[j]=gettop();
j++;
pop();
}
}
int Evaluate(int t,char y,int r){
int ty;
switch(y){
case '+':
ty=t+r;
break;
case '-':
ty=r-t; //I inverted these.
break;
case '*':
ty=r*t;
break;
case '/': //I inverted these because
ty=r/t; //even though I did t/r it performed r/t.
break; //may be somewhere before the numbers were swapped
default:
ty=-1;
break;
}
return ty;
}
int calculatepostfix(char *c){
for(int i=0;i<strlen(c);i++){
if(c[i]==' ' || c[i]==','){
continue;
}
else if(isOperator(c[i])){
int op1=gettop2();
pop2();
int op2=gettop2();
pop2();
int oper=Evaluate(op1,c[i],op2);
push2(oper);
}
else if(isOperand(c[i])){
int res=0;
while(i<strlen(c) && isOperand(c[i])){
res=(res*10)+(c[i]-'0');
i++;
}
i--;
push2(res);
}
}
return gettop2();
}
int main(){
char b[65];
printf("\n \n**-- Calculator --**\n");
printf("Enter expression: ");
fgets(b,sizeof(b),stdin);
char str[50];
infToPost(b,str);
int tt =calculatepostfix(str);
printf("Your answer is: %d",tt);
}
The code in "stackforcalc.h" is
#ifndef stacycalc
#define stacycalc
#define maxsize 50
char a[maxsize];
int top=-1;
int abc[maxsize];
int to=-1;
void push2(int re){ abc[++to]=re; }
void push(char b){ a[++top]=b; }
void pop2(){ to--; }
void pop(){ top--;}
int gettop2(){ return (to==-1)?-1:abc[to]; }
char gettop(){ return (top==-1)?0:a[top]; }
int empty(){ return (top==-1)?1:0; }
#endif
That is because the code is doing 52*53+50/51 (because it is using the ascii values) and not 4*5+2/3.
Yes.
I believe the reason for this is because I am storing 4*5+2/3 in a string of char and not in an array of int.
No.
In C, int is just a bigger char. There's nothing magical about them; they both hold numbers.
There are a variety of ways to derive the integer value from an ASCII character. If you have exactly one character and don't want to use a library, you can "mask off" the bits: since the ASCII range for digits is 0x30 - 0x39,
static char string[] = "4";
int value = string[0] & 0x0F;
does the trick. For more complex operations, my favorite is sscanf(3), but many use atoi(3) or various flavors of strtol(3).

How do I evaluate decimals & floating point numbers in scientific e notation - e.g. {1.23e4}. in postfix?

I have written my code to evaluate from postfix to result. However, I am stuck at how to do it when the postfix is going to be in decimals & floating point numbers in scientific e notation - e.g. {1.23e4}. Any specific suggestion would be highly appreciated. Thanks.
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#define SIZE 50 /* Size of Stack */
double s[SIZE];
int top=-1; /* Global declarations */
int flag=0;
double pop()
{ /* Function for POP operation */
return(s[top--]);
}
double push(double elem)
{ /* Function for PUSH operation */
if(flag==1){
int num;
num=pop();
s[++top]=elem+10*num;
}
else if(flag==0){
s[++top]=elem;
flag=1;
}
}
void main()
{ /* Main Program */
char pofx[50],ch;
int i=0;
double op1,op2;
printf("Enter the Postfix Expression:");
fgets(pofx,100,stdin);
while( (ch=pofx[i++]) != '\n')
{
if(isdigit(ch)) push(ch-'0'); /* Push the operand */
else if(ch==' ')
flag=0;
else
{ /* Operator,pop two operands */
flag=0;
op2=pop();
op1=pop();
switch(ch)
{
case '+':push(op1+op2);break;
case '-':push(op1-op2);break;
case '*':push(op1*op2);break;
case '/':push(op1/op2);break;
case '^':push(pow(op1,op2));break;
default:
printf("Input invalid ... give proper input\n");
return 0;
}
}
}
printf("Result: %lf\n",s[top]);
}
How do I evaluate decimals & floating point numbers in scientific e notation ... (?)
To convert a string into FP value use strtod() #M Oehm
Yet code has other problems in that the operator symbols '-' and '+' may also begin valid value tokens like -123.45.
// insufficient test to determine if the next part of the string is a number or operator.
if(isdigit(ch))
push(ch-'0');
Use strtod() to convert text to double and determine if the next part of the string is a double.
Alternative code:
const char *st = pofx;
while (*st) {
char *end; //location to store end of FP parsing
double value = strtod(st, &end);
if (end > st) {
push(value);
st = end;
} else if (isspace((unsigned char) *st)) {
st++;
} else {
switch (*st) {
case '+':push(pop() + pop());break; // pop order irrelevant
case '-':{ double t = pop(); push(pop() - t);break; } // pop order relevant
case '*':push(pop() * pop());break;
...
default: {
printf("Input invalid operator: character code %d\n", *st);
return 0;
}
} // end switch
st++;
}
}
Re-write push()
void push(double elem) {
if (top + 1 >= SIZE) {
printf("Stack overflow\n");
return;
}
s[++top] = elem;
}
Wrong argument to fgets()
char pofx[50];
// fgets(pofx,100,stdin); // 100??
fgets(pofx, sizeof pofx, stdin); // better
The function strtod from <stdlib.h> will parse a double for you. It takes the string to parse and a pointer to a string, that will begin with the first unparsed character. (There's a similar function for long integers, strtol.)
Here's an example of how this might work in your case. (The code just prints out the tokens and doesn't do any calculations.)
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int is_number(const char *p)
{
if (*p == '-' || *p == '+') p++;
if (*p == '.') p++;
return isdigit((unsigned char) *p);
}
int main(void)
{
const char *line = " .1 20.1* 1.0e-3+2e+7 * -1.0*";
const char *p = line;
while (isspace((unsigned char) *p)) p++;
while (*p) {
if (is_number(p, after_op)) {
char *end;
double x = strtod(p, &end);
if (p == end) {
puts("Illegal number");
p++;
} else {
printf("Number %g\n", x);
p = end;
}
} else {
int c = *p++;
switch (c) {
case '+': puts("Operator add"); break;
case '-': puts("Operator sub"); break;
case '*': puts("Operator mult"); break;
case '/': puts("Operator div"); break;
case '^': puts("Operator pow"); break;
default: printf("Illegal char '%c'\n", c);
}
}
while (isspace((unsigned char) *p)) p++;
}
return 0;
}
This is still very crude, mind you. Strings like 20x21 will be parsed as number 20, unknown character x and number 21. While this code is bad at detecting and reporting errors (which really should be done, but it's left as an exercise, yadda, yadda), it works for valid input.
[Edit: I've incorporated chux's suggestions and also made the code compatible to read numbers with explicit signs, but that means that the binary operators - and + cannot immediately be followed by a digit. Pick your poison. I've also allowed the abridged version that leaves out a leading zero, e.g. .12, a format that I'm not very fond of.]

printf with %g and a correct double value prints irritating number - What could be the cause?

Hi there I was hoping to find help here. I don't understand the following behavior. Please note that this is an exercise from The C Programming Language (4-4).
It is about the double top(void) definition in the stack.c. It should return the top of the stack as a double.
When I try to print it (with the command p) then the number format is not correct.
If I put the printf(...) in the top function itself then the format is correct.
I don't understand why that is.
I am using NetBeans 8.0.2 with default gcc compiler.
main.c
#include <stdio.h>
#include <stdlib.h>
#define MAXOP 100 /* max size of operand or operator */
#define NUMBER '0' /* signal that a number was found */
int getop(char []);
void push(double);
double pop(void);
/* reverse Polish calculator */
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;
case '%':
op2 = pop();
if (op2 != 0.0)
push((int) pop() % (int) op2);
else
printf("error: zero divisor\n");
break;
case 'p':
printf("\t%.8g\n", top());
break;
case 'd':
push(top());
break;
case 's':
printStack();
break;
case '\n':
printf("\t%.8g\n", pop());
break;
default:
printf("error: unknown command %s\n", s);
break;
}
}
return 0;
}
stack.c
#include <stdio.h>
#define MAXVAL 100 /* maximum depth of val stack */
int sp = 0;
/* next free stack position */
double val[MAXVAL];
/* value stack */
/* 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;
}
}
/* top: return top value from stack */
double top(void) {
if (sp > 0) {
return val[sp - 1];
} else {
printf("error: stack empty\n");
return 0.0;
}
}
/* swap two top values */
void swap(void) {
if (sp > 1) {
double t1 = pop();
double t2 = pop();
push(t1);
push(t2);
} else
printf("error: stack (almost) empty\n");
}
/* clear the stack */
void clear(void) {
sp = 0;
}
/* print the stack */
void printStack(void) {
int i;
for (i = sp - 1; i >= 0; i--)
printf("%g ", val[i]);
}
getop.c
#include <ctype.h>
#include <stdio.h>
#define NUMBER '0' /* signal that a number was found */
int getch(void);
void ungetch(int);
/* getop: get next operator or numeric operand */
int getop(char s[]) {
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';
if (!isdigit(c) && c != '.' && c != '-')
return c;
if (c == '-') { // possible negative number
if (!isdigit(s[0] = c = getch())) { // minus operator
ungetch(c);
s[0] = c = '-';
return c;
} else { // negative number
s[0] = '-';
s[1] = c;
i = 1;
}
} else
i = 0; // positive number
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.c
#define BUFSIZE 100
char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */
int getch(void) /* get a (possibly pushed back) character */ {
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c) /* push character back on input */ {
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
Your main.c does not know how top is defined. It decides on a default return value of int, which leads to undefined behaviour when printing it with a format designed for double. If you enable warnings, which you should, you'll get something like "Implicit declaration of top".
You have written the declarations of the stack functions push and pop at the top of main.c, but not the declaration of top.
Including the required prototypes by hand is not good practice. It is better to declare the interface of a compilation unit in a header file:
// stack.h
#ifndef STACK_H_INCLUDED
#define STACK_H_INCLUDED
void push(double f);
double pop(void);
double top(void);
void swap(void);
#endif
Include that header file from the code where you wish to use the interface. You will always have the correct and up-to-date version.
Include the header from stack.c, too, to ensure that the published interface and the actual implementation are consistent.
%g prints shorter of the two representations: f or e .
example:
1) printf( "%g", 3.1415926 );
OUTPUT: 3.1515926
2) printf( "%g", 93000000.0 );
OUTPUT: 9.3e+07
Where scientific notation is most appropriate.

Reverse Polish Calculator in C : isdigit() issues

I'm doing a homework assignment in C. I have to build a calculator that takes in RPN, converts it to a double, adds / removes it from stack and prints what's left on the stack.
Everything seems to be going well until I run it. Upon entering my input, the char[] gets successfully converted to double (or so i think) and somewhere along the way (maybe in getop()) does the program think that i'm not entering digits. Here is the code and the output.
#include <stdio.h>
#define MAXOP 100 /* maximum size of the operand of operator */
#define NUMBER '0' /* signal that a number was found */
int getOp(char []); /* takes a character string as an input */
void push(double);
double pop(void);
double asciiToFloat(char []);
/* reverse polish calculator */
int main()
{
int type;
double op2;
char s[MAXOP];
printf("Please enter Polish Notation or ^d to quit.\n");
while ((type = getOp(s)) != EOF) {
switch (type) {
case NUMBER:
push(asciiToFloat(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%.2f\n", pop()); /* this will print the last item on the stack */
printf("Please enter Polish Notation or ^d to quit.\n"); /* re-prompt the user for further calculation */
break;
default:
printf("error: unknown command %s.\n", s);
break;
}
}
return 0;
}
#include <ctype.h>
/* asciiToFloat: this will take ASCII input and convert it to a double */
double asciiToFloat(char s[])
{
double val;
double power;
int i;
int sign;
for (i = 0; isspace(s[i]); i++) /* gets rid of any whitespace */
;
sign = (s[i] == '-') ? -1 : 1; /* sets the sign of the input */
if (s[i] == '+' || s[i] == '-') /* excludes operands, plus and minus */
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;
}
#define MAXVAL 100 /* maximum depth of value stack */
int sp = 0; /* next free stack position */
double val[MAXVAL]; /* value stack */
/* push: push f onto value stack */
void push(double f)
{
if (sp < MAXVAL) {
val[sp++] = f; /* take the input from the user and add it to the stack */
printf("The value of the stack position is %d\n", sp);
}
else
printf("error: stack full, cant push %g\n", f);
}
/* pop: pop and return the top value from the stack */
double pop(void)
{
if (sp > 0)
return val[--sp];
else {
printf("error: stack empty\n");
return 0.0;
}
}
#include <ctype.h>
int getch(void);
void ungetch(int);
/* getOp: get next operator or numeric operand */
int getOp(char s[])
{
int i;
int c;
while ((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';
if (!isdigit(c) && c != '.') {
printf("Neither a digit or a decimal.\n");
return c; /* neither a digit nor a decimal */
}
i = 0;
if (isdigit(c)) /* grab the integer */
while (isdigit(s[++i] = c = getch()))
;
if (c == '.') /* grab the fraction */
while (isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}
#define BUFSIZE 100
char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buffer */
/* getch: get a number that may or may not have been pushed back */
int getch(void)
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
/* ungetch: if we read past the number, we can push it back onto input buffer */
void ungetch(int c)
{
if (bufp >= BUFSIZE)
printf("ungetch: to many characters.\n");
else
buf[bufp++] = c;
}
Output :
Please enter Polish Notation or ^d to quit.
123
The value of the stack position is 1
Neither a digit or a decimal.
123.00
Please enter Polish Notation or ^d to quit.
Any thoughts regarding what's going on will be super helpful. It seems like then number is properly getting passed in, properly formatted from char to double, and then something goes wrong.
Thank you.
Rock
Change
printf("Neither a digit or a decimal.\n");
to
printf("Neither a digit or a decimal: %d 0x%x.\n", c, c);
so you can see what is causing the message.
Your output shows that getch() is returning the line feed ("\n", 0x0A) at the end of the line. Also, unless you were required to write asciiToFloat() for your homework assignment, you should use atof() or strtod() (both declared in "stdlib.h") from the Standard C Library. They are (usually?) implemented to avoid loss of precision and accuracy during the conversion; repeatedly multiplying by 10 causes a loss of same. Nice looking code, otherwise! :)

gcc produces .o but bash says unknown command

Edit: I've fixed several things that were pointed out but the real problem remains unsolved.
This bash script:
set -vx
/usr/bin/llvm-gcc-4.2 -ansi -g -o mytest mytest.c
ls -l mytest
./mytest
file mytest
produces this output:
/usr/bin/llvm-gcc-4.2 -ansi -g -o mytest mytest.c
++ /usr/bin/llvm-gcc-4.2 -ansi -g -o mytest mytest.c
ls -l mytest
++ ls -l mytest
-rwxr-xr-x 1 jimslager wheel 37496 May 27 17:26 mytest
./mytest
++ ./mytest
error: unknown command ./mytest
file mytest
++ file mytest
mytest: Mach-O 64-bit executable x86_64
I've extracted this out of something larger that I've been using for several months but have never seen a result like this. How can gcc produce an object with no errors or warnings but the object is unknown?
I'll post test.c if someone asks but it's long and my question seems to me to be independent of what's in test.c.
Edit: Here is the code. Sorry it is so long.
/* Test Exercise 5-10: Write the program myexpr, which evaluates a reverse Polish expression from the command line, where each operator or operand is a separate argument. For example,
* expr 2 3 4 + *
* evaluates 2 x (3+4).
* */
#include <stdio.h>
#include <string.h>
#define MAXLINE 68
#define TABSIZE 8
#define TAB '`'
#define SPACE '-'
#define NEW '\\'
#define TRUE 1
#define FALSE 0
#define IN 1
#define OUT 0
#define FOLDLENGTH 20
#define MAXLEN 12
#define SMALLER(i, j) ((i) > (j) ? (j) : (i))
#define N(c) (c=='\0' ? '\\' : c)
/* #include "subs.c" */
#define MAXOP 100 /* max size of operand or operator */
#define NUMBER '0' /* signal that a number was found */
int getop(char []);
void push(double);
double pop(void);
double top(void);
void dup(void);
void clear(void);
void stackswap(void);
double atof(char s[]);
int myisdigit(char c);
int myisspace(char c);
/* reverse Polish calculator */
int main(int argc, char *argv[])
{
int type;
double op2;
char s[MAXOP];
while (--argc>0)
while (type = getop(&(*++argv[0])))
printf("Just after while: type = %d, *argv[0] = %s\n", type, *argv);
switch (type) {
case NUMBER:
push(atof(*argv));
printf("NUMBER: atof(*argv[0]) = %g, *argv[0] = %s\n", atof(*argv), *argv);
break;
case '+':
printf("+ detected\n");
push(pop() + pop());
break;
case '*':
printf("* detected\n");
push(pop() * pop());
break;
case '-':
printf("- detected\n");
op2 = pop();
push(pop() - op2);
break;
case '/':
printf("/ detected\n");
op2 = pop();
if (op2 != 0.0)
push(pop() / op2);
else
printf("error: zero divisor\n");
break;
case '%':
printf("Modulo detected\n");
op2 = pop();
if (op2 != 0.0)
push((int) pop() % (int) op2);
else
printf("error: zero divisor\n");
break;
case 't':
printf("t detected\n");
printf("%g\n", top());
break;
case 'd':
printf("d detected\n");
dup();
break;
case 's':
printf("s detected\n");
stackswap();
break;
case 'c':
printf("c detected\n");
clear();
break;
case '\n':
printf("\\n detected\n");
printf("\t%.8g\n", pop());
break;
default:
printf("error: unknown command %s\n", *argv);
break;
}
return 0;
}
#define MAXVAL 100 /* maximum depth of val stack */
int sp = 0; /* next free stack position */
double val[MAXVAL]; /* value stack */
/* push: push f onto value stack */
void push(double f)
{
printf("push: Started. f = %g, sp = %d\n", f, sp);
if (sp < MAXVAL)
val[sp++] = f;
else
printf("error: stack full, can't push %g\n", f);
printf("push: Finished. f = %g, sp = %d\n", f, sp);
}
/* dup: duplicate top of stack */
void dup(void)
{
printf("dup: Started. top = %g, sp = %d\n", top(), sp);
push(top());
printf("dup: Finished. top = %g, sp = %d\n", top(), sp);
}
/* pop: pop and return top value from stack */
double pop(void)
{
printf("pop: sp = %d, val[--sp] = %g\n", sp, val[sp-1]);
if (sp > 0)
return val[--sp];
else {
printf("error: stack empty\n");
return 0.0;
}
}
/* top: return top value from stack without changing sp */
double top(void)
{
printf("top: sp = %d, val[0] = %g\n", sp, val[0]);
if (sp > 0)
return val[sp-1];
else {
printf("error: stack empty\n");
return 0.0;
}
}
/* stackswap: swap the top 2 values in stack */
void stackswap(void)
{
printf("Starting stackswap: val[sp-1] = %g, val[sp-2] = %g\n", val[sp-1], val[sp-2]);
double op2, op3;
op2 = pop();
op3 = pop();
push(op2);
push(op3);
printf("Finishing stackswap: val[sp-1] = %g, val[sp-2] = %g\n", val[sp-1], val[sp-2]);
}
/* clear: clear the stack */
void clear(void)
{
sp = 0;
}
int getch(void);
void ungetch(int);
/* 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 != '.')
return c; /* not a number */
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;
}
#define BUFSIZE 100
char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */
int getch(void) /* get a (possibly pushed-back) character */
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c) /* push character back on input */
{
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
/* atof: convert s to double */
double atof(char s[])
{
double val, power, epower, d;
int i, j, sign, esign=0, eval;
printf("atof: s = %s\n", s);
for (i = 0; myisspace(s[i]); i++); /* skip white space */
sign = (s[i] == '-') ? -1 : 1; /* Determine sign and strip it */
if (s[i] == '+' || s[i] == '-')
i++;
for (val = 0.0; myisdigit(s[i]); i++) /* Determine value before dec point */
val = 10.0 * val + (s[i] - '0');
if (s[i] == '.')
i++;
for (power = 1.0; myisdigit(s[i]); i++) { /* include value after dec */
val = 10.0 * val + (s[i] - '0');
power *= 10; /* power is where . goes */
}
if (s[i]=='e' || s[i]=='E') { /* Exponential form */
esign = (s[++i]=='-') ? -1 : 1; /* Sign of exponent */
if (s[i]=='+' || s[i]=='-')
i++;
for (epower=0.1, eval=0.0; myisdigit(s[i]); i++) { /* Determine exponent */
eval = 10*eval + (s[i]-'0');
epower *= 10;
}
}
d = (sign*val / power); /* Place dec point in mantissa */
if (esign!=0) { /* If exp form then adjust exponent */
for (j=1; j<=eval; j++) {
d = (esign==1 ? d*10.0 : d/10.0);
}
}
return (d);
}
/* Determine is c is a digit */
int myisdigit(char c)
{
if (c>='0' && c<='9')
return TRUE;
else
return FALSE;
}
/* Returns 1 if c is whitespace, 0 otherwise */
int myisspace(char c)
{
return ((c==' ' || c=='\n' || c=='\t') ? 1 : 0);
}
It should probably be ./test.o to run it. Generally, UNIX systems don't have "." (the current dir) in the PATH by default.
Also, the ".o" extension is slightly misleading, because that is convention for an intermediate object file, not a stand-alone executable like you have produced here.
Make the last line ./test.o and everything should work.
If you only supply the file name but not a path, then only the search paths will be taken into account, and your current working directory in most cases isn't part of them (or rather definitely not, in your example).
. is not in $PATH, so you need to specify the path to the file. ./test.o
.o files are usually not executable; they must be linked before they can be run. Although this is not the case here.
Probably the local directory is not in your path (nor do you want it to be). You should be able to run it with ./test.o. Also, the .o suffix here is strange. You have a dynamically linked executable file, not an object file. (Try file test.o.) On Unix those normally don't have an extension, on Windows they normally have the extension .exe.
Doh! It finally occurred to me what is happening here. This program is exercise 5-10 from K&R which is to revise the Reverse Polish Calculator of page 76 to receive its input from the command line rather than from stdin. I was in the process of doing that when I got the "unknown command" message and thought it was coming from the compiler but it was actually coming from my own code!
Now I will go back and modify it to prefix all error messages with argv[0] (and use this from now on) so that this mistake will never happen again.

Resources