views:

158

answers:

5

I am trying to do a homework assignment where we insert a string into a string at a specified point using a linked stack, hence the struct and typedef. Anyway, when I try to access stringLength in the StringModifier class inside the InsertAfter method, I get a run time error and I cannot figure out what the problem is. I should be able to access and modify the variable because it's protected and the derived class is inherited publicly.

struct StringRec
{
    char theCh;
    StringRec* nextCh;
};

typedef StringRec* StringPointer;

class String
{
    public:
     String();
     ~String();
     void SetString();
     void OutputString();
     int GetLength() const;
    protected:
     StringPointer head;
     int stringLength;
};

class StringModifier : public String
{
    public:
     StringModifier();
     ~StringModifier();
     void InsertAfter( StringModifier& subString, int insertAt );
};

void StringModifier::InsertAfter( StringModifier& subString, int insertAt )
{
// RUN TIME ERROR HERE
    stringLength += subString.stringLength;
}

in MAIN

StringModifier test;
StringModifier test2;

cout << "First string" << endl;
test.SetString();
test.OutputString();
cout << endl << test.GetLength();
cout << endl << "Second string" << endl;
test2.SetString();
test2.OutputString();
cout << endl << test2.GetLength();
cout << endl << "Add Second to First" << endl;
test.InsertAfter( test2, 2 );
test.OutputString();
cout << endl << test.GetLength();

//String Class

String::String()
{
    head = NULL;
    stringLength = 0;
}

String::~String()
{
// Add this later
}

void String::SetString()
{
    StringPointer p;
    char tempCh;

    int i = 0;
    cout << "Enter a string: ";
    cin.get( tempCh );
// Gets input and sets it to a stack
    while( tempCh != '\n' )
    {
     i++;
     p = new StringRec;
     p->theCh = tempCh;
     p->nextCh = head;
     head = p;
     cin.get( tempCh );
    }

    stringLength = i;
}

void String::OutputString()
{
    int i = stringLength;
    int chCounter;
    StringPointer temp;
// Outputs the string bottom to top, instead of top to bottom so it makes sense when read
    while( head != NULL && i > 0 )
    {
     temp = head;
     chCounter = 0;
     while( temp != NULL && chCounter < (i-1) )
     {
      temp = temp->nextCh;
      chCounter++;
     }
     cout << temp->theCh;
     i--;
    }
}

int String::GetLength() const
{
    return stringLength;
}

The StringModifier class has empty constructors and destructors.

+2  A: 

Just a hint: Runtime errors in C++ are completely unrelated to public/protected/private access. The compiler, when compiling your code, has already checked that all the class member access rules are followed.

A runtime error means that you've got a bug in your program, most probably memory corruption of some kind.

Greg Hewgill
When I run it, the program always stops working when I attempt to change stringLength from the method. If I do not try to modify it, it runs fine.
Nickolas
Change the access from `protected` to `public` and re-run your program. Ooops--the program still crashes! How come?
Pavel Shved
Yes, but it's not the `protected` access that is the problem. You have a bug in your code somewhere, and without being able to see the rest of your code it would be impossible for us to guess where.
Greg Hewgill
I figured it wasn't a member access specifier that was the problem but I had nothing else in mind. haha. I can't figure out which way to go to fix it though.
Nickolas
Two suggestions: (1) When in doubt, print more out. (2) Take this opportunity to learn about what the debugger in your development environment can do for you.
Greg Hewgill
Yeah I am gonna have to do more printing definitely. I do need to use the debugger more than I do though. Thanks for all the help at 1:30AM Pacific. :)
Nickolas
A: 

Are you sure your runtime error actually happens in the InsertAfter function? It looks to me like when you modify the stringLength you should get an access violation in OutputString because you haven't actually added the characters yet. Adding the (temp != NULL) clause to your while loop almost avoids this - but look at what happens if you actually leave the loop because of temp becoming NULL...

Responding to your comments: I'm afraid I'm still a bit skeptical about where this runtime error is happening! If the code really is as given in the question, and assuming you've not got a messed-up build, having an AV or something in InsertAfter would be nigh-on impossible (OK, that's a dangerous thing to say in C++, but hey - you're just changing the value of a member of an object that is allocated on the stack). Note that you can't tell that the error is occurring in the InsertAfter method just because it goes away if you don't call it - indeed the bug in OutputString is only exposed by the call to InsertAfter, so it should disappear if the InsertAfter call is removed. To check, either use a debugger, or add some logging to InsertAfter, both before and after the suspect statement.

Mike Dinsdale
Yes I am sure it happens in the InsertAfter method. I can use every other method from String class. When I try to access stringLength and modify it from the StringModifier derived class, it causes a run time error.
Nickolas
A: 

Are you sure about run time error location? How did you checked that? I see one place which is very suspicious:

while( temp != NULL && chCounter < (i-1) )
{
        temp = temp->nextCh;
        chCounter++;
}
cout << temp->theCh; // temp can be NULL here?

Either temp != NULL is always true in loop header or in some cases you do have NULL pointer dereference which is itself a run time error.

Dmitriy Matveev
When I output using that loop in the output method it works fine for me. I am sure about the error location because when I take it out all of the other methods work fine, but as soon as I try in InsertAfter it crashes.
Nickolas
A: 

You can try running your program under Valgrind (free) or Purify (probably not free) to detect memory errors as early as possible. The error message should also be much more clear.

Also, just run the program under a debugger, and when it crashes, check its state. Is it what you expect?

phjr
A: 

Thanks for everyone's help. It turns out I was adding things to the list wrong to begin with. Instead of making it a stack I made it a Queue and all is working great! I took advice you guys gave and looked elsewhere for the problem. Thank You!

void String::SetString()
{
    StringPointer p, last;
    char tempCh;
    last = head;
    int i = 0;
    cout << "Enter a string: ";
    cin.get( tempCh );

    while( tempCh != '\n' )
    {
     i++;
     if( i == 1 )
     {
      p = new StringRec;
      p->theCh = tempCh;
      head = p;
      last = p;
     }
     else
     {
      p = new StringRec;
      p->theCh = tempCh;
      p->nextCh = last;
      last->nextCh = p;
      last = p;
     }
     cin.get( tempCh );
    }

    last->nextCh = NULL;

    stringLength = i;
}
Nickolas