简体   繁体   中英

Did not understand C++ stack<char*> behavior

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?

    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:

  1. Write proper code: use string and let the compiler figure out copying them around and cleaning them up as needed.

  2. 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.

Because you have declared stk as a std::stack<char*> , its elements will be char* , or pointers to char data (ie 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.

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;

}

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