Dynamic Array and [] operator overloading issue.

Hello, I need some help from experienced folks on this dynamic array I'm creating. I'll get straight to the point. My program asks the user to enter in the initial size s of the array and then a multiplier m. The array is initiated with the first number, but s * m doubles are assigned to the array, which it creates space for. The problem is with my [] operator overload, which is randomly breaking my program. It seems as long as my array only has one row, it works perfectly. If I allocate another to the ** pointer it seems like that breaks it.

I need another opinion on this, because I feel like I'm stuck. Is it not hard copying or am I allocating the memory incorrectly. Either way I'm in a jam.

Here's my code.

DynArray.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#ifndef DYNARRAY_H
#define DYNARRAY_H

class DynArray
{
private:
	//fields
	double ** m_cArray;
	int m_cSize;
	int m_cNumArrays;
public:
	//Constructors
	DynArray();

	DynArray(int);

	DynArray(DynArray &);

	~DynArray();
	//Operators
	DynArray & operator = (const DynArray &);
	double & operator [] (const int &);
	//Public Methods
	int getSize();
	//Helper Methods
private:
	void Grow();

};


#endif // !DYNARRAY_H 


DynArray.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include "DynArray.h"
#include <iostream>

	DynArray::DynArray()
	{
		DynArray::DynArray(1);
	}
	DynArray::DynArray(int size)
	{
		m_cNumArrays = 1;
		m_cSize = size;
		m_cArray = new double*;
		m_cArray[0] = new double[m_cSize];
		memset(m_cArray[0], 0, m_cSize * sizeof(double));
	}
	DynArray::DynArray(DynArray & other)
	{
		m_cNumArrays = 1;
		m_cSize = other.m_cSize;
		m_cArray = new double*;
		m_cArray[0] = new double[m_cSize];
		for (int i = 0; i < other.m_cSize; i++)
				m_cArray[0][i] = other[i];
	}
	DynArray::~DynArray() 
	{
		for (int i = 0; i < m_cNumArrays; i++) {
			delete [] m_cArray[i];
			m_cArray[i] = nullptr;
		}
		delete [] m_cArray;
		m_cArray = nullptr;
		std::cout << "***DESTRUCTION***" << std::endl;
	}
	DynArray & DynArray::operator = (const DynArray & other)
	{
		if (this != &other)
		{
			if ((m_cSize != other.m_cSize) | (m_cNumArrays != other.m_cNumArrays))
			{
				delete[] m_cArray;
				m_cArray = nullptr;

				m_cNumArrays++;
				m_cSize = other.m_cSize % 10;
				m_cArray = new double*[m_cSize];

				while (m_cSize < other.m_cSize)
					Grow();
			}
			for (int k = 0; k < m_cNumArrays; k++) {
				for (int i = 0; i < m_cSize; i++)
					m_cArray[k][i] = other.m_cArray[k][i];
			}
		}
		return *this;
	}
	
	double & DynArray::operator [] (const int &index)
	{
		while (index >= m_cSize) Grow();
		int row = 0, col = 0, first = m_cSize - ((m_cNumArrays - 1)*10);

		for (int i = 0; i < index; i++)
		{
			col++;
			if (col == first && i == first - 1)
			{
				col = 0;
				row++;
			}
			else if (col == 10 && i >= first)
			{
				col = 0;
				row++;
			}
		}

		if (&m_cArray[row][col] == nullptr) 
			throw - 1;

		//std::cout << row << "," << col << " \n";
		return this->m_cArray[row][col];
	}
	
	int DynArray::getSize()
	{
		return m_cSize;
	}

	void DynArray::Grow()
	{
		m_cSize += 10;
		m_cNumArrays++;
		m_cArray = new double*;
		m_cArray[m_cNumArrays - 1] = new double[10];
		memset(m_cArray[m_cNumArrays - 1], 0, 10 * sizeof(double));
		std::cout << "**Generating Array**\n";
	}


Main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include "stdafx.h"
#include "DynArray.h"
#include <ctime>
#include <iostream>
//Function Declarations
void BubbleSort(DynArray &, int);	
void Pause();					
void IsSorted(DynArray &, int);		

int main()
{
	std::srand(time(NULL));
	int s = 0, m = 0;
	std::cout << "Enter in an initial size for the array: ";
	std::cin >> s;
	std::cout << "Enter in a multiplier: ";
	std::cin >> m;
	DynArray f(s);
	for (int i = 0; i < s * m; i++) 
	{
			f[i] = (double)rand() / RAND_MAX;
	}
	std::cout << s * m << " Doubles Generated.\n";
	BubbleSort(f, s * m);

	Pause();
    return 0;
}

