【问题标题】:Postfix getting wrong values in C后缀在 C 中得到错误的值
【发布时间】:2020-11-10 09:02:15
【问题描述】:

所以我正在使用链表在 C 中编写一个后缀程序并且我的输出值是关闭的,例如表达式:[ 3 4 5 * + 6 7 * 8 + 9 * + ] 应该等于 473,但我的程序返回4. 我还需要检查诸如(2 3 - 没有关闭的地方)之类的错误。现在它会忽略它并给我一个值。

我的代码如下:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

// Node to store data and address of next next
struct Node
{
    int value;
    struct Node *next;
} ;

// Stack type
typedef struct Stack
{
    int value;
    struct Node* top;
    struct Node* back;
} Stack;

// Stack Operations
struct Stack* createStack()
{
    Stack* stack = (Stack*) malloc(sizeof(Stack));

    if (!stack)
        return NULL;

    stack->top = NULL;
    stack->value = 0;

    return stack;
}

// check stack is empty or not
int isEmpty(Stack* stack)
{
    return stack->top == NULL;
}

// return peek of stack
int peek(Stack* stack)
{
    return stack->top->value;
}

/**
 * return top of stack and pop element from top of stack
 */
int pop(Stack* stack)
{
    char  top;
    if (!isEmpty(stack)) // no empty
    {
        top = stack->top->value;
        stack->top = stack->top->next;
        stack->value--;
        return top;
    }
    return -1;
}

/*
 * push an element into stack
 */
void push(Stack* stack, char  op)
{
    struct Node *newNode = (struct Node*) malloc(sizeof(struct Node*));

    newNode->next = NULL;
    newNode->value = op;

    if (isEmpty(stack))
    {
        stack->top = newNode;
        stack->value++;
        return;
    }

    newNode->next = stack->top;
    stack->top = newNode;
}


// The main function that returns value of a given postfix expression
int evaluatePostfix(char* exp)
{
    // Create a stack of capacity equal to expression size
    Stack* stack = createStack();
    int i, val, val2, res;

    // Scan all characters one by one
    for (i = 0; i < strlen(exp); i++)
    {
        // If the scanned character is an operand (number here),
        // push it to the stack.

        if (isdigit(exp[i]))
            push(stack, exp[i] - '0');


        // If the scanned character is an operator, pop two
        // elements from stack apply the operator
        else
        {
            val = pop(stack);
            val2 = pop(stack);

            switch (exp[i])
            {
            case '+':
                res = val2 + val;
                push(stack, res);
                break;

            case '-':
                res = val2 - val;
                push(stack, res);
                break;

            case '*':
                res = val2 * val;
                push(stack, res);
                break;

            case '/':
                res = val2 / val;
                push(stack, res);
                break;
            }
            push (stack, res);
        }
    }
    return pop(stack);
}

// Driver program to test above functions
int main()
{
    char exp [20];
    Stack* stack = createStack();


    printf("Enter postfix expression: ");
    scanf("%s", exp);


    printf ("postfix result: %d\n", evaluatePostfix(exp));

    return 0;
}

【问题讨论】:

  • 看起来您要推送结果两次。删除 switch 语句中的 push 调用。我没有检查或测试这个。再加上其他方面:1)您的程序容易受到缓冲区溢出的影响,2)缓存 strlen 的结果,否则你会以 O(n^2) 运行时结束,3)不要转换 malloc 和 4 的结果) 使用sizeof(*newNode) 而不是sizeof(struct Node*)
  • 我把switch里面的push删了还是不正确。
  • 好的,然后尝试调试它。对于初学者,您是否验证过您的堆栈是正确的?请分享您的最小化/调试尝试并包含您的最新代码。双推绝对是不正确的,因此您需要解决该问题并解释新问题出在哪里。谢谢。
  • 我想通了,我摆脱了我的 'stack->value--' 和 'stack->value++'
  • 很高兴听到!随时发布self-answer 或者我们可以将其关闭,因为不再可复制。

标签: c linked-list stack singly-linked-list postfix-notation


【解决方案1】:

对于初学者这个结构定义

// Stack type
typedef struct Stack
{
    int value;
    struct Node* top;
    struct Node* back;
} Stack;

意义不大。例如,不使用数据成员back。数据成员value的含义未知。

动态定义 Stack 类型的对象是没有意义的。所以这个函数

