C ++ seg故障在哪里?

时间:2015-10-02 22:21:11

标签: c++ memory-leaks error-handling segmentation-fault

我目前正在为我的计算机科学课程完成这项任务:

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

使用malloc和free。做一个版本。

使用new和delete执行一个版本。

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

        public ActionResult Create([Bind(Include = "PersonRodneCislo, FirstName, LastName, Street, City, PSC, PhoneNumber, SecondaryStreet, SecondaryCity, SecondaryPSC")]Person person,
                               [Bind(Include = "InsuranceNumber,Premium,PaymentFrequency,AnnualDate,BeginDate,EndDate,ProductType,PersonRodneCislo")] Insurance insurance,
                               [Bind(Include = "Ico,Street,City,PSC")] Firm firm)
    {
        try
        {
            ViewBag.ProductType = new SelectList(db.Product, "ProductType", "ProductName");
            // TODO: Add insert logic here
            if (ModelState.IsValid)
            {
                if(String.IsNullOrWhiteSpace(firm.Ico.ToString()) && String.IsNullOrWhiteSpace(person.PersonRodneCislo.ToString()))
                {
                    ModelState.AddModelError("Ico", "Vložte prosím IČO nebo rodné číslo");
                }
                if (!(String.IsNullOrWhiteSpace(firm.Ico.ToString())))
                {
                    insurance.PersonRodneCislo = person.PersonRodneCislo;              
                    if (!(db.Person.Any(x => x.PersonRodneCislo == person.PersonRodneCislo)))
                    {
                        db.Person.Add(person);
                        db.Insurance.Add(insurance);
                    }
                    else
                    {
                        db.Insurance.Add(insurance);
                    }
                }
                if (String.IsNullOrWhiteSpace(person.PersonRodneCislo.ToString()))
                {
                    insurance.Ico = firm.Ico;               
                    if (!(db.Firm.Any(x => x.Ico == firm.Ico)))
                    {
                        db.Firm.Add(firm);
                        db.Insurance.Add(insurance);
                    }
                    else
                    {
                        db.Insurance.Add(insurance);
                    }
                }
                db.SaveChanges();
            }
            return RedirectToAction("Index");
        }
        catch
        {
            return View(insurance);
        }
    }

这给出了一个seg错误;但是,当我把它更改为:

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

return 0;

没有seg错误。这让我相信问题出在我的addData函数中。这是代码:

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

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

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

1 个答案:

答案 0 :(得分:2)

Array2 <T> *tmp;

分配指针。这并不指向任何指针或为指针指向任何存储器指向。未明确指定的内容未定义。如果你很幸运,而你现在就是这个时候,tmp指向一个无效的位置并且程序崩溃了。如果你运气不好,tmp指向程序存储器的某个可用区域并允许你在其上书写,从而破坏那里的任何信息。

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

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

或许我错了,出于同样的原因停止了:

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有效地分配一个新缓冲区,将旧缓冲区复制到新缓冲区中,并一次性释放旧缓冲区。 Groovy的。

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

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

用法可以是

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

如果您有运营商&lt;&lt;支持书面

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

如果我是你,我会回过new版本的数组。这里发现的大多数错误都是概念错误,也适用于它。你可能只是变得不走运,它只是看起来很有效。我刚看了C++ Calling Template Function Error。发布的解决方案解决了当前的问题,但没有触及底层的内存管理问题。

至于你班上的其他人,我建议点击链接并回答What is The Rule of Three?因为Array2违反了它。