我目前正在为我的计算机科学课程完成这项任务:
制作自己的动态阵列模板。它应该允许创建连续的数组(填充相同类型的东西),你可以扩展,而不必担心空间不足。
使用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;
};
答案 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->data
和this->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违反了它。