Reputation: 33
I got stuck for two hours trying to understand what is happening in this simple C++ test program, but still did not get it. It should just receive three strings as inputs, insert them into a stack and finally print all elements of this same stack.
#include <iostream>
#include <stack>
#include <cstring>
using namespace std;
int main(){
stack<char*> stk;
int stringLength;
for (int i=0; i<3; i++){
char new_element[200];
scanf("%s", new_element);
stringLength = strlen(new_element);
stk.push(new_element);
}
cout << "Stack content: ";
while(!stk.empty()){
cout << stk.top() << " ";
stk.pop();
}
cout << endl;
}
The strange thing is that the final output is the same element (the last one added) printed 3 times, which makes no sense to me.
For example, if the inputs are:
John
Mary
Rick
then the current output is
Rick
Rick
Rick
Can anyone help me understanding and fixing this?
Upvotes: 1
Views: 133
Reputation: 1218
You can use string
instead of char*
#include <iostream>
#include <stack>
#include <cstring>
int main(){
stack<string> stk;
int stringLength;
for (int i=0; i<3; i++){
string new_element;
cin>>new_element;
cout<<new_element<<"\n";
stk.push(new_element);
}
cout << "Stack content: ";
while(!stk.empty()){
cout << stk.top() << " ";
stk.pop();
}
cout << endl;
}
Upvotes: 1
Reputation: 67380
char new_element[200];
// [...]
stk.push(new_element);
You're pushing the same pointer in your stack object.
What's worse is, you're pushing system stack pointers, so if you were to use the stack from outside your function, you'd get an access violation (segfault in Linux) and crash. In your case you aren't using them from outside though, since the stack object is also on the stack.
Anyway, there's two quick fixes:
Write proper code: use string
and let the compiler figure out copying them around and cleaning them up as needed.
Don't write proper code: use strdup
to get an unique string pointer. You may or may not want to free them at some point, that always seems optional for people opting for this route.
Upvotes: 5
Reputation: 51825
Because you have declared stk
as a std::stack<char*>
, its elements will be char*
, or pointers to char
data (i.e. addresses).
So, what you do when execute the stk.push(new_element);
line is place the address of your (local) character array onto the stack. Technically, when you then pop
that address later and print the string it points to, you are performing undefined behaviour, as the memory pointed to has gone out of scope (it's 'lifetime' is just one iteration of the first for
loop).
However, your system simply re-uses the same address/buffer on each loop iteration, so your scanf("%s", new_element);
line is replacing the contents of that buffer each time. Then, when you print the contents of the three stack elements, each of which will be the same address, you are simply displaying the last-modified version of that buffer.
To fix this, either use a std::string
for your 'local' variable (which will then be copied by the push
call); or, if you insist on using a char*
, then push the address of a copy of that, made using the strdup()
function:
for (int i=0; i<3; i++){
char new_element[200];
scanf("%s", new_element);
stringLength = strlen(new_element);
stk.push(strdup(new_element)); // Allocate and copy the buffer before pushing
}
Then, in your second loop, don't forget to release the memory when you're done with it:
while(!stk.empty()){
cout << stk.top() << " ";
free(stk.top()); // Release the allocated memory before we lose the pointer
stk.pop();
}
The strdup()
and free()
functions are declared in the <stdlib.h>
header file.
Upvotes: 2