我对代码进行了一些小的修改,以便可以将其编译为单个文件,并添加了基本的调试打印,并将堆栈类型从 int 更改为 float。通过这些更改,我无法重现声称的问题。
代码(rpn61.c):
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// #include "stack.h"
void make_empty(void);
bool is_empty(void);
bool is_full(void);
void push(float i);
float pop(void);
float read_expression(void);
int main(void)
{
for ( ; ; )
{
printf("Enter an RPN expression: ");
printf("\nValue of expression: %.4f\n", read_expression());
}
}
float read_expression(void)
{
while (scanf("\n") == false)
{
float operand, op1, op2;
char ch;
if (scanf(" %f", &operand))
{
push(operand);
}
else
{
scanf(" %c", &ch);
switch (ch)
{
case '+':
op2 = pop();
op1 = pop();
printf("%f + %f = %f\n", op1, op2, op1 + op2);
push(op1 + op2);
break;
case '-':
op2 = pop();
op1 = pop();
printf("%f - %f = %f\n", op1, op2, op1 - op2);
push(op1 - op2);
break;
case '*':
op2 = pop();
op1 = pop();
printf("%f * %f = %f\n", op1, op2, op1 * op2);
push(op1 * op2);
break;
case '/':
op2 = pop();
op1 = pop();
printf("%f / %f = %f\n", op1, op2, op1 / op2);
push(op1 / op2);
break;
case '=':
op1 = pop();
printf("Result = %f\n", op1);
return op1;
//return pop();
default:
printf("Unexpected operator %c\n", ch);
exit(EXIT_SUCCESS);
}
}
}
return 0;
}
#define STACK_SIZE 100
_Noreturn void stack_overflow(void);
_Noreturn void stack_underflow(void);
void stack_underflow(void)
{
printf("\nNot enough operands in expression\n");
exit(EXIT_FAILURE);
}
void stack_overflow(void)
{
printf("\nExpression is too complex\n");
exit(EXIT_FAILURE);
}
float contents[STACK_SIZE];
int top = 0;
void make_empty(void)
{
top = 0;
}
bool is_empty(void)
{
return top == 0;
}
bool is_full(void)
{
return top == STACK_SIZE;
}
void push(float i)
{
if (is_full())
stack_overflow();
else
contents[top++] = i;
}
float pop(void)
{
if (is_empty())
stack_underflow();
else
return contents[--top];
}
样本输出
$ rpn61
Enter an RPN expression: 1 2 3 4 5 + + + + =
4.000000 + 5.000000 = 9.000000
3.000000 + 9.000000 = 12.000000
2.000000 + 12.000000 = 14.000000
1.000000 + 14.000000 = 15.000000
Result = 15.000000
Value of expression: 15.0000
Enter an RPN expression: 3 4 + =
3.000000 + 4.000000 = 7.000000
Result = 7.000000
Value of expression: 7.0000
Enter an RPN expression: 3 4 5 6 + + + =
5.000000 + 6.000000 = 11.000000
4.000000 + 11.000000 = 15.000000
3.000000 + 15.000000 = 18.000000
Result = 18.000000
Value of expression: 18.0000
Enter an RPN expression: 3 4 + 5 6 +
3.000000 + 4.000000 = 7.000000
5.000000 + 6.000000 = 11.000000
=
Result = 11.000000
Value of expression: 11.0000
Enter an RPN expression: =
Result = 7.000000
Value of expression: 7.0000
Enter an RPN expression: 3 4 + 5 6 +
3.000000 + 4.000000 = 7.000000
5.000000 + 6.000000 = 11.000000
=
Result = 11.000000
Value of expression: 11.0000
Enter an RPN expression: 11.11111 +=
7.000000 + 11.111110 = 18.111111
Result = 18.111111
Value of expression: 18.1111
Enter an RPN expression: 355 113 /
355.000000 / 113.000000 = 3.141593
q
Unexpected operator q
$
TL;DR
我无法重现您的问题...
更多调试(rpn67.c):
此代码包含更多调试信息。特别是,有一个函数dump_stack() 将信息转储到堆栈上,并且代码在读取操作数和运算符时报告它们。很遗憾,我仍然无法重现您的问题。
我想知道scanf(" %f", &operand) 是否正在使用+ 运算符。它不应该,但它可能是对出了什么问题的解释。这可以通过查看操作符在读取时的内容来揭示。是不是只有+ 和- 丢失了,还是你有一个带有* 或/(而不是+ 或-)的序列也出错了?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// #include "stack.h"
void make_empty(void);
bool is_empty(void);
bool is_full(void);
void push(float i);
float pop(void);
static void dump_stack(void);
float read_expression(void);
int main(void)
{
for ( ; ; )
{
printf("Enter an RPN expression: ");
printf("\nValue of expression: %.4f\n", read_expression());
dump_stack();
}
}
float read_expression(void)
{
while (scanf("\n") == false)
{
float operand, op1, op2;
char ch;
if (scanf(" %f", &operand))
{
printf("NUmber: %f\n", operand);
push(operand);
dump_stack();
}
else
{
if (scanf(" %c", &ch) != 1)
{
fprintf(stderr, "Operator scan failed\n");
exit(EXIT_FAILURE);
}
printf("Operator: %c\n", ch);
dump_stack();
switch (ch)
{
case '+':
op2 = pop();
op1 = pop();
printf("%f + %f = %f\n", op1, op2, op1 + op2);
push(op1 + op2);
break;
case '-':
op2 = pop();
op1 = pop();
printf("%f - %f = %f\n", op1, op2, op1 - op2);
push(op1 - op2);
break;
case '*':
op2 = pop();
op1 = pop();
printf("%f * %f = %f\n", op1, op2, op1 * op2);
push(op1 * op2);
break;
case '/':
op2 = pop();
op1 = pop();
printf("%f / %f = %f\n", op1, op2, op1 / op2);
push(op1 / op2);
break;
case '=':
op1 = pop();
printf("Result = %f\n", op1);
return op1;
//return pop();
default:
printf("Unexpected operator %c\n", ch);
exit(EXIT_SUCCESS);
}
}
}
return 0;
}
#define STACK_SIZE 100
_Noreturn void stack_overflow(void);
_Noreturn void stack_underflow(void);
void stack_underflow(void)
{
printf("\nNot enough operands in expression\n");
exit(EXIT_FAILURE);
}
void stack_overflow(void)
{
printf("\nExpression is too complex\n");
exit(EXIT_FAILURE);
}
float contents[STACK_SIZE];
int top = 0;
void make_empty(void)
{
top = 0;
}
bool is_empty(void)
{
return top == 0;
}
bool is_full(void)
{
return top == STACK_SIZE;
}
void push(float i)
{
if (is_full())
stack_overflow();
else
contents[top++] = i;
}
float pop(void)
{
if (is_empty())
stack_underflow();
else
return contents[--top];
}
static void dump_stack(void)
{
printf("Stack (%d): Top", top);
for (int i = top; i > 0; i--)
printf(" %f", contents[i-1]);
printf(" Bottom\n");
}
样本输出
$ rpn67
Enter an RPN expression: 1 2 3 4 5 + + + + =
NUmber: 1.000000
Stack (1): Top 1.000000 Bottom
NUmber: 2.000000
Stack (2): Top 2.000000 1.000000 Bottom
NUmber: 3.000000
Stack (3): Top 3.000000 2.000000 1.000000 Bottom
NUmber: 4.000000
Stack (4): Top 4.000000 3.000000 2.000000 1.000000 Bottom
NUmber: 5.000000
Stack (5): Top 5.000000 4.000000 3.000000 2.000000 1.000000 Bottom
Operator: +
Stack (5): Top 5.000000 4.000000 3.000000 2.000000 1.000000 Bottom
4.000000 + 5.000000 = 9.000000
Operator: +
Stack (4): Top 9.000000 3.000000 2.000000 1.000000 Bottom
3.000000 + 9.000000 = 12.000000
Operator: +
Stack (3): Top 12.000000 2.000000 1.000000 Bottom
2.000000 + 12.000000 = 14.000000
Operator: +
Stack (2): Top 14.000000 1.000000 Bottom
1.000000 + 14.000000 = 15.000000
Operator: =
Stack (1): Top 15.000000 Bottom
Result = 15.000000
Value of expression: 15.0000
Stack (0): Top Bottom
Enter an RPN expression: q
Operator: q
Stack (0): Top Bottom
Unexpected operator q
$
再现!
在 Mac 上运行的 Ubuntu 16.04 VM,rpn67 产生:
$ rpn67
Enter an RPN expression: 1 2 3 4 5 + + + + =
NUmber: 1.000000
Stack (1): Top 1.000000 Bottom
NUmber: 2.000000
Stack (2): Top 2.000000 1.000000 Bottom
NUmber: 3.000000
Stack (3): Top 3.000000 2.000000 1.000000 Bottom
NUmber: 4.000000
Stack (4): Top 4.000000 3.000000 2.000000 1.000000 Bottom
NUmber: 5.000000
Stack (5): Top 5.000000 4.000000 3.000000 2.000000 1.000000 Bottom
Operator: +
Stack (5): Top 5.000000 4.000000 3.000000 2.000000 1.000000 Bottom
4.000000 + 5.000000 = 9.000000
Operator: +
Stack (4): Top 9.000000 3.000000 2.000000 1.000000 Bottom
3.000000 + 9.000000 = 12.000000
Operator: =
Stack (3): Top 12.000000 2.000000 1.000000 Bottom
Result = 12.000000
Value of expression: 12.0000
Stack (2): Top 2.000000 1.000000 Bottom
Enter an RPN expression: q
Operator: q
Stack (2): Top 2.000000 1.000000 Bottom
Unexpected operator q
$
显示有问题。我们在scanf() 的 Linux 和 BSD/macOS 版本之间存在差异。
Linux 实现中甚至可能存在一些正义。它最多向前看一个字符,因此它将+ 读取为有效的可能开始,然后找到一个空白,意识到它作为数字无效,并且转换失败,但只有空格而不是+被推回去了。
因此,您将需要一种不同的机制来代替 if (scanf(" %f", &operand)) 来读取操作数。
分辨率
有很多方法可以“解决”问题。下面的代码很hacky,但或多或少可以完成这项工作。更好的解决方案是将接口重新设计为read_expression(),以便它返回状态和评估的表达式。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
// #include "stack.h"
void make_empty(void);
bool is_empty(void);
bool is_full(void);
void push(float i);
float pop(void);
static void dump_stack(void);
float read_expression(void);
int main(void)
{
for ( ; ; )
{
printf("Enter an RPN expression: ");
printf("\nValue of expression: %.4f\n", read_expression());
dump_stack();
}
}
static inline bool is_operator(char c)
{
return (c == '+' || c == '-' || c == '*' || c == '/' || c == '=' || c == '.' || c == 'q');
}
static bool get_token(size_t buflen, char buffer[buflen])
{
int c;
while ((c = getchar()) != EOF && isspace((unsigned char)c))
;
ungetc(c, stdin);
size_t i;
for (i = 0; i < buflen - 1; i++)
{
c = getchar();
if (c == EOF)
{
if (i > 0)
{
buffer[i] = '\0';
return true;
}
else
{
printf("EOF detected\n");
return false;
}
}
else if (isspace(c))
{
buffer[i] = '\0';
return true;
}
else if (isdigit(c) || is_operator(c))
{
buffer[i] = c;
}
else
{
printf("Invalid character %c\n", c);
buffer[i] = '\0';
return false;
}
}
buffer[i] = '\0';
return false;
}
float read_expression(void)
{
char buffer[64];
while (get_token(sizeof(buffer), buffer))
{
float operand;
if (sscanf(buffer, " %f", &operand))
{
printf("NUmber: %f\n", operand);
push(operand);
dump_stack();
}
else
{
char ch;
if (sscanf(buffer, " %c", &ch) != 1)
{
fprintf(stderr, "Operator scan failed\n");
exit(EXIT_FAILURE);
}
printf("Operator: %c\n", ch);
dump_stack();
float op1, op2;
switch (ch)
{
case '+':
op2 = pop();
op1 = pop();
printf("%f + %f = %f\n", op1, op2, op1 + op2);
push(op1 + op2);
break;
case '-':
op2 = pop();
op1 = pop();
printf("%f - %f = %f\n", op1, op2, op1 - op2);
push(op1 - op2);
break;
case '*':
op2 = pop();
op1 = pop();
printf("%f * %f = %f\n", op1, op2, op1 * op2);
push(op1 * op2);
break;
case '/':
op2 = pop();
op1 = pop();
printf("%f / %f = %f\n", op1, op2, op1 / op2);
push(op1 / op2);
break;
case '=':
op1 = pop();
printf("Result = %f\n", op1);
return op1;
//return pop();
case 'q':
printf("Quitting\n");
exit(EXIT_SUCCESS);
default:
printf("Unexpected operator %c\n", ch);
exit(EXIT_FAILURE);
}
}
}
printf("EOF or invalid input\n");
exit(EXIT_FAILURE);
}
#define STACK_SIZE 100
_Noreturn void stack_overflow(void);
_Noreturn void stack_underflow(void);
void stack_underflow(void)
{
printf("\nNot enough operands in expression\n");
exit(EXIT_FAILURE);
}
void stack_overflow(void)
{
printf("\nExpression is too complex\n");
exit(EXIT_FAILURE);
}
float contents[STACK_SIZE];
int top = 0;
void make_empty(void)
{
top = 0;
}
bool is_empty(void)
{
return top == 0;
}
bool is_full(void)
{
return top == STACK_SIZE;
}
void push(float i)
{
if (is_full())
stack_overflow();
else
contents[top++] = i;
}
float pop(void)
{
if (is_empty())
stack_underflow();
else
return contents[--top];
}
static void dump_stack(void)
{
printf("Stack (%d): Top", top);
for (int i = top; i > 0; i--)
printf(" %f", contents[i-1]);
printf(" Bottom\n");
}
样本输出
$ rpn71
Enter an RPN expression: 1 2 3 4 5 + + + + =
NUmber: 1.000000
Stack (1): Top 1.000000 Bottom
NUmber: 2.000000
Stack (2): Top 2.000000 1.000000 Bottom
NUmber: 3.000000
Stack (3): Top 3.000000 2.000000 1.000000 Bottom
NUmber: 4.000000
Stack (4): Top 4.000000 3.000000 2.000000 1.000000 Bottom
NUmber: 5.000000
Stack (5): Top 5.000000 4.000000 3.000000 2.000000 1.000000 Bottom
Operator: +
Stack (5): Top 5.000000 4.000000 3.000000 2.000000 1.000000 Bottom
4.000000 + 5.000000 = 9.000000
Operator: +
Stack (4): Top 9.000000 3.000000 2.000000 1.000000 Bottom
3.000000 + 9.000000 = 12.000000
Operator: +
Stack (3): Top 12.000000 2.000000 1.000000 Bottom
2.000000 + 12.000000 = 14.000000
Operator: +
Stack (2): Top 14.000000 1.000000 Bottom
1.000000 + 14.000000 = 15.000000
Operator: =
Stack (1): Top 15.000000 Bottom
Result = 15.000000
Value of expression: 15.0000
Stack (0): Top Bottom
Enter an RPN expression: q
Operator: q
Stack (0): Top Bottom
Quitting
$
测试:在使用 GCC 7.2.0 运行 macOS Sierra 10.12.6 的 Mac 上,以及使用 GCC gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609 在 Mac 上运行的 Ubuntu 16.04 VM 上。