从节点获取数据值,指针混淆



因此,由于类之间的循环依赖关系,我的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对象。假设对象包含指向动态分配内存的指针,则需要正确复制它。

正确的副本意味着副本必须与原始对象无法区分。对于您的情况,这意味着源对象的所有成员都需要分配给目标对象。对于两个指针成员(sendBackrest)和一个布尔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;

相关内容

  • 没有找到相关文章

最新更新