0

I tried to make a dynamic array that adds elements at the beginning of the array. It works just fine with int, but when i try double, it gives me the error Process returned -1073741819 (0xC0000005). Debugging it works perfectly and all are in range, but when i run it crashes.

This is the header:

#define DYNAMICARRAY_H
#include <cstddef>

template <class T>
class DynamicArray
{
    public:
        DynamicArray();
        DynamicArray(size_t);
        DynamicArray(const DynamicArray&);
        virtual ~DynamicArray();

        DynamicArray& operator=(const DynamicArray&);
        T &operator[] (size_t);

        void add(T element);
        size_t getCapacity();
        size_t getLength();
        bool isEmpty();
        void print();
        void resizeArr();

    protected:

    private:
        T *arr;
        size_t capacity;
        size_t length;
};
#endif // DYNAMICARRAY_H

This is the .cpp

#include "DynamicArray.h"
#include <iostream>

template <class T>
DynamicArray<T>::DynamicArray()
{
    length = 0;
    capacity = 1;
    arr = (T*)malloc(capacity * sizeof(arr));
    if(!arr){
        throw std::bad_alloc();
    }

}

template <class T>
DynamicArray<T>::DynamicArray(size_t newSize)
{
    length = 0;
    capacity = newSize;
    arr = (T*)malloc(capacity * sizeof(arr));
    if(!arr){
        throw std::bad_alloc();
    }
}

template <class T>
DynamicArray<T>::~DynamicArray()
{
    delete[] arr;
    delete arr;
    delete &capacity;
    delete &length;
}

template <class T>
DynamicArray<T>::DynamicArray(const DynamicArray& other)
{
    length = other.length;
    capacity = other.capacity;
    arr = (T*)malloc(capacity * sizeof(arr));
    if(!arr){
        throw std::bad_alloc();
    }

    for(size_t i = 0; i < length; i++){
        arr[i] = other.arr[i];
    }

}

template <class T>
DynamicArray<T>& DynamicArray<T>::operator=(const DynamicArray& rhs)
{
    if (this == &rhs){
        return *this;
    }

    delete[] arr;

    length = rhs.length;
    capacity = rhs.capacity;
    arr = (T*)malloc(capacity * sizeof(arr));
    if(!arr){
        throw std::bad_alloc();
    }

    for(size_t i = 0; i < length; i++){
        arr[i] = rhs.arr[i];
    }

    return *this;
}

template <class T>
size_t DynamicArray<T>::getLength()
{
    return length;
}

template <class T>
size_t DynamicArray<T>::getCapacity()
{
    return capacity;
}

template <class T>
bool DynamicArray<T>::isEmpty(){
    return length == 0;
}

template <class T>
T &DynamicArray<T>::operator[] (size_t index)
{
    if(index >= length){
        std::cout << "Array index out of bounds" << "\n";
        exit(0);
    }
    return arr[index];
}

template <class T>
void DynamicArray<T>::add(T element)
{
    if(length >= capacity){
        resizeArr();
    }
    if(!isEmpty()){
        for(size_t i = length; i > 0; i--){
            arr[i] = arr[i-1];
        }
    }

    arr[0] = element;
    length ++;

}

template <class T>
void DynamicArray<T>::print()
{
    if(length == 0){
        std::cout << "The array is empty!";
    }
    else{
        for(size_t i = 0; i < length; i++){
            std::cout << arr[i] << " ";
        }
    }
    std::cout << "\n";
}

template <class T>
void DynamicArray<T>::resizeArr(){
    size_t newCapacity = capacity * 2;
    T *arr2 = (T*)realloc(arr, newCapacity * sizeof(arr));

    if(!arr2){
        std::cout << "Bad memory allocation";
        throw std::bad_alloc();
    }

    arr = arr2;
    capacity = newCapacity;
}

template class DynamicArray<double>;
template class DynamicArray<int>;

And the main

#include "DynamicArray.h"
#include <cstdlib>
#include <time.h>
#include <cstddef>

using namespace std;

