为啥使用动态 ptr 数组检测到分段错误或双重释放?

Posted

技术标签:

【中文标题】为啥使用动态 ptr 数组检测到分段错误或双重释放?【英文标题】:Why am I getting segmentation fault or double free detected with dynamic ptr arrays?为什么使用动态 ptr 数组检测到分段错误或双重释放? 【发布时间】:2021-12-20 11:41:09 【问题描述】:

更新:退休的忍者如果你读过这篇文章,非常感谢!摆脱第二个数组的“Todo”修复了所有问题!我已经尝试解决这个问题 8 小时了,哈哈,我真的无法感谢你!

所以我正在制作一个创建 ToDo 列表的程序,但由于我的第一个数组太小而不断收到分段错误,但在代码中我将其删除并使其变大了。

此外,如果我只是将数组设置为更大的数字来临时修复它,我开始在 tcache 2 错误中检测到双重释放。

任何解决方案或建议将不胜感激! 注意:我更喜欢使用向量,但是对于这个赋值,需要一个动态数组。

这是我的代码:

#include <iostream>
#include <sstream>
#include <limits>
#include <ctime>
#include <cstring>

using namespace std;

class Date

    public:
    
    Date()
    
        time_t currentdate = time(0);
        tm* date = localtime(&currentdate);
        cout << "Today's date: " << 1 + date->tm_mon << "/" << date->tm_mday << "/" << 1900 + date->tm_year << endl << endl; // For some reason my system month was only 10 so I had to add 1
    
;

class Todo

    public: 
        string todoItem, addDate;
        int itemID;
        
        
        
    void setData(string input, int arraysize)
    
        input.erase(0,1);
        todoItem=input;
        itemID=arraysize;
        stringstream buffer;
        time_t currentdate = time(0);
        tm* date = localtime(&currentdate);
        buffer << "Date added: " << 1 + date->tm_mon << "/" << date->tm_mday << "/" << 1900 + date->tm_year << endl << endl;    
        addDate = buffer.str();
    
    
    void getData()
    
        cout <<"GetData:\n";
        cout << itemID << "/" << todoItem << "/" << addDate << endl;
    
;

void ProgramGreeting();
char MenuChoice(string todoItem);

int main()

    ProgramGreeting();
    bool menuloop=true;
    bool firstrun=true;

    
    string input;
    int arraysize=1;
    int arrayindex=arraysize-1;
    
    // in the array below I can put an arbitrary number so it wont get the segmentation fault but then I get the double free error instead
    Todo *todoptr = new Todo[arraysize]; 
    
    do
        getline(cin,input);
        switch (MenuChoice(input))
        
            case '+':
            
                cout << "plus loop\n"; //program runs this last line of code then crashes with double free error
                if (firstrun==false)
                
                    
                    arrayindex=arraysize-1;
                    Todo *tempptr = new Todo[arraysize];
                    for (int i = 0; i < arrayindex; i++)
                    
                        tempptr[i]=todoptr[i];
                    
                    //tempptr++;
                    tempptr[arrayindex].setData(input, arraysize);
                    //tempptr--;
                    delete[] todoptr;
                    Todo *todoptr = new Todo[arraysize+1];
                    for (int i = 0; i < arraysize; i++)
                    
                        todoptr[i]=tempptr[i];
                    
                    for (int i = 0; i < arraysize; i++)
                    
                        todoptr[i].getData();
                    
                    
                
                if (firstrun==true)
                
                    todoptr->setData(input, arraysize);
                    firstrun=false;
                
                arraysize++;
                break;
            case '-':
            
                break;
            case '?':
                break;
            default:
                cout << "Invalid entry. If you would like to quit, enter 'Q'";
                string quit;
                cin >> quit;
                if (quit=="q" or quit=="Q")
                    
                        menuloop=false;
                    
                break;
        
     while(menuloop==true);


void ProgramGreeting()

    cout << "Hello and welcome to my to do list maker!\n"
            "Program Author: John Doe\n";
            Date date;
            cout << endl;
            


char MenuChoice(string input)

    int n=input.length();
    char charray[n+1];
    strcpy(charray, input.c_str());
    return charray[0];

【问题讨论】:

这个 sn-p 不会编译。请发minimal reproducible example 顺便说一句,为什么不使用std::vector&lt;Todo&gt; 而不是使用new 手动进行动态分配? 这会删除在循环外声明的指针:delete[] todoptr; 这会声明一个同名的新变量,它会遮蔽外部:Todo *todoptr = new Todo[arraysize+1]; 循环中该行之前的所有内容都指向外部 @ 987654327@ 以及该行之后到循环末尾的所有内容都指的是新变量。您很可能只想在循环中使用todoptr = new Todo[arraysize+1];,否则第二次迭代会尝试第二次删除相同的指针。 请注意,代码不是标准的 C++。 char charray[n + 1]; 是一个可变长度数组。不要使用它们。请改用std::stringstd::vector&lt;char&gt; MenuChoice 函数完全没有必要。 switch (input[0]) 是一回事。在这两种情况下都应该首先检查!input.empty() 【参考方案1】:

有许多错误导致它崩溃。 例如:

变量阴影:有两个“Todo *todoptr”,这就是为什么会发生双重释放。 "outer todoptr" 在输入第三个 '+' 时没有有效指针。

for 循环中的赋值可能超出范围

【讨论】:

以上是关于为啥使用动态 ptr 数组检测到分段错误或双重释放?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 realloc() 时会出现双重释放或损坏错误?

动态二维数组。为啥是分段错误?

检测到 glibc - 在 C 程序中释放(int ** 类型)时出现双重释放或损坏消息

为啥这个程序在调用函数时会出现分段错误?

为啥释放内存会导致分段错误?

用指向数组的指针替换衰减的数组导致分段错误