void BubbleSort(DynArray & Array, int size)
{
	int i, j;
	std::clock_t start;
	double duration, temp;

	std::cout << "**Beginning sort**" << std::endl;
	start = clock();

	for (i = 1; i < size; ++i)
	{
		for (j = 0; j < (size - i); ++j)
			if (Array[j] > Array[j + 1])
			{
				temp = Array[j];
				Array[j] = Array[j + 1];
				Array[j + 1] = temp;
			}
	}
	IsSorted(Array, size);

	duration = ((clock() - start) / (double) CLOCKS_PER_SEC);

	for (int i = 0; i < size; i++)
	{
		std::cout << i + 1 << ": " << Array[i] << std::endl;
	}
	std::cout << "Sort Duration: " << duration << " seconds" << std::endl;
}

void Pause()
{
	std::cout << "\nPaused: Enter any character to continue\n";
	char s = '\0';									//Throwaway character variable
	std::cin >> s;
}

void IsSorted(DynArray &arr, int size)
{
	for (int i = 1; i < size; i++)
	{
		if (arr[i - 1] > arr[i])
		{
			std::cout << "**Array Not Sorted**" << std::endl;
		}
	}
	std::cout << "**Array Sorted**" << std::endl;
}
Last edited on
The problem is in your ctor DynArray::DynArray(int size), it takes one argument which is variable s, line 15, main(). But there is no way to pass variable m, line 17, main() to this ctor and so whatever memory it'll be allocating within the ctor would be off. You need to have another ctor with 2 arguments that'll allocate memory in accordance with variables s and m.

Also take another look at your default ctor - I'm getting the following error messages related to it:
1
2
error: cannot call constructor 'DynArray::DynArray' directly [-fpermissive]|
note: for a function-style cast, remove the redundant '::DynArray'|

If you're trying to delegate ctor's (allowed since C++11) take a look here for the right syntax: https://en.wikipedia.org/wiki/C++11#Object_construction_improvement
Huh, I'm not getting that error you're getting. Also, The point and purpose of this program is that you create an array smaller than the amount of variables you're assigning to it, so passing m and s would be cheating. The code I posted compiles and runs for me up until line 72 main() where it tries to get the numbers I assigned to it using the [] which it seems to have a problem with.

Thanks for your help, but my problem still persists.
Last edited on
Hmm, interesting. At my end the program has a run-time error after line 23 of main() and I'm still intrigued how you can
create an array smaller than the amount of variables you're assigning to it
. Anyways, let me step aside and see if someone can shed some light on this
closed account (48T7M4Gy)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <iostream>

class DynArray
{
private:
    double ** m_cArray;
    int m_cSize;
    int m_cNumArrays;
    
public:
    DynArray();
    DynArray(int);
    DynArray(DynArray &);
    
    ~DynArray();
    
    DynArray & operator = (const DynArray &);
    double & operator [] (const int &);
    int getSize();

private:
    void Grow();
    
};

DynArray::DynArray()
{
    DynArray::DynArray(1);
}

DynArray::DynArray(int size)
{
    m_cNumArrays = 1;
    m_cSize = size;
    m_cArray = new double*;
    m_cArray[0] = new double[m_cSize];
}

DynArray::DynArray(DynArray & other)
{
    m_cNumArrays = 1;
    m_cSize = other.m_cSize;
    m_cArray = new double*;
    m_cArray[0] = new double[m_cSize];
    for (int i = 0; i < other.m_cSize; i++)
        m_cArray[0][i] = other[i];
}
DynArray::~DynArray()
{
    for (int i = 0; i < m_cNumArrays; i++) {
        delete [] m_cArray[i];
        m_cArray[i] = nullptr;
    }
    delete [] m_cArray;
    m_cArray = nullptr;
    std::cout << "***DESTRUCTION***" << std::endl;
}
DynArray & DynArray::operator = (const DynArray & other)
{
    if (this != &other)
    {
        if ((m_cSize != other.m_cSize) | (m_cNumArrays != other.m_cNumArrays))
        {
            delete[] m_cArray;
            m_cArray = nullptr;
            
            m_cNumArrays++;
            m_cSize = other.m_cSize % 10;
            m_cArray = new double*[m_cSize];
            
            while (m_cSize < other.m_cSize)
                Grow();
        }
        for (int k = 0; k < m_cNumArrays; k++) {
            for (int i = 0; i < m_cSize; i++)
                m_cArray[k][i] = other.m_cArray[k][i];
        }
    }
    return *this;
}