int main()
{
    srand (time(NULL));


    DynamicArray<int> d(5);
    int randomInt;
    for(size_t i = 0; i < d.getCapacity(); i++){
        randomInt = rand()% 100;
        d.add(randomInt);
    }

    d.print();


    d.add(5);
    d.add(55);
    d.add(3);
    d.add(33);
    d.add(37);

    d.print();

    delete &d;

    cout << "\n\n";

    DynamicArray<double> d2(5);

    double randomDouble;

    for(size_t i = 0; i < d2.getCapacity() - 3; i++){
        //randomDouble = (double)rand() / ((double)RAND_MAX);
        randomDouble = 0.5f;
        d2.add(randomDouble);
        d2.print();
    }

    d2.print();

    return 0;
}

It crashes at the second for in the main, I've tried to make sure everything it set correctly, but still won't work:

for(size_t i = 0; i < d2.getCapacity() - 3; i++){
        //randomDouble = (double)rand() / ((double)RAND_MAX);
        randomDouble = 0.5f;
        d2.add(randomDouble);
        d2.print();
    }
  • 2
    Don't `delete` pointer to local variables, nor member of a class. – AProgrammer Nov 18 '19 at 17:54
  • You combine `malloc` with `delete`. Sounds like a bad idea. Use the C++ `new` operator. And maybe also look into smart pointers... – JHBonarius Nov 18 '19 at 17:57
  • Seems like [a similar homework assignment](https://stackoverflow.com/questions/58904203/what-is-the-problem-with-appending-arbitrary-object-to-the-array), with the exact same issues. – PaulMcKenzie Nov 18 '19 at 18:09
  • Also, a `DynamicArray` will fail miserably due to using `malloc` and `free` instead of `new[]` and `delete[]`. Also, the assignment operator is flawed. If `malloc` returns NULL, you have a zombie object floating around the code that is invalid to use. – PaulMcKenzie Nov 18 '19 at 18:11

2 Answers2

5
arr = (T*)malloc(capacity * sizeof(arr));

delete[] arr;
delete arr;
delete &capacity;
delete &length;

delete &d;

You pass pointers to delete[] and delete that were not returned from new[] or new respectively. Behaviour of the program is undefined. Relevant language rule:

[expr.delete]

... In a single-object delete expression, the value of the operand of delete may be a null pointer value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject representing a base class of such an object. If not, the behavior is undefined. In an array delete expression, the value of the operand of delete may be a null pointer value or a pointer value that resulted from a previous array new-expression. If not, the behavior is undefined. ...

Every delete expression of your program violate this rule.

To fix this, you must consistently use free on memory allocated with malloc, realloc or strdup, and use delete with pointers allocated with new, delete[] with pointers allocated with new[], absolutely no deallocation functions with pointers to non-dynamic objects such as member variables or objects with automatic or static storage duration, (or invalid pointers).

eerorika
  • 181,943
  • 10
  • 144
  • 256
2
arr = (T*)malloc(capacity * sizeof(arr));

sizeof(arr) is the same as sizeof(T*) which isn't what you want, I suppose. This should rather be sizeof(*arr) or sizeof(T).


Apart from that, don't mix malloc/delete or new/free, as others already pointed out.

If you're doing C, use malloc/free, and if you're in C++ use new/delete.

Using new would change the above to

arr = new T[capacity];

avoiding the whole sizing altogether.

Olaf Dietsche
  • 66,104
  • 6
  • 91
  • 177
  • Yes, thank you, it was the problem of mixing together the malloc/ delete and new/free. It works now! :D – DonVladster Nov 18 '19 at 18:09
  • There are more problems in the code beyond mixing `malloc/delete`. @eerorika already pointed out the deletes of non-allocated elements, or the double delete of `arr`. – Olaf Dietsche Nov 18 '19 at 18:14
  • @DonVladster be warned: your code [has undefined behavior](https://stackoverflow.com/q/9169774/10957435). That means it can appear to work, but really not. Please see [eerorika's answer](https://stackoverflow.com/a/58920376/10957435). –  Nov 18 '19 at 18:25