0

大学の課題のコンポーネントとして、スタックを実装する必要がありますが、これは機能するのに十分うまくいったと思います。スタック自体をテストしているときは問題なく動作しているように見えますが、ソリューションの一部として使用しているときは動作が異なり、その理由がわかりません。誰かが私の間違いを指摘できますか?ありがとう。

編集:「どのように動作が異なるのですか?」という多くのことを感じることができます。コメントが途中なので、ここに私が気づいたことがあります。のテスト スタックセクションをmain実行すると、すべての操作が実行され、完全に正常に出力されますがmain、代わりに の 2 番目の部分を実行してテスト部分をコメント アウトすると、スタックにプッシュしようとするとプログラムがクラッシュします。以前は失敗していませんでした。

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

2 に答える 2

4

差し迫った問題が少なくとも 1 つあります。

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

スタックの初期化はどこにありますか? 初期化されていないポインターの使用は、即座に「未定義の動作」領域になります。

コードをよく見るとpush、現在のアイテムの前に新しいアイテムが挿入されますが、新しいアイテムのnextPtrポインターは前の (初期化されていない) 値に設定されていることがわかります。

つまり、スタックの最後の項目は実際には NULL を指しません。

于 2012-05-09T03:25:01.243 に答える
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ます。

于 2012-05-09T03:33:31.813 に答える