0

I am having trouble doing a deep copy of my doubly linked list. This is a homework assignment, so I'd like to know why my code is not working, rather than get working code that I don't understand.

Here is my class:

#include "textAnalyzer.h"
#include <string>
#include <iostream>
#include <sstream>

TextAnalyzer::Node* TextAnalyzer::createNode(const string& word, const int wordFrequency, 
Node* const previous, Node* const next)
{
return new Node(word, wordFrequency, previous, next);
}
void TextAnalyzer::releaseNodes()
{
Node* del = tail;

while(tail != NULL)
{
    tail = tail->previous;
    tail->next = del;
    delete del;
    del = tail;
}

delete [] head;
delete [] tail;

head = tail = del = NULL;
}

void TextAnalyzer::copyNodes(Node* const copyHead)
{
head = new Node(*copyHead);
Node* iter = head->next;

for(Node* np = copyHead->next; np != NULL; np = np->next)
{
    iter->next = new Node(*np);
    iter = iter->next;
}

iter = NULL;
}

TextAnalyzer::TextAnalyzer():head(createNode("0",0,NULL,NULL)),tail(head)
{}

TextAnalyzer::TextAnalyzer(const TextAnalyzer& copyObject)
{
copyNodes(copyObject.head);
}

TextAnalyzer::~TextAnalyzer()
{
releaseNodes();
}

TextAnalyzer TextAnalyzer::operator=(const TextAnalyzer& assignObject)
{
return TextAnalyzer(assignObject);
}

void TextAnalyzer::insertWord(const string& word)
{
Node* iter = head->next;

while(iter != NULL)
{
    if(iter->word == word)
        iter->wordFrequency++;
    else if(iter->word[0] == word[0] && iter->next != NULL)
    {
        Node* temp = iter->next;
        iter->next = createNode(word, 1, iter, temp);
        iter = iter->next;
        temp->previous = iter;

        temp = NULL;
    }
    else if(iter->word[0] == word[0] && iter->next == NULL)
    {
        iter = createNode(word, 1, tail, NULL);
        tail = iter;
    }
    else
        iter = iter->next;
}

iter = NULL;
}

int TextAnalyzer::wordCount() const
{
Node* iter = head->next;
int count = 0;

while(iter != NULL)
    count++;

return count;
}

int TextAnalyzer::wordCountWithInitialCharacter(const char startsWith)
{
Node* iter = head->next;
int count = 0;

for(int i = 0; i < wordCount(); i++)
{
    if(startsWith == iter->word[0])
        count++;

    iter->previous = iter;
    iter = iter->next;
}

iter = NULL;

return count;
}

string TextAnalyzer::toString() const
{
Node* iter = head->next;
string desc = "List of words: \n";
ostringstream convert;

for(int i = 0; i < wordCount(); i++)
{
    convert << iter->word[0] << " words:\n"
            << iter->word    << "(" 
            << iter->wordFrequency
            << ")\n";
    iter->previous = iter;
    iter = iter->next;
}

iter = NULL;

return desc + convert.str();
}

Here is the interface:

#ifndef TEXTANALYZER_H
#define TEXTANALYZER_H

#include <iostream>
#include <string>

using namespace std;

class TextAnalyzer {
private:

/*
 * Class: Node
 *
 * This class represents a node in a sorted doubly linked list that stores a
 * list of words and their frequency of occurrence.
 */
class Node {
public:
    string word;
    int wordFrequency;
    Node* previous;
    Node* next;

    Node(const string& word,
         const int wordFrequency,
         Node* const previous,
         Node* const next)
    : word(word),
      wordFrequency(wordFrequency),
      previous(previous),
      next(next)
    {}
}; // end ListNode
/*********************************************************************/

Node* head;
Node* tail;


/*
 * Releases all the memory allocated to the list.
 */
void releaseNodes();

/*
 * Makes a deep copy of the object.
 */
void copyNodes(Node* const copyHead);

/*
 * Returns a populated Node.
 * Throws a bad_alloc exception if memory is not allocated.
 */
Node* createNode(const string& word,
                 const int wordFrequency,
                 Node* const previous,
                 Node* const next);

public:
/* 
 * Initializes head and tail, each to a dymmy node.
 */
TextAnalyzer();

/*
 * Makes a deep copy of the object passed in.
 * Calls copyNodes() to do the actual work.     
 */
TextAnalyzer(const TextAnalyzer& copyObject);

/* 
 * Releases all the memory allocated to the object.
 * Calls the releaseNodes() method to do the actual work.
 */
~TextAnalyzer();

/* 
 * Makes a deep copy of the rhs object.
 */
TextAnalyzer operator =(const TextAnalyzer& assignObject);

/*
 * Inserts the word in a sorted order into the list. 
 *
 * If no Node exists with that initial character, one is added in
 * sorted order. If one does exist (same word), then the word frequency
 * of that word is incremented by one.
 */
void insertWord(const string& word);

/*
 * Returns a count of all the words in the list.
 */
int wordCount() const;

/* 
 * Returns a count of all the words with the initial character.
 */
int wordCountWithInitialCharacter(const char startsWith);

/*
 * Returns a description of the object. The string is formatted as:
 * [A words:]
 *     [<word>(<count>)]
 *     [<word>(<count>)]
 *     ...
 *
 * [B words:]
 *     [<word>(<count>)]
 *     [<word>(<count>)]
 *     ...
 *
 *...
 */
string toString() const;

};

