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

时间:2014-10-23 20:36:59

标签: c++ pointers linked-list nodes

因为我的类之间存在循环依赖关系,我的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 \0 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在它们需要用于++和 - 重载之前不会被声明,因为它们用于生成猪拉丁文并回到英语中

我的构造函数:

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

}

2 个答案:

答案 0 :(得分:1)

看看每行代码本身在做什么:

首先,您要在堆上分配一个Node对象,并将其地址值存储在名为&#39; temp&#39;

的指针变量中
temp = new Node;

其次,您通过覆盖其地址值来泄漏该内存,将该地址值替换为&#39; head&#39;中包含的地址值。指针变量。

temp = head;

第三,您在“临时”中覆盖了地址值。再次通过存储链表中第二项的地址

temp = temp->next;

事实上,您可以用以下内容替换这3行:

temp = head->next;

您已经有可能在此处出现错误,因为无法保证head不为空,因此您可以通过针对null检查代码来改进代码。

接下来,当您在delete变量上调用temp时,列表中的第二个节点将被释放;将第一个节点留在列表中,其中包含&#34;悬空&#34;其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;

答案 1 :(得分:1)

您声明要返回Word个对象。假定对象包含指向动态分配内存的指针,则需要正确复制它。

正确的副本意味着副本必须与原始对象无法区分。对于您的情况,这意味着需要将源对象中的 all 成员分配给目标对象。您的代码无法为两个指针成员(sendBackrest)以及一个bool 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);
}

请注意,我直接从传入的对象复制了所有成员。没有“商业逻辑”,也没有愚弄这些bool的价值,没什么。刚复制过。这是复制构造函数的工作和唯一工作。

其次,您需要一个赋值运算符。赋值运算符的签名如下:

Word& operator = (const Word& w);

换句话说,您需要能够将Word分配给另一个Word。这可以这样写:

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是一个实用函数,可以交换这两个值。

所以如果我们删除无关的两个char指针,这应该照顾Word的复制。如果它们必须在那里,那么你需要修改上面的代码来正确地分配和复制这两个指针的数据。