C中的堆栈实现会产生令人困惑的结果

时间:2012-05-09 03:17:56

标签: c

对于大学作业的一个组成部分,我们必须实现一个堆栈,我认为我已经做得很好,可以实现它的功能。当我自己测试堆栈时,它似乎工作正常,但是当我使用它作为我的解决方案的一部分时,它表现不同,我无法弄清楚为什么。有人可以指出我的错误吗?感谢。

编辑:我可以感受到很多“它的表现如何?”评论即将发布,所以这就是我注意到的。运行main测试堆栈部分时,所有操作都执行并打印完全正常,但是当我运行main的第二部分并注释掉测试部分时相反,当我试图推入堆栈时程序崩溃 - 这是以前没有失败的事情。

的main.c

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

struct stackNode {
    char data;
    struct stackNode *nextPtr;
};
typedef struct stackNode StackNode;
typedef StackNode *StackNodePtr;

typedef enum {
    false, true
} t_bool;

void* emalloc(size_t s) {
    void* p = malloc(s);
    if (NULL == p) {
        fprintf(stderr, "Memory allocation failed.\n");
        exit(EXIT_FAILURE);
    }
    return p;
}

void print_array(char* array, size_t n){
    int i;
    printf("[");
    for(i = 0; i < n - 1; i++){
        printf("%c, ", array[i]);
    }
    printf("%c]\n", array[i]);
}


// Determine if c is an operator.
int isOperator(char c) {
    char ops [6] = {'+', '-', '*', '/', '%', '^'};
    int i;
    for (i = 0; i < 6; i++)
        if (ops[i] == c) return true;
    return false;
}

int op_priority(char c) {
    if (c == '+' || c == '-') return 0;
    else if (c == '*' || c == '/') return 1;
    else if (c == '^' || c == '%') return 2;
    return -1;
}


// Determine if the precedence of operator1 is less than, equal to, or greater than
// the precedence of operator2. The function returns -1, 0 and 1, respectively.
int precedence(char op1, char op2) {
    int op1_p = op_priority(op1);
    int op2_p = op_priority(op2);
    if (op1_p < op2_p) return -1;
    else if (op1_p > op2_p) return 1;
    else return 0;
}





// Push a value on the stack.
void push(StackNodePtr *topPtr, char value) { 
    StackNodePtr temp = (StackNodePtr) emalloc(sizeof (StackNode));
    temp->data = value;
    temp->nextPtr = *topPtr;
    *topPtr = temp;
}

// Pop a value off the stack. 
char pop(StackNodePtr *topPtr) {
    StackNodePtr t = *topPtr;
    if (NULL != *topPtr) {
        char c = t->data;
        *topPtr = t->nextPtr;
        free(t);
        return c;
    } else {
        printf("Stack is empty.\n");
        return '\0';
    }
}

// Return the top value of the stack without popping the stack.
char peek(StackNodePtr topPtr) {
    if (NULL != topPtr) {
        return topPtr->data;
    } else {
        printf("Stack is empty.\n");
    }
}

// Determine if the stack is empty.
int isEmpty(StackNodePtr topPtr) {
    if (NULL == topPtr) return true;
    return false;
}

// Prints the stack
void printStack(StackNodePtr topPtr) {
    if (!isEmpty(topPtr)){

    StackNodePtr t = topPtr;
    while (NULL != t) {
        printf("%c\t", t->data);
        t = t->nextPtr;
    }
    printf("NULL\n");
    } else {
       printf("Stack is empty.\n");
    }
}

// Convert the infix expression to postfix notation.
void convertToPostfix(char infix [], char postfix [], int expression_length) {
    printf("At top of cnvToPostfix\n");
    int infix_count = 0;
    int postfix_count = 0;

    ////////////////////////////////////////////
    StackNodePtr *stack;
    push(stack, '(');
    printStack(*stack);
    ////////////////////////////////////////////

    infix[expression_length] = ')';
    while (isEmpty(*stack)) {
        char current = infix[infix_count++];
        if (isdigit(current)) {
            postfix[postfix_count++] = current;
        } else if (current == '(') {
            push(stack, current);
        } else if (isOperator(current)) {
            while (true) {
                char top = peek(*stack);
                if (isOperator(top) && precedence(current, top) >= 0) {
                  postfix[postfix_count++] = pop(stack);
                } else {
                    break;
                }
            }
            push(stack, current);
        }
        else if (current == ')') {
            while (true) {
                char top = peek(*stack);
                if (top == '(') {
                    pop(stack);
                    break;
                } else {
                     postfix[postfix_count++] = pop(stack);
                }
            }
        }
    }
}


int main() {

    printf("Testing stack\n");
    printf("Pushing 1, 2, and 3 onto stack, peeking and popping.\n");
    StackNodePtr *stack;
    push(stack, '1');
    push(stack, '2');
    push(stack, '3');
    printf("Printing stack\n\n");
    printStack(*stack);
    printf("Peek: %c\n", peek(*stack));
    printf("Pop: %c\n", pop(stack));
    printf("Printing stack\n");
    printStack(*stack);


/*
    printf("Enter the infix expression.\n");

    char c;
    char infix [1024];
    int count = 0;
    while ((scanf("%c", &c)) == 1) {
        if ((int) c == 10) break;
        infix[count++] = c;
    }

    printf("The original infix expression is:\n");
    print_array(infix, count);


    char postfix [count];

    convertToPostfix(infix, postfix, count);
    printf("The expression in postfix notation is:\n");
    print_array(postfix, count);
*/
     return 0;
}

2 个答案:

答案 0 :(得分:4)

我至少看到一个问题:

StackNodePtr *stack;
push(stack, '1');

您的筹码的初始化在哪里?使用未初始化的指针是即时“未定义的行为”区域。

如果仔细查看push代码,您会看到它在当前代码之前插入新项目,但将新项目的nextPtr指针设置为前一个(未初始化)值。

这意味着,堆栈中的最后一项实际上不会指向NULL。

答案 1 :(得分:2)

你并没有真正初始化你的筹码:

StackNodePtr *stack;
push(stack, '(');

StackNodePtr作为指针类型并且stack是指向该类型的指针也可能令人困惑。您需要在每种可能的用法中清楚应该应用多少级别的间接。

首先,想象一下首先将新堆栈传递给isEmpty

StackNodePtr *stack;
printf("%d\n", isEmptypush(*stack));

isEmpty对传递的价值做了什么?

我认为你想要的是:

StackNodePtr stack = NULL;
push(&stack, '(');

该功能中stack的其他用途应同样从*stack更改为stack,或stack更改为&stack