因此,由于类之间的循环依赖关系,我的Node看起来像
struct Node{
Word * data;
Node * next;
};
因此,当创建一个新的Node时(w是Word类型,newptr是类的数据成员)
newptr = new Node;
newptr-> data = &w;
newptr-> next = NULL;
如果我想访问链表的第一个节点中的数据,我认为正确的方法是
Word retVal;
Node *temp;
temp = head->next;
retVal = temp->data;
return retVal;
然而,数据是指向Word类型的指针,它本身不是Word类型。但我想返回一个Word,而不是Word指针。那么我可以添加Word * word;
、word = temp->data;
和retVal = *word;
吗?我的测试程序告诉我一路上所做的事情是错误的,因为当我到达函数时,会出现分段错误。我正在试用这个
Word retVal;
Word * word;
Node *temp;
temp = head->next;
word = temp->data;
retVal = *word;
return retVal;
在不同的地方使用cout线路,我知道我的故障发生在word = temp->data
线路
我的Word课堂成员按要求:
class Word{
public:
char * charArray;
char * sendBack; //ignore
char * rest; //ignore
bool isPigLatin;
bool firstIsVowel;
Word();
Word(const Word& w);
Word(char array[], int size);
~Word();
void show(); //ignore
//ignore everything below
friend ostream& operator<< (ostream& out, const Word& w);
Sentence operator+ (Sentence s);
Sentence operator+ (Word w);
void operator+ (int i);
Word& operator++(int);
Word& operator++();
Word& operator--(int);
Word& operator--();
};
很多事情都与链接列表本身无关,但我包括了所有内容,以防
根据要求复制Word的构造函数:
Word::Word(const Word& w){
cout << "Copy constructor for Word" << endl;
int size = 0;
while(w.charArray[size]){
size++;
}
charArray = new char[size + 1]; //+1 for at end
int i = 0;
while(w.charArray[i]){
charArray[i] = w.charArray[i];
i++;
}
if(!w.isPigLatin){
isPigLatin = false;
}
else{
isPigLatin = true;
}
}
firstIsVowel、sendBack和rest在需要在++和--重载中使用之前不会被声明,因为它们用于将单词转换为Pig拉丁语并返回为英语
我的构造函数:
Word::Word(char array[], int size){
//In my test code I am hard coding a char array and its size, for the actual program I read in the char array from a file, then go thru the char array to get the size before calling Word(char c[], int s)
cout << "Character Array Word constructor" << endl;
int i = 0;
charArray = new char[size];
while(array[i]){
charArray[i] = array[i];
i++;
}
isPigLatin = false;
//this is needed for my Pig Latin function. All words will be read in as English, thus Piglatin = false. If the function to change PigLatin into English is called, nothing will happen since this is false. It gets set to true in the function that changes English to Pig Latin
}
和默认构造函数
Word::Word(){
cout << "Default constructor for Word" << endl;
charArray = new char[1];
sentBack = new char[1];
rest = new char[1];
}
您说过要返回一个Word
对象。假设对象包含指向动态分配内存的指针,则需要正确复制它。
正确的副本意味着副本必须与原始对象无法区分。对于您的情况,这意味着源对象的所有成员都需要分配给目标对象。对于两个指针成员(sendBack
和rest
)和一个布尔firstIsVowel
,您的代码未能做到这一点。
让我们抛出两个指针变量,并假设Word
没有它们。复制构造函数看起来像这样:
Word::Word(const Word& w) : isPigLatin(w.isPigLatin), firstIsVowel(w.firstIsVowel)
{
int size = strlen(w.charArray);
charArray = new char[size + 1];
strcpy(charArray, w.charArray);
}
请注意,我直接从传入的对象中复制了所有成员。没有"商业逻辑",没有到处检查那些bools的值,什么都没有。刚刚复制。这是复制构造函数的工作,也是唯一的工作。
其次,你需要一个赋值运算符。分配操作员的签名如下:
Word& operator = (const Word& w);
换句话说,你需要能够将一个单词分配给另一个单词。可以这样写:
Word& Word::operator=(const Word& w)
{
Word temp(w);
std::swap(isPigLatin, temp.isPigLatin);
std::swap(firstIsVowel, temp.firstIsVowel);
std::swap(charArray, temp.charArray);
return *this;
}
这使用了复制/交换习惯用法,在SO上的许多链接中都有描述。我不会深入讨论,但它确实需要Word
有一个有效的复制构造函数和析构函数来实现它。std::swap
是一个交换这两个值的实用函数。
因此,如果我们删除多余的两个字符指针,这应该会处理Word
的复制。如果它们必须在其中,那么您需要修改上面的代码,以正确分配和复制这两个指针的数据。
看看每一行代码自己在做什么:
首先,在堆上分配一个Node对象,并将其地址值存储在一个名为"temp"的指针变量中
temp = new Node;
其次,您通过覆盖其地址值来泄漏内存,将该地址值替换为"head"指针变量中包含的地址值。
temp = head;
第三,通过将第二个项目的地址存储在链接列表中,您将再次覆盖"temp"中的地址值
temp = temp->next;
事实上,您可以用以下内容替换这3行:
temp = head->next;
这里已经有可能出现错误,因为不能保证head
不是null,所以可以通过检查null来改进代码。
接下来,当您对temp
变量调用delete
时,将释放列表中的第二个节点;为列表中的第一个节点的next
指针留下一个"悬空"(无效)值。
然而,由于你想要的只是第一个节点(假设你想删除第一个节点,而不是第二个),你可能想改为这样做:
Word* retVal = nullptr;
if (head != nullptr)
{
// (1) Remember the address-of the first node for later deletion
Node* temp = head;
// (2) The second node becomes the new head
head = head->next;
// (3) Grab the data from the old head
retVal = temp->data;
// (4) Release the memory for the old head
delete temp;
}
return retVal;