C++ 赛格故障在哪里

C++ Where is the seg fault?

本文关键字:在哪里 故障 C++      更新时间:2023-10-16

我目前正在为我的计算机科学课处理这项作业:

创建您自己的动态数组模板。它应该允许创建连续的数组(填充相同类型的东西(,您可以扩展这些数组而不必担心空间不足。

使用 malloc 做一个版本并免费。

使用新的和删除执行一个版本。

我使用new和delete的版本完美无缺;但是,在尝试将我的new/delete代码转换为使用malloc/free时,我不断遇到seg错误。我已经将段错误(我认为(缩小到一个函数:addData。看看我用来测试这个的主要代码:

Array2<int> *testArray3 = new Array2<int>(5);
Array2<int> *testArray4;
testArray3->initArray();
testArray3->printArray();
testArray4 = testArray3->addData(7);
testArray4->printArray();
return 0;

这给出了一个 seg 错误;但是,当我将其更改为以下错误时:

Array2<int> *testArray3 = new Array2<int>(5);
Array2<int> *testArray4;
testArray3->initArray();
testArray3->printArray();
testArray4 = testArray3; //->addData(7);
testArray4->printArray();
return 0;

没有赛格故障。这让我相信问题出在我的addData函数中。这是代码:

Array2<T> *addData(T dataToAdd){
    Array2 <T> *tmp;
    tmp->data = this->getData();
    Array2 <T> *newData;
    newData->data = (T *) malloc(sizeof(T)*(this->size + 1));
    for (int i = 0; i < tmp->getSize() + 1; ++i){
        if (i < tmp->getSize()){
            //newData->data[i] = tmp->data[i];
            newData->setData(tmp->getData()[i], i);
        }
        else{
            //newData->data[i] = dataToAdd;
            newData->setData(dataToAdd, i);
        }
    }
    free(tmp->data);
    free(this->data);
    return newData;
};

我是整个编程的新手,还没有完全了解指针和内存分配等。您能给我的任何建议将不胜感激!如果您需要查看其余代码,这是我编写模板的整个文件。非常感谢您的时间!

#include <iostream>
#include <string>
#include <cstdlib>
#include <sstream>
using namespace std;
template<typename T>
class Array2{
public:
    Array2(int size){
        this->size = size;
        data = (T *) malloc(sizeof(T)*size);
    };
    Array2<T> *addData(T dataToAdd){
        Array2 <T> *tmp;
        tmp->data = this->getData();
        Array2 <T> *newData;
        newData->data = (T *) malloc(sizeof(T)*(this->size + 1));
        for (int i = 0; i < tmp->getSize() + 1; ++i){
            if (i < tmp->getSize()){
                //newData->data[i] = tmp->data[i];
                newData->setData(tmp->getData()[i], i);
            }
            else{
                //newData->data[i] = dataToAdd;
                newData->setData(dataToAdd, i);
            }
        }
        free(tmp->data);
        free(this->data);
        return newData;
   };
    ~Array2(){
        free(this->data);  
    };
    void initArray(){
        for (int i = 0; i < this->size; ++i){
            //this->data[i] = i;
            this->setData(i, i);
        }
    };
    void printArray(){
        //ostringstream oss;
        string answer = "";
        for (int i = 0; i < this->size; ++i){
            //oss << this->data[i] + " ";
            cout << this->data[i] << " ";
        }
        //answer = oss.str();
        cout << answer << endl;
    };
    T* getData(){
        return this->data;
    }
    int getSize(){
        return this->size;
    }
    void setData(T data, int index){
        this->getData()[index] = data;
    }
private:
    int size;
    T* data;
};
Array2 <T> *tmp;

分配指针。这不会将指针指向任何内容,也不会为指针分配任何存储空间。它所指向的没有明确分配的内容是未定义的。如果你很幸运,而你这次是,tmp 指向一个无效的位置,程序崩溃。如果你运气不好,tmp 指向程序内存的某个可用区域,让你覆盖它,破坏那里的任何信息。

tmp->data = this->getData();

尝试在 tmp 上访问数据成员,但幸运的是,访问在无效内存中,程序停止。它也有tmp的数据指向这个数据,这是一个危险的位置。对一个的更改将发生在另一个,因为它们都使用相同的存储。还要考虑一下,如果您释放 tmp->data,这些数据会发生什么>数据。

或者也许我错了,出于同样的原因,停止在这里:

Array2 <T> *newData;
newData->data = (T *) malloc(sizeof(T)*(this->size + 1));

两者都需要修复.tmp不必存活很长时间,因此我们可以将其设置为临时局部变量。

Array2 <T> tmp;

通常,这将在堆栈上创建,并在函数结束且 tmp 超出范围时销毁。

但这行不通,因为 Array2 的构造函数需要一个大小,以便它可以分配数组的存储。你需要找出它有多大。可能是这样:

Array2 <T> tmp(this->size + 1);

但坦率地说,我认为你根本不需要 tmp。您应该能够将 dataToAdd 直接复制到 newData 中,而无需使用 tmp 作为中介。

newData 最终将返回给调用方,因此它需要更长的范围。是时候使用new了。

Array2 <T> *newData = new Array2 <T>(this->size + 1);

并通过构造函数的魔力...等一下。不能使用new。这就很难了。 malloc 不调用构造函数,因此虽然malloc将为 newData 分配资源,但它不会完成正确设置 newData 的繁琐工作。经验法则是永远不要malloc对象。我敢肯定会有例外,但不应该要求你这样做。我建议在这里使用new,并礼貌地告诉教练,如果他们抱怨,他们正在破解。

无论如何,new Array2 <T>(this->size + 1)将使用构造函数为您分配data存储。

接下来有更简单的方法可以做到这一点

for (int i = 0; i < tmp->getSize() + 1; ++i){
    if (i < tmp->getSize()){
        //newData->data[i] = tmp->data[i];
        newData->setData(tmp->getData()[i], i);
    }
    else{
        //newData->data[i] = dataToAdd;
        newData->setData(dataToAdd, i);
    }
}

尝试:

for (int i = 0; i < tmp->size; ++i){
    newData->data[i] = tmp->data[i]; // you were right here
}
newData->data[tmp->size] = dataToAdd;

回到我之前暗示的内容:

free(tmp->data);
free(this->data);

tmp->datathis->data都指向同一内存。老实说,我不确定如果您两次释放相同的内存会发生什么,但我怀疑这是否好。无论如何,我认为你不想释放它。这将使this处于破碎状态。

回顾和修复

Array2<T> *addData(T dataToAdd)
{
    Array2 <T> *newData = new Array2 <T>(this->size + 1);
    for (int i = 0; i < this->size; ++i)
    {
        newData->data[i] = this->data[i];
    }
    newData->data[this->size] = dataToAdd;
    return newData;
};

此版本保持不变,并返回一个比这更大的 newData。它没有做的是添加任何东西。对于名为addData的方法来说,这是愚蠢的。

这也导致了这样的事情:

mydata = myData->addData(data);

这会泄漏内存。原始 mydata 丢失而不删除,导致内存泄漏。

我认为你真正需要的要简单得多:

Array2<T> & addData(T dataToAdd)
{
    this->data = realloc(this->data, this->size + 1);
    this->data[this->size] = dataToAdd;
    this->size++;
    return *this;
};

RealLoc 有效地分配了新缓冲区,将旧缓冲区复制到新缓冲区中,并一举释放旧缓冲区。槽的。

然后,我们添加新元素并增加存储的元素计数。

最后,我们返回对对象的引用,以便可以在链中使用。

用法可以是

myData.addData(data);
myData.addData(data).addData(moredata);
myData.addData(data).printArray();

如果您有操作员<<支持

书面
std::cout << myData.addData(data) << std::endl;

如果我是你,我会回到new版本的 Array。这里选择的大多数错误都是概念错误,也适用于它。你可能只是运气不好,它只是看起来有效。我刚刚阅读了C++调用模板函数错误。发布的解决方案解决了眼前的问题,但没有触及潜在的内存管理问题。

至于你班上的其他同学,我建议点击链接并回答什么是三法则?因为 Array2 违反了它。