[英]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->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有效地分配了一个新缓冲区,将旧缓冲区复制到新缓冲区中,并一举释放了旧缓冲区。 时髦。
然后我们添加新元素并增加存储元素的计数。
最后,我们返回对象的引用,以便它可以在链中使用。
用法可以
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.