struct Stack* createStack()
{
    Stack* stack = (Stack*) malloc(sizeof(Stack));

    if (!stack)
        return NULL;

    stack->top = NULL;
    stack->value = 0;

    return stack;
}

是多余的。

函数 pop 使用 char 类型的对象而不是 int 类型来返回存储在堆栈中的值。 char 类型的对象无法存储等于例如 473 的正值。

/**
 * return top of stack and pop element from top of stack
 */
int pop(Stack* stack)
{
    char  top;
    ^^^^^^^^^^
    if (!isEmpty(stack)) // no empty
    {
        top = stack->top->value;
        stack->top = stack->top->next;
        stack->value--;
        return top;
    }
    return -1;
}

它也不会释放弹出的节点。所以函数会产生内存泄漏。

同样的问题也出现在函数 push 声明中

void push(Stack* stack, char  op);
                        ^^^^^^^^^

另外你忘了在栈不为空的时候增加数据成员value

if (isEmpty(stack))
{
    stack->top = newNode;
    stack->value++;
    return;
}

newNode->next = stack->top;
stack->top = newNode;
// stack->value++; <===

函数 evaluatePostfix 应该有限定符 const 和它的参数

int evaluatePostfix( const char* exp)

因为传递的字符串在函数中没有改变。

在for循环中使用函数strlen效率低

for (i = 0; i < strlen(exp); i++)

在函数中,您在每个 case 标签下和 switch 语句之后推送计算结果两次

        switch (exp[i])
        {
        case '+':
            res = val2 + val;
            push(stack, res);
            break;

        case '-':
            res = val2 - val;
            push(stack, res);
            break;

        case '*':
            res = val2 * val;
            push(stack, res);
            break;

        case '/':
            res = val2 / val;
            push(stack, res);
            break;
        }
        push (stack, res); 

最好跳过字符串中嵌入的空格。

由于堆栈是动态分配的,您需要在退出函数之前释放它。

这是一个演示程序,展示了如何编写程序。

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

typedef struct Stack
{
    struct Node
    {
        int value;
        struct Node *next;
    } *top;
} Stack;

int push( Stack* stack, int  value )
{
    struct Node *newNode = malloc( sizeof( struct Node ) );
    int success = newNode != NULL;
    
    if ( success )
    {
        newNode->value = value;
        newNode->next = stack->top;
        
        stack->top = newNode;
    }
    
    return success;
}

void pop( Stack *stack )
{
    if ( stack->top != NULL )
    {
        struct Node *tmp = stack->top;
        stack->top = stack->top->next;
        free( tmp );
    }
}

int isEmpty( Stack *stack )
{
    return stack->top == NULL;
}

int peek( Stack *stack )
{
    return stack->top->value;
}


// The main function that returns value of a given postfix expression
int evaluatePostfix( const char *exp )
{
    // Create a stack of capacity equal to expression size
    Stack stack = { NULL };
    int res = 0;

    // Scan all characters one by one
    for ( ; *exp; ++exp )
    {
        if ( !isspace( ( unsigned char )*exp ) )
        {
            // If the scanned character is an operand (number here),
            // push it to the stack.

            if ( isdigit( ( unsigned char ) *exp ) )
            {
                push( &stack, *exp - '0' );
            }

            // If the scanned character is an operator, pop two
            // elements from stack apply the operator
            else
            {
                int val = peek( &stack );
                pop( &stack );
                int val2 = peek( &stack );
                pop( &stack );

                res = 0;
                switch ( *exp )
                {
                    case '+':
                        res = val2 + val;
                        break;

                case '-':
                    res = val2 - val;
                    break;

                case '*':
                    res = val2 * val;
                    break;

                case '/':
                    res = val2 / val;
                    break;
                }
                
                push( &stack, res );
            }
        }
    }
    
    if ( !isEmpty( &stack ) ) 
    {
        res = peek( &stack );
        pop( &stack );
    }
    
    return res;
}

int main(void) 
{
    const char *exp = "3 4 5 * + 6 7 * 8 + 9 * +";
    
    printf( "postfix result: %d\n", evaluatePostfix( exp ) );
    
    return 0;
}

程序输出是

postfix result: 473

您可以在程序中附加一个代码,该代码将检查所传递字符串的当前符号是否为有效符号。那就是传递的表达式是否正确。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-07
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    • 2016-04-16
    • 1970-01-01
    • 2012-01-05
    相关资源
    最近更新 更多