2014-10-23 2 views
0

Так из-за круговую зависимость между моими классами моего узел выглядит какполучает значение данных от узла, указатель путаница

struct Node{ 
    Word * data; 
    Node * next; 
}; 

Так, при создании нового узла я делаю (ш быть типом 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 линии

Моих членов класса слов по запросу:

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, а остальные не объявлены, пока они не должны быть использованы в ++ и - перегруженные, поскольку они предназначены для создания слова на латынь Свиньи и обратно на английский

мой конструктор :

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

} 
+0

Почему вы назначаете новый Узел, когда мгновенно отправляете точку «temp» в голову? – Creris

+0

Это хороший момент. Нет причин для этого. Я пытался сделать шаг за шагом, нет причин для этого, если я просто установлю его на 'head'. Это не устраняет мою ошибку сегментации, но –

+0

@TommyK - 'Если я хочу получить доступ к данным в первом узле связанного списка,' доступ к данным не должен включать никакого динамического распределения вообще. Просто дойдите до нужного узла и верните данные. – PaulMcKenzie

ответ

1

Вы заявили, что хотите вернуть объект Word. Учитывая, что объект содержит указатели на динамически распределенную память, его необходимо скопировать правильно.

Правильная копия означает, что копия должна быть неотличима от исходного объекта. Для вашей ситуации это означает, что все члены от исходного объекта должны быть назначены целевому объекту. Ваш код не смог сделать это для двух указателей (sendBack и rest) и для одного 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); 
} 

Обратите внимание, что я скопировал все элементы непосредственно из переданного объекта. Нет «бизнес-логики», не обманывать, проверяя, какие значения для этих bools, ничего. Просто скопирован. Это работа и только работа конструктора копирования.

Во-вторых, вам нужен оператор присваивания. Подпись для оператора присваивания выглядит следующим образом:

Word& operator = (const Word& w); 

Другими словами, вы должны уметь назначать 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 - это служебная функция, которая меняет местами два значения.

Так что это должно позаботиться о копировании Word, если мы удалим посторонние указатели на два символа. Если они должны быть там, вам необходимо внести изменения в код выше, чтобы правильно распределить и скопировать данные для этих двух указателей.

+0

что означает эта строка «Word :: Word (const Word & w): isPigLatin (w.isPigLatin), firstIsVowel (w.firstIsVowel)'? Я никогда не видел этого раньше. Я предполагаю, что это копирование, но как вам разрешено это делать? –

+1

Этот синтаксис заключается в том, как вы инициализируете участников. Это список инициализации членов. – PaulMcKenzie

1

Посмотрите на то, что каждая строка кода делает сам по себе:

Во-первых, выделяют объект Node в куче и хранить его адрес-значение в указатель переменной под названием «Темп»

temp = new Node; 

Во-вторых, вы протечки, что память, переписав его адрес-значение , заменив это значение адреса на значение, указанное в указателе-переменной «head».

temp = head; 

В-третьих, вы перезаписать адрес-значение «Темп» снова путем сохранения адреса-второго элемента в связанном списке

temp = temp->next; 

В самом деле, вы могли бы заменить тех, 3 строки со следующим:

temp = head->next; 

Уже, у вас есть потенциал для ошибки здесь, потому что нет никакой гарантии, что head не равно нулю, так что вы можете улучшить код чеком с его нулевым значением.

Далее, когда вы вызываете delete в переменной temp, второй узел в вашем списке освобождается; оставив первый узел в вашем списке с «зависающим» (недопустимым) значением для его указателя 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; 
+0

Я думаю, вы имеете в виду 'temp = head-> next' в своем последнем коде. Я обновил свой код, но когда я его запускаю, я все еще получаю ошибку сегментации. Используя операторы печати, я знаю, что это происходит на строке 'word = temp-> data'. Я думаю, что это связано с тем, что я должен объявлять данные как указатель –

+0

@TommyK Нет, я не имел в виду это вообще - это приведет к удалению второго узла в вашем списке и оставьте «свисающим», указатель (что является вероятной причиной для Segfault). Строка 'head = head-> next' гарантирует, что первый узел будет безопасно удален из вашего списка перед его удалением. –

+0

сейчас я вижу. Тем не менее, я не пытаюсь вернуть указатель Word, мне нужно вернуть Word. –

Смежные вопросы