为什么我使用与其他人相同的代码获得不同的结果?

时间:2017-09-09 03:33:03

标签: c scanf stdin

我一直在努力与K.N.的这个项目。 King的 C编程:现代方法现在已经有一段时间了。本书指示使用堆栈编写简单的反向抛光表示法评估程序。 “使用scanf(" %c", &ch)  阅读操作符和操作数“指示本书,但我认为编写一个只能评估单个数字整数的求值程序是荒谬和不现实的,因此我使用了float值作为操作数和char值对于运营商。

我的问题是该程序从第一个开始跳过所有其他运算符'+''-''*''/'。它不会对'='执行此操作,也不会对float操作数执行此操作。据我所知scanf这不应该发生 - 请你能解释一下这种现象吗?

编辑:好吧,看起来这段代码对Jonathan Leffler来说效果不错,现在我很困惑为什么它对他有用,但不适合我。

#include <stdio.h>
#include <stdlib.h>
#include "stack.h"

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);
            continue;
        }

        else 
        {
            scanf(" %c", &ch);

            switch (ch)
            {
                case '+':
                    op2=pop();
                    op1=pop();
                    push(op1+op2);
                    break;
                case '-':
                    op2=pop();
                    op1=pop();
                    push(op1-op2);
                    break;
                case '*':
                    op2=pop();
                    op1=pop();
                    push(op1*op2);
                    break;
                case '/':
                    op2=pop();
                    op1=pop();
                    push(op1/op2);
                    break;
                case '=': return pop();
                default: exit(EXIT_SUCCESS);
            }
        }

    }
}

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);
}

如果你想执行这段代码,这里是包含的stack.h文件:

#include<stdbool.h>

#define STACK_SIZE 100

void stack_overflow(void);
void stack_underflow(void);

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];
}

编辑: 下面是编译和执行Jonathan Leffler的rpn61.c的输出,在我的机器上使用gcc 7.1.1-4和clang 4.0.1-5,这是一个Arch linux vm。

[lyle@ARCHnix chapter10]$ ./proj6
Enter an RPN expression: 1 2 3 4 5 + + + + =

Value of expression: 12.0000                                                                                                                                  
Enter an RPN expression: g
[lyle@ARCHnix chapter10]$ clang rpn61.c -o rpn61
[lyle@ARCHnix chapter10]$ ./rpn61
Enter an RPN expression: 1 2 3 4 5 + + + + =
4.000000 + 5.000000 = 9.000000
3.000000 + 9.000000 = 12.000000
Result = 12.000000

Value of expression: 12.0000
Enter an RPN expression: g
Unexpected operator g
[lyle@ARCHnix chapter10]$ gcc rpn61.c -o rpn61
[lyle@ARCHnix chapter10]$ ./rpn61
Enter an RPN expression: 1 2 3 4 5 + + + + =
4.000000 + 5.000000 = 9.000000
3.000000 + 9.000000 = 12.000000
Result = 12.000000

Value of expression: 12.0000
Enter an RPN expression: 1 2 + =
Result = 2.000000

Value of expression: 2.0000
Enter an RPN expression: 1 2 + + =
1.000000 + 2.000000 = 3.000000
Result = 3.000000

Value of expression: 3.0000
Enter an RPN expression: g
Unexpected operator g

1 个答案:

答案 0 :(得分:1)

我对代码进行了一些小修改,以便可以将其编译为单个文件,并添加基本的调试打印,并将堆栈类型从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实现中甚至可能存在一些正义。它最多只查找一个字符,因此它将+读作有效的可能开始,然后找到一个空白,意识到它无效为数字,转换失败,但只有空格而不是{{ 1}}被推回。

因此,您将需要一种不同的机制来代替+来读取操作数。

分辨率

有很多方法可以“解决”这个问题。下面的代码是hacky,但或多或​​少的工作。更好的解决方案是重新设计if (scanf(" %f", &operand))的接口,以便返回状态和评估表达式。

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");
}

测试:在使用GCC 7.2.0运行macOS Sierra 10.12.6的Mac上,以及在Mac上运行的Ubuntu 16.04 VM上,使用GCC $ 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 $