#endif 

I am required to use the interface given above. My problem is that I get an error in my copy constructor saying "The object has qualifiers that are not compatible" or something similar. I am assuming this is because copyObject is constant. However, I am at a loss as to how to do this otherwise, can someone tell me what I am missing here? I am fairly new to C++, I am more experienced with Java so that could be why I'm being confused.

EDIT:

Thanks for the responses. I think I was about to figure out how to successfully do a deep copy. I've updated my code to show what I have completed so far. Now that I have compiled the code, I've gotten a new error. "unhandled exception 0xc0000005" every time I run it. I googled it and believe it to be an error caused by attempting to dereference a null pointer. The debugger shows it is thrown in my releaseNodes() method.

void TextAnalyzer::releaseNodes()
{
Node* del = tail;

while(tail != NULL)
{
    tail = tail->previous; //error on this line
    tail->next = del;
    delete del;
    del = tail;
 }

delete [] head;
delete [] tail;

head = tail = del = NULL;
}

Above is just my releaseNodes() method, with a comment showing where the debugger says the error originates. Id like to see if the rest of my code works since I am new to C++ and it is very likely my logic is flawed elsewhere as well, unfortunately until this error is resolved I can't test anything. I'm still tracing through my code trying to find what could be causing it. If anyone can point me in the right direction it would be appreciated.

ad absurdum
  • 19,498
  • 5
  • 37
  • 60
borabut
  • 27
  • 3
  • 6
  • OK, never mind! Thats good as pointed out here: http://stackoverflow.com/questions/890535/what-is-the-difference-between-char-const-and-const-char Just never seen this before! – v01pe Feb 14 '13 at 20:46
  • 1
    You are very close to figuring out the problem yourself. It is indeed because of the `copyObject` being const. Are you sure you are calling `copyNodes()` method on the correct instance? – vhallac Feb 14 '13 at 20:51
  • 1
    ... and shouldn't you be passing an argument to `copyNodes`? – Jonathan Wakely Feb 14 '13 at 20:52
  • `delete [] head; delete [] tail;` what are these supposed to mean? –  Feb 14 '13 at 21:19
  • I have updated the code to reflect current changes and to hopefully get help with my new problem. @arrows delete [] head; and delete [] tail; release the memory of the list. I could be wrong in my thinking, perhaps these are only needed when using an array for dynamic allocation? – borabut Feb 15 '13 at 02:36
  • You should abandon this question and open a new one with your new info – Bohemian Feb 15 '13 at 03:02

1 Answers1

0

I'm assuming it's the line where it says

void TextAnalyzer::copyNodes(Node* const copyHead)
{
    head->next = new Node(*copyHead);   
}

You're just assigning the next pointer in head a new Node object. Basically you're only copying one Node, the Node following head, not the entire list. You've got the right idea on what you should do in releaseNodes with the while loop.

Also you're calling it incorrectly in the copy constructor. You gave it a parameter in your definition, but you're calling one that accepts none in the constructor.

Goyatuzo
  • 58
  • 5
  • Not necessarily. There is no copy constructor in the code that I see, but one is perfectly capable of creating a copy of the whole list (perhaps even recursively to keep code short). – vhallac Feb 14 '13 at 20:46
  • I see it, it's the last 3 lines in the cpp file. OP is calling copyNodes(), which I assumed he meant to call copyNodes( Node* const head);. – Goyatuzo Feb 14 '13 at 20:53
  • I meant the copy constructor for `Node` class. It should go something like: initialize the data with the other Node's data, create a new instance of other Node's `next`, and link this new object to `next` (and remember to update it's `previous`). About 4 lines of code to do the deep copy. – vhallac Feb 14 '13 at 21:01