简体   繁体   中英

Deleting pointers from an array

I am fairly new to C++, and this problem I am having has had me stumped for like the last 2 hours. What I am trying to do is create an array of pointers to my class Word objects, so a 2 dimensional array, which is **wordPtrList . Then I need to delete the memory of certain objects in the array and set their pointers to null. I have written a smaller version of what I am trying to accomplish below.

int main()
{
    char *cArray;
    cArray = new char[4];
    int i;

    for (i = 0; i < 3; i++)
        cArray[i] = 'a';

    cArray[i + 1] = '\0';   //cArray is a null terminated string

    Word **wordPtrList;
    wordPtrList = new Word* [3];

    for (i = 0; i < 3; i++)
    {
        wordPtrList[i] = new Word(cArray);
    }

    wordPtrList[1]->del();
    delete wordPtrList[1];
    wordPtrList[1] = '\0';

    return 0;
}

class Word
{
private:
    char* ptr_;
    int len_;
public:
    Word(const char* word)
    {
        len_ = strlen(word);
        ptr_ = new char[len_];      
        strcpy(ptr_, word);
    }
    ~Word()
    {
        delete [] ptr_;
        ptr_ = 0;
    }


    void del()
    {
        delete [] ptr_;
        ptr_ = 0;
        return;
    }

};

When I do this however, I get:

Debug Error Heap Corruption Detected after normal block

This is in VS 2010 on Windows 7.

So what I am asking is, how do I delete the memory of my object so that I can set wordPtrList[1] to Null?

Look at this code:

for (i = 0; i < 3; i++)
    cArray[i] = 'a';
cArray[i + 1] = '\0';   //cArray is a null terminated string

The problem is at the last line which is using i+1 as index, which is going out of range, as by the time the loop exits, the value of i is already 3 ; that means i+1 will become 4 which cannot be a valid index when you've allocated cArray as:

cArray = new char[4]; //taken from your code

The solution is this:

cArray[i] = '\0';   //Now, it is correct. Here i is equal to 3

That is, use i instead of i+1 ; Or simply use 3 .


In C++, you could std::fill instead of manual loop, as:

std::fill(cArray, cArray + 4, 'a'); //done

Even better avoid using char* with new as much as possible, and prefer using std::string instead.

You are allocating 4 bytes to cArray (meaning you have access to write to bytes 0 through 3), and then writing to cArray[4]. You also allocate one byte too small in the Word constructor.

char *cArray;
cArray = new char[4];
int i;

for (i = 0; i < 3; i++)
    cArray[i] = 'a';
cArray[i] = '\0';   //cArray is a null terminated string - i is now 3

and

 Word(const char* word)
 {
    len_ = strlen(word);
    ptr_ = new char[len_ + 1];      
    strcpy(ptr_, word);
 }

should do the trick.

There are two obvious off-by-one errors in the code (when you get out of the first loop what is the value of the variable i ? when calling strlen did you remember to consider the space needed by the null terminator?).

Also please note that c strings are not "null terminated", they are "NUL terminated" with uppercase letters and only one "L". NUL is the name of the ASCII control character with all bits set to zero and is represented in C++ with '\\0' . In one place you used NUL character as a null pointer, and while this is technically correct (because of a design bug of the C++ language) it's better to understand that the two concepts are quite different.

As others have said, you're basically accessing an array index which is out of bounds of the array.

I would go with Nathan Wiebe's solution.

In the future, when you have the option to do this, it's recommended to use std::vector<T> as that will allow you to store any type you wish in a dynamically resizeble array. In other words, providing you don't access an index which is outside of the vector's bounds, you could do something like this:

std::vector< char* > str;

for( size_t i = 0; i < str.size(); ++i )
{
   str.push_back( 'a pointer to a block of memory consisting of characters' ); 
}

class Word
{
public:
    Word( const char* str )
    {
        mStrs.push_back( str );
    }
    ~Word( void )
     {
         for( size_t i = 0; i < mStrs.size(); ++i )
         {
             if( mStrs[ i ] )
             {
                 delete mStrs[ i ];
                 mStrs[ i ] = NULL;
             }
         }

         mStrs.clear();
     }

private:
    void del( size_t index )
    {   
         if( index > mStrs.size() )
         {
              //error - throw new exception or something
         }

         delete mStrs[ index ];
    }

    std::vector< const char* > mStrs;

};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM