Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception Error : Access violation reading location 0xDDDDDDDD

I am trying to create a dynamic string array in c++. When trying to display the contents of my dynamic string array to the console I receive this error:

Exception thrown at 0x0FD670B6 (msvcp140d.dll) in Assignment4.exe: 0xC0000005: Access violation reading location 0xDDDDDDDD.

Here is my code:

DynamicStringArray.h

#pragma once
#include "stdafx.h"
#include <string>
#include <iostream>

using namespace std;

class DynamicStringArray
{
public:
    DynamicStringArray();
    DynamicStringArray(DynamicStringArray &array);
    ~DynamicStringArray();
    int getSize();
    void displayContents();
    void addEntry(const string &addElement);
    string getEntry(int index);
    int deleteEntry(const string &deleteElement);

private: 
    string *dynamicArray;
    int size;
};

DynamicStringArray.cpp

#include "stdafx.h"
#include "DynamicStringArray.h"
#include <string>
#include <iostream>

using namespace std;

DynamicStringArray::DynamicStringArray()
{
    dynamicArray = NULL;
    size = 0;
}

DynamicStringArray::DynamicStringArray(DynamicStringArray &array)
{
    if (dynamicArray != NULL)
    {
        size = 0;
        delete [] dynamicArray;
        dynamicArray = NULL;
    }

    size = array.getSize();
    dynamicArray = new string[size];
    for (int i = 0; i < size; i++)
        dynamicArray[i] = array.dynamicArray[i];
}

DynamicStringArray::~DynamicStringArray()
{
    cout << "In destructor." << endl;
    delete [] dynamicArray;
    dynamicArray = NULL;
}

int DynamicStringArray::getSize()
{
    return size;
}

void DynamicStringArray::displayContents()
{
    if (size != 0)
        for (int i = 0; i < size; i++)
            cout << "Item-" << i << ": " << dynamicArray[i] << endl;
    else
        cout << "Array is empty." << endl;
}

void DynamicStringArray::addEntry(const string &addElement)
{
    string *temp = new string[size + 1];
    for (int i = 0; i < size; i++)
            temp[i] = dynamicArray[i];
    temp[size] = addElement;
    size++;
    delete [] dynamicArray;
    dynamicArray = temp;
    delete[] temp;
}

string DynamicStringArray::getEntry(int index)
{
    if ((index >= 0) && (index < size))
    {
        return dynamicArray[index];
    }
    return NULL;
}

int DynamicStringArray::deleteEntry(const string &deleteElement)
{
    if(size == 0)
    {
        return false;
    }

    for (int i = 0; i < size; i++)
    {
        if (dynamicArray[i] == deleteElement)
        {
            string *temp = new string[size - 1];
            for (int x = 0; x < size - 1; ++x)
            {
                if (x < i)
                    temp[x] = dynamicArray[x];
                else
                    temp[x] = dynamicArray[x + 1];
            }

            delete[] dynamicArray;
            dynamicArray = temp;
            delete[] temp;
            --size;
            return true;
        }
    }

    return false;
}

main:

int main()
{
    DynamicStringArray dsArray1;
    cout << "dsArray1.displayContents():" << endl;
    dsArray1.displayContents();  // Should indicate array is empty
    cout << "Display dsArray1.getSize()= " << dsArray1.getSize() << endl;

    dsArray1.addEntry("Entry-A");
    dsArray1.displayContents();

    dsArray1.addEntry("Entry-B");
    dsArray1.displayContents();
    dsArray1.addEntry("Entry-C");
    dsArray1.displayContents();
    return 0;
}

Can anyone tell me what I am doing wrong. How can i fix this problem?

like image 773
mtcode Avatar asked Dec 18 '15 03:12

mtcode


1 Answers

Please note that all of this is already available by utilizing std::vector<std::string>. The std::vector class is the dynamic array class that C++ provides, and there is little to no reason to make home-made versions of what is available to you.


Having said this, one glaring issue is that your copy constructor is incorrect. The dynamicArray is uninitialized, but you use it here:

if (dynamicArray != NULL)

There is no guarantee what value dynamicArray has. The fix is to remove this entire block of code in the copy constructor:

if (dynamicArray != NULL)
{
    size = 0;
    delete [] dynamicArray;
    dynamicArray = NULL;
}

Since the copy constructor constructs a brand new object, there is no reason to "pretest" for a NULL pointer and thus do unnecessary work. Remember that the object did not exist, so there is nothing preliminary to do.


The second issue is that you're issuing a delete [] temp; call in the addEntry and deleteEntry functions. Remove these lines, as you are deallocating the memory that you've just assigned to dynamicArray.


The third issue is that you're missing the user-defined assignment operator. The assignment operator has the following signature, and you need to provide the implementation:

DynamicStringArray& operator=(const DynamicStringArray& );

Without this function, assigning a DynamicStringArray to another DynamicStringArray will cause memory leaks and double deallocation of memory when both objects go out of scope.

One implementation can use the copy / swap idiom:

#include <algorithm>
//...
DynamicStringArray& DynamicStringArray::operator=(const DynamicStringArray& rhs)
{
    DynamicStringArray temp(rhs);
    std::swap(temp.dynamicArray, dynamicArray);
    std::swap(temp.size, size);
    return *this;
}

Another issue is this:

string DynamicStringArray::getEntry(int index)
{
    if ((index >= 0) && (index < size))
    {
        return dynamicArray[index];
    }
    return NULL;  // <-- Undefined behavior if this is done
}

It is undefined behavior to assign a std::string object with NULL. Either return an empty string, or throw an exception if the index is out of bounds.


In conclusion, I highly recommend that you read up on the Rule of 3 when it comes to designing classes that must implement correct copy semantics.

like image 95
PaulMcKenzie Avatar answered Oct 04 '22 03:10

PaulMcKenzie