繁体   English   中英

C++ seg 错误在哪里?

[英]C++ Where is the seg fault?

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

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

使用 malloc 和 free 做一个版本。

使用 new 和 delete 做一个版本。

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

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

return 0;

这会导致段错误; 但是,当我将其更改为:

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,this->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++ Calling Template Function Error 发布的解决方案解决了眼前的问题,但没有触及底层内存管理问题。

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

暂无
暂无

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

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