繁体   English   中英

没看懂 C++ 堆栈<char*>行为</char*>

[英]Did not understand C++ stack<char*> behavior

我被困了两个小时,试图了解这个简单的 C++ 测试程序中发生了什么,但仍然没有得到它。 它应该只接收三个字符串作为输入,将它们插入堆栈,最后打印同一堆栈的所有元素。

#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;

}

奇怪的是,最终的 output 是相同的元素(最后添加的)打印了 3 次,这对我来说毫无意义。

例如,如果输入是:

John
Mary
Rick

那么当前的 output 是

Rick
Rick
Rick

谁能帮我理解和解决这个问题?

    char new_element[200];
    // [...]
    stk.push(new_element);

您在堆栈 object 中推送相同的指针。

更糟糕的是,您正在推送系统堆栈指针,因此如果您要从 function 外部使用堆栈,您会遇到访问冲突(Linux 中的段错误)并崩溃。 在您的情况下,您并没有从外部使用它们,因为堆栈 object 也在堆栈上。

无论如何,有两个快速修复:

  1. 编写正确的代码:使用string并让编译器找出复制它们并根据需要清理它们。

  2. 不要编写正确的代码:使用strdup获取唯一的字符串指针。 您可能希望或不希望在某个时候释放它们,对于选择这条路线的人来说,这似乎总是可选的。

因为您已将stk声明为std::stack<char*> ,所以它的元素将是char* ,或指向char数据的指针(即地址)。

那么,执行stk.push(new_element);时你会做什么行是将您的(本地)字符数组的地址放入堆栈中。 从技术上讲,当您稍后pop该地址并打印它指向的字符串时,您正在执行未定义的行为,因为指向的 memory 已超出 scope (它的“生命周期”只是第一个for循环的一次迭代)。

但是,您的系统只是在每次循环迭代中重复使用相同的地址/缓冲区,因此您的scanf("%s", new_element); 行每次都替换该缓冲区的内容。 然后,当您打印三个堆栈元素的内容时,每一个都将是相同的地址,您只是显示该缓冲区的最后修改版本。

要解决此问题,请为您的“本地”变量使用std::string (然后将通过push调用复制该变量); 或者,如果您坚持使用char* ,则推送使用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
    }

然后,在第二个循环中,完成后不要忘记释放 memory:

    while(!stk.empty()){
        cout << stk.top() << " ";
        free(stk.top()); // Release the allocated memory before we lose the pointer
        stk.pop();
    }

strdup()free()函数在<stdlib.h> header 文件中声明。

您可以使用string而不是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;

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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