double & DynArray::operator [] (const int &index)
{
    while (index >= m_cSize) Grow();
    int row = 0, col = 0, first = m_cSize - ((m_cNumArrays - 1)*10);
    
    for (int i = 0; i < index; i++)
    {
        col++;
        if (col == first && i == first - 1)
        {
            col = 0;
            row++;
        }
        else if (col == 10 && i >= first)
        {
            col = 0;
            row++;
        }
    }
    
    if (&m_cArray[row][col] == nullptr)
        throw - 1;
    
    //std::cout << row << "," << col << " \n";
    return this->m_cArray[row][col];
}

int DynArray::getSize()
{
    return m_cSize;
}

void DynArray::Grow()
{
    m_cSize += 10;
    m_cNumArrays++;
    m_cArray = new double*;
    m_cArray[m_cNumArrays - 1] = new double[10];
    memset(m_cArray[m_cNumArrays - 1], 0, 10 * sizeof(double));
    std::cout << "**Generating Array**\n";
}

int main()
{
    std::srand(time(NULL));
    int s = 0, m = 0;
    std::cout << "Enter in an initial size for the array: ";
    std::cin >> s;
    std::cout << "Enter in a multiplier: ";
    std::cin >> m;
    DynArray f(s);
    for (int i = 0; i < s * m; i++)
    {
        f[i] = (double)rand() / RAND_MAX;
    }
    std::cout << s * m << " Doubles Generated.\n";
    
    return 0;
}
closed account (48T7M4Gy)
I haven't got a clue what your program is supposed to do but the above runs. I cut out what appeared to be unnecessary stuff including the memset which is frowned upon. I tried a number of options with s & m (???) and they all gave output similar to this, and the program didn't crash.

Enter in an initial size for the array: 2
Enter in a multiplier: 6
**Generating Array**
12 Doubles Generated.
***DESTRUCTION***
Program ended with exit code: 0


I get the impression that your program creates a single 1d array of length s, and then allocates m-1 arrays additional space. Why you would do that and not just create a 2d dynamic array straight off is very unclear to me. becuse there doesn't appear to be any 'multiplication' after the DynArray is initialised.

This is yet another case, unfortunately, where a less than adequate problem definition and purpose obscures a simple solution. :)

PS I just saw the Grow function. I see that is bound into the operator[] method. That is bad practice because it makes debugging difficult. Separate the two as stand alone methods and test each. Also I can't see any value in making Grow() private. All it does is add complexity. :) ( ... still )
Last edited on
Yes, my experience as mentioned above, corroborates kemort's. Not sure what the OP is trying to do here but s/he seemed quite confident about whatever it is
closed account (48T7M4Gy)
Maybe it's an exercise in duplicating the ability of STL containers to grow as required. (I guess we shouldn't even contemplate shrinking)

If it the object 'knows' how to grow, the lines in main regarding f(s) and the number of doubles generated are misleading. For good debugging they should be in a class method somewhere.

Anyway, I've had enough.
Thanks everyone. I'll try to clear up what my program is supposed to do.

I've tried to make a dynamic array class called DynArray which holds doubles with appropriate fields, getters, setters, and methods. A DynArray acts like an array, but grows as necessary to accommodate the items it holds obviously using dynamic allocation.I'm trying to ensure that DynArray approximates the performance of an array.

The easy way to do this would be by making a new larger array when the existing one is too short and subsequently copying items over. I'm not doing it the easy way. I decided to use large blocks for the arrays that are created dynamically and linked to another root array, for example.

The main() method first asks the user to enter an initial size for the array (say s), and the initial array should be at least that large. It then prompts the user to enter another positive integer as a multiplier (say m). The program will then generate s*m random doubles and insert them into the dynamic array which should grow as needed.

The goal of this program is to have a dynamic array class that ACTS like an array. The class does not work right now. While my [] operator overload does allow me to "set" doubles to my dynamic array, it's acting like my arrays are pointing at nothing when I try to "get" them.

If there's anything else you'd like me to clear up or if I wasn't specific enough in any area, I'll gladly elaborate more. I'm eager to solve this problem.
Last edited on
What you are trying to do seems to be more in line with defining an Allocator rather than a dynamic array. Each std library container template takes a parameter of type Allocator that handles its memory management. It is possible to have an user-defined Allocator such as here: http://www.josuttis.com/cppcode/allocator.html
So in your case you could try working with one of the std library containers with your own Allocator (would not work with std::array though as its size, similar to C-style arrays, is fixed)
closed account (48T7M4Gy)
And here is another example from "Data Structures and Algorithm Analysis in C++ (Fourth Edition)", M.A. Weiss. This is a Vector (not <vector>) that dynamically allocates memory for templated objects stored in arrays.

https://users.cs.fiu.edu/~weiss/dsaa_c++4/code/Vector.h

Weiss's website https://users.cs.fiu.edu/~weiss/#dsaac++3
Topic archived. No new replies allowed.