简体   繁体   中英

Stack with push and pop functions not working

This is the program.

#include<iostream>
#include<string>

using namespace std;

struct stack
{
    int inf;
    stack* link;
} *start, *p;

void push(stack*, stack*, int);
void pop(stack*, stack*);

int main()
{
    int s = 0;
    string thing;

    cin >> thing;
    while (thing != "end")
    {
        if (thing == "push")
        {
            push(start, p, s);
        }
        if (thing == "pop")
        {
            pop(start, p);
        }
        cin >> thing;
    }
    return 0;

}

void push(stack *start, stack *p, int s)
{

        cin >> s;

        p = start;
        start = new stack;
        start->inf = s;
        start->link = p;

        cout << "pushed " << start->inf << endl;
}

void pop(stack *start, stack *p)
{


    cout << "popped " << start->inf;
    p = start;
    start = start->link;
    delete p;


}

It's a simple program to allow me to push and pop items to and from a stack, but for some reason the pop() just won't work. If I add an if(start) before the pop it just skips it, making me think that the stack somehow becomes NULL after push is completed. Basically everything works until it reaches the cout << "popped " << start->inf; line, when it just crashes (no error message) which again makes me think the stack becomes null before it reaches pop() . Any suggestions?

First, both of your function's signature are weird:

void push(stack *start, stack *p, int s)
void pop(stack *start, stack *p)

Assuming start points to top of stack, you should discard p . It should be a local variable to the function, not a parameter.

Second, let's see push implementation:

p = start;
start = new stack;
start->inf = s;
start->link = p;

this one looks ALMOST good. What you missed is that start is declared as a pointer to stack, and you are changing the pointer inside the function, which is a value parameter instead of a reference. With your current signature, you can change what start POINTS TO, but not start itself. You can either declare it as pointer to pointer to stack, and change the body accordingly (you need double dereference for assigning inf and link ) or use reference parameter by adding & before the parameter name. The same case applies to your pop function.

Here how you make reference of pointer:

void push(stack*&, stack*&, int);
void pop(stack*&, stack*&);

The previous answers are correct, but they aren't really explaining why.

The start and p used here

void push(stack *start, stack *p, int s)

Are not the same as those defined here.

struct stack
{
    int inf;
    stack* link;
} *start, *p;

push has a whole new start and p which may be copies of the other start and p, but they are not the same. Push could be defined

void push(stack *hamburger, stack *cheeseburger, int s)

with corresponding changes to the variables used inside the functions and you would see no difference in the behaviour of the function.

What you would get in the burger version of push is the ability to see the original start and p . Because allowing two variables with the same name at the same time would lead to total confusion (seriously, which one gets used?) the inner-most definition hides all outer definitions. So not only is push 's start not the globally defined start , but push 's start is blocking access to global start .

However, if you define and don't change the contents

void push(stack *hamburger, stack *cheeseburger, int s)
{
    cin >> s;

    p = start;
    start = new stack;
    start->inf = s;
    start->link = p;

    cout << "pushed " << start->inf << endl;
}

hamburger and cheeseburger aren't used for anything and push uses the global start and p

Now think about what happens if someone modifies your code and leaves out p by mistake.

void push(stack *start, int s)

p is still a valid variable, the code still happily compiles, and it uses the wrong p .

Consider carefully before reusing variable names. I like to tag global variables so I can see when they are being used and so they are less likely to collide with locals. For me, start would be gStart. It looks odd enough to stand out and unlikely to be used by accident.

OP's code's not bad. Needed a test for valid integer input and for popping of empty stack

#include<iostream>
#include<string>

using namespace std;

struct stack
{
    int inf;
    stack* link;
} *gStart; // don't need p at all start renamed to avoid collisions

void push(stack * & start)
{
    stack *p; //just holds a temporary no need to pass
    int s; // same as above

    while (!(cin >> s)) // read and test the input        
    { // bad input. Clear stream and prompt
        cin.clear(); 
        cout << "nice try, wiseguy. Gimmie an int!" << endl;
    }

    p = new stack();
    p->inf = s;
    p->link = start;
    start = p;

    cout << "pushed " << start->inf << endl;
}

void pop(stack *& start)
{
    stack *p; //no need to pass in
    if (start != NULL)
    { // don't pop list if list empty
        cout << "popped " << start->inf << endl;
        p = start;
        start = p->link;
        delete p;
    }
    else
    {
        cout << "stack empty" << endl;
    }
}

int main()
{
    // there is no need for start to be global. It could just as easily be allocated here.
    string thing;

    cin >> thing;
    while (thing != "end")
    {
        if (thing == "push")
        {
            push(gStart);
        }
        else if (thing == "pop")
        {
            pop(gStart);
        }

        cin >> thing;
    }
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM