Reputation: 77
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?
Upvotes: 0
Views: 1541
Reputation: 33932
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;
}
Upvotes: 0
Reputation: 5163
Here how you make reference of pointer:
void push(stack*&, stack*&, int);
void pop(stack*&, stack*&);
Upvotes: 0
Reputation: 9340
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.
Upvotes: 1