2D array in a class using c++ - c++

I wrote a code to present a class Third takes instances of other two classes One , and Two respectively , everything was working fine until i added a matrix Mat , and the method get_Mat in the third class , in the code it has the name Third, this code doesn't produce any error message , but when execute it does until the line before return 0 in main , then it terminate as something wrong was encountered by the compiler and need to be closed , i wish that you can help me find the problem.
Thanks.
#include<iostream>
#include<vector>
#include <stdlib.h>
using namespace std;
class One // this the first class
{
private:
unsigned int id;
public:
unsigned int get_id(){return id;};
void set_id(unsigned int value) {id = value;};
One(unsigned int init_val = 0): id(init_val) {}; // constructor
~One() {}; // destructor
};
////////////////////////////////////////////////////////////////////
class Two // the second class
{
private:
One first_one;
One second_one;
unsigned int rank;
public:
unsigned int get_rank() {return rank;};
void set_rank(unsigned int value) {rank = value;};
unsigned int get_One_1(){return first_one.get_id();};
unsigned int get_One_2(){return second_one.get_id();};
Two(const One& One_1 = 0, const One& One_2 =0 , unsigned int init_rank = 0)
: first_one(One_1), second_one(One_2), rank(init_rank)
{
}
~Two() {} ; // destructor
};
/////////////////////////////////////////////////////////////
class Three // the third class
{
private:
std::vector<One> ones;
std::vector<Two> twos;
vector<vector<unsigned int> > Mat;
public:
Three(vector<One>& one_vector, vector<Two>& two_vector)
: ones(one_vector), twos(two_vector)
{
for(unsigned int i = 0; i < ones.size(); ++i)
for(unsigned int j = 0; j < ones.size(); ++j)
Mat[i][j] = 1;
}
~Three() {};
vector<One> get_ones(){return ones;};
vector<Two> get_twos(){return twos;};
unsigned int get_Mat(unsigned int i, unsigned int j) { return Mat[i][j];};
void set_ones(vector<One> vector_1_value) {ones = vector_1_value;};
void set_twos(vector<Two> vector_2_value) {twos = vector_2_value;};
};
///////////////////////////////////////////////////////////////////////
int main()
{
cout<< "Hello, This is a draft for classes"<< endl;
vector<One> elements(5);
cout<<elements[1].get_id()<<endl;
vector<Two> members(10);
cout<<members[8].get_One_1()<<endl;
Three item(elements, members);
cout<<item.get_ones()[3].get_id() << endl;
cout << item.get_Mat(4, 2) << endl;
return 0;
}

First, when you construct your object of class Three here:
Three item(elements, members);
its Mat member is a vector<vector<unsigned int> > of size zero. It is pure coincidence that the constructor does not crash right away. For example if you need a matrix of size n x m, you would have to do
Mat.resize(n);
for(unsigned int i =0;i<n;++i)
Mat[i].resize(m);
before you can safely use expressions like Mat[i][j].
Second, in your constructor of Three:
for(unsigned int i = 0; i < ones.size(); ++i)
for(unsigned int j = 0; j < ones.size(); ++j)
Mat[i][j] = 1;
is it intended that you don't use twos.size() in one of the loops?

Related

Avoiding struct downcasting when passing to a function (C++)

I have a set of Arguments defined as struct for a set of operations (mean, minmax etc.)
struct Arguments {
double *data;
int num_data;
Arguments(double *data, int num_data) : data(data), num_data(num_data) {}
};
struct MeanOperationArguments: Arguments {
MeanOperationArguments(double *data, int num_data) : Arguments(data, num_data) {}
};
struct MinmaxOperationArguments: Arguments {
bool is_min_op;
MinmaxOperationArguments(double *data, int num_data, bool is_min_op) : is_min_op(is_min_op), Arguments(data, num_data) {}
};
I need to define an Operation class as follows:
class Operation {
public:
virtual void execute() = 0;
}
class MeanOperation: public Operation {}
// an operation that can be told to display either the minimum or the maximum.
class MinmaxOperation: public Operation {}
Also, I have an operation factory with returns the specifc operation object instance based on the type of operation:
class OperationFactory {
public:
Operation *get(OP_TYPE t, Arguments *args) {
switch(t) {
case MEAN:
return new MeanOperation(args);
case MINMAX:
return args->is_min_op ? // ERROR: Because struct downcasts to `Arguments`
new MinOperation(args):
new MaxOperation(args);
}
}
};
I need to be able to run my operation based on the type of argument struct like this:
int main() {
double data[] = { 1, 2, 3, 4 };
int num_data = 4;
OperationFactory operations;
Arguments *mean_args = new MeanOperationArguments(data, num_data);
Operation *mean_op = operations.get(MEAN, mean_args);
mean_op->execute();
Arguments *min_args = new MinmaxOperationArguments(data, num_data, true);
Operation *min_op = operations.get(MINMAX, min_args);
min_op->execute();
return 0;
}
How can I initialize my operation with require arguments based on the use case?
If you put a single virtual method in the base class, preferably the destructor, you could use dynamic_cast to convert the pointer to an instance of the derived class. If the conversion fails you have your answer, if it succeeds you can call any of the derived class methods on it.
There are multiple things I have to address. First, avoid structure parent / child relationships. It adds unnecessary dependencies. Look at structures like custom data structures. Data is data at the end of the day. It only has meaning when you interpret it. Going off that logic, your argument structure could be simplified as an array with an unsigned integer that tells how long is that array (similar to a vector, so maybe you could look into using a vector instead of a struct). Going off this logic, the best approach you can take is having multiple functions with different names that take in the same arguments but return different result based on whatever it is that you want it to do. Here is what I am talking about:
#include <iostream>
struct DataSet {
public:
double* data;
int size;
DataSet(double* data, unsigned int size) {
this->data = new double[size];
this->size = size;
for (unsigned int i = 0; i < size; i++)
this->data[i] = data[i];
}
};
double mean(const DataSet& dataSet) {
double mean = 0;
for (unsigned int i = 0; i < dataSet.size; i++)
mean += dataSet.data[i];
mean = mean / dataSet.size;
return mean;
}
double min(const DataSet& dataSet) {
double min = dataSet.data[0];
for (unsigned int i = 1; i < dataSet.size; i++)
if (dataSet.data[i] < min)
min = dataSet.data[i];
return min;
}
double max(const DataSet& dataSet) {
double min = dataSet.data[0];
for (unsigned int i = 1; i < dataSet.size; i++)
if (dataSet.data[i] > min)
min = dataSet.data[i];
return min;
}
int main() {
double data[5] = { 1, 2, 3, 4, 5 };
unsigned int size = 5;
DataSet dataSet = DataSet(data, size);
double result = 0;
result = mean(dataSet);
std::cout << "Mean: " << result << std::endl;
result = min(dataSet);
std::cout << "Min: " << result << std::endl;
result = max(dataSet);
std::cout << "Max: " << result << std::endl;
}
I included everything in one .cpp file for convenience. If you are trying to implement a system, I would suggest making an enum class, store an enum value that represents what operation the user wants to perform, make a switch statement that points to these functions.
Note, be careful with passing pointers around because you might end up with memory leaks. If you notice in the code implementation, I am doing a deep copy, therefore passing memory ownership to the structure to DataSet.
Edit for better system design fit
#include <iostream>
class DataSet {
public:
double* data;
int size;
DataSet() {
data = nullptr;
size = 0;
}
DataSet(double* data, unsigned int size) {
this->data = new double[size];
this->size = size;
for (unsigned int i = 0; i < size; i++)
this->data[i] = data[i];
}
~DataSet() {
if (data != nullptr)
delete(data);
}
};
class Operation {
protected:
DataSet dataSet;
public:
Operation(double* data, unsigned int size) : dataSet(data, size) {
}
virtual double execute() = 0;
};
class Mean : public Operation {
public:
Mean(double* data, unsigned int size) : Operation(data, size) {
}
~Mean() {
}
double execute() {
double mean = 0;
for (unsigned int i = 0; i < dataSet.size; i++)
mean += dataSet.data[i];
mean = mean / dataSet.size;
return mean;
}
};
class MinMax : public Operation {
public:
bool useMin;
MinMax(double* data, unsigned int size) : useMin(true), Operation(data, size) {
}
~MinMax() {
}
double execute() {
if (useMin) {
double min = dataSet.data[0];
for (unsigned int i = 1; i < dataSet.size; i++)
if (dataSet.data[i] < min)
min = dataSet.data[i];
return min;
}
else {
double min = dataSet.data[0];
for (unsigned int i = 1; i < dataSet.size; i++)
if (dataSet.data[i] > min)
min = dataSet.data[i];
return min;
}
}
};
int main() {
double data[5] = { 1, 2, 3, 4, 5 };
unsigned int size = 5;
DataSet dataSet = DataSet(data, size);
double result = 0;
Mean mean = Mean(data, size);
std::cout << "Mean: " << mean.execute() << std::endl;
MinMax minMax = MinMax(data, size);
std::cout << "MinMax: " << minMax.execute() << std::endl;
minMax.useMin = false;
std::cout << "MinMax: " << minMax.execute() << std::endl;
}
For better fit your system, I worked out a better solution. I still got rid of your struct hierarchy but kept the hierarchy in your classes. MinMax will return min or max depending on the useMin boolean value. You said you are printing it in the comments, so you would just have to change it to void and instead of returning the value, just print it. I hope this points you into a better direction.
Something like:
case MINMAX:
return dynamic_cast<MinmaxOperationArguments*>(args)->is_min_op ?
new MinOperation(args):
new MaxOperation(args);
}
Note, that result of cast should be checked before use or it may crash in case of incorrect argument.
RTTI has to be enabled.

Class that uses dynamically generated array

Trying to make a class that can change the contents of a specific element in a dynamically created 2 dimensional array of strings.
So I have a program that creates a 2d array dynamically and later on I want to have a class that takes that array as its argument, along with 2 integers that will be the indexes of a specific element. Later on I'll have it swap the content of that element and scan other elements of the array that it wants to swap it with. For now I'm struggling with even having the class take that array as its argument. I know I'll have to do this by reference and not by value, since the array will be dynamically created, but it seems I am doing it wrong.
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Example {
int x, y;
string** chart;
public:
Example(int i, int j,string **arr);
void print() const { cout << x << y << chart[x][y] << endl; }
};
Example::Example(int i, int j,string **arr) {
x = i;
y = j;
**chart = **arr;
}
int main() {
string chart[7][7]; //to make the experiment simpler I haven't
//made the array dynamically generated yet
//but it will be later
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 7; j++) {
if (chart[i][j] == "")
chart[i][j].insert(0, 3, ' ');
}
}
chart[6][5] = "EXA";
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 7; j++) {
cout << '[' << chart[i][j] << ']';
}
cout << endl;
}
Example Exa1(6, 5, &chart);
Exa1.print();
return 0;
}
The problem is that the type of &chart is std::string (*)[7][7] which cannot be implicitly converted to a string** and so the constructor Example::Example(int i, int j,string **) cannot be used. This is exactly what the mentioned error says:
error: no matching function for call to 'Example::Example(int, int, std::string (*)[7][7])'
45 | Example Exa1(6, 5, &chart);
To solve this make sure that &chart has the same type as the 3 parameter of your constructor.
Also it would be better to use std::vector.
class Example {
int x, y;
std::vector<std::vector<string>> chart;
public:
Example(int i, int j,const std::vector<std::vector<std::string>> &arr);
};
Example::Example(int i, int j,const std::vector<std::vector<std::string>> &arr)
:x(i),y(j),chart(arr) {
}
int main() {
std::vector<std::vector<std::string>> chart(7, std::vector<std::string>(7));
//pass chart instead of &chart
Example Exa1(6, 5, chart);
}
Working demo
Or you can also use std::array
class Example {
int x, y;
std::array<std::array<std::string, 7>, 7> chart;
public:
Example(int i, int j,const std::array<std::array<std::string, 7>, 7> &arr);
};
Example::Example(int i, int j,const std::array<std::array<std::string, 7>, 7> &arr)
:x(i),y(j),chart(arr) {
}
int main() {
std::array<std::array<std::string, 7>, 7> chart;
//pass chart instead of &chart
Example Exa1(6, 5, chart);
}

C++: Two Dimensional Array as class member

in my C++ class at university, i have to implement a Directed, weighted graph. As internal representation i have to implement a two-dimensional array, which stores the information about the edges between the vertices in the graph.
okay, i´ve implemented a C++ class "TwoDimArray" with an overloaded [] operator.
it works well as long as i instantiate objects of TwoDimArray in main(). But it does not as class member.
My Class for representation of the graph is "DirectedGraph" and has a private member "adjacencyMatrix" of Type TwoDimArray*.
In the constructor of my DirectedGraph class i intend to fill the array with zeros initially, indicating "there is no edge between the nodes i and j".
okay, and this is where it all goes wrong. I can write till coordinate [0][2] (when initializing the graph with 3 nodes, so the array should have 3x3 cells). when trying to write at adress [1][0] the assignment operation crashes with segmentation fault. So the assignment operations succeed n times and fail beginning at n+1 (where n is the number of vertices).
Any ideas what i am doing wrong?
My TwoDimArray Class (first header, then implementation):
#ifndef TWODIMARRAY_H_INCLUDED
#define TWODIMARRAY_H_INCLUDED
class TwoDimArray{
private:
int* pArr;
int rows;
int cols;
public:
TwoDimArray(int rows, int cols);
int* operator[](int row);
~TwoDimArray();
};
#endif // TWODIMARRAY_H_INCLUDED
The implementation:
#include <TwoDimArray.h>
TwoDimArray::TwoDimArray(int nrOfRows, int nrOfCols){
rows = nrOfRows;
cols = nrOfCols;
//allocate memory
pArr = new int[rows * cols];
}
int* TwoDimArray::operator [](int row){
return &pArr[row * cols];
}
TwoDimArray::~TwoDimArray(){
delete[] pArr;
}
Directed Graph header:
#define DIRECTEDGRAPH_H_INCLUDED
#include <string>
#include <list>
#include <Vertex.h>
#include <TwoDimArray.h>
using namespace std;
/**
* DOCUMENTATION
* ======================
* object oriented Implementation
* of the abstract
* Datatype Directed Graph
* as C++ class
*/
class DirectedGraph{
private:
int maxVertices;
list<Vertex> vertices;
TwoDimArray* adjacencyMatrix;
bool edgeExists(string srcName, string tgtName);
int vertexExists(string vName);
public:
//DirectedGraph();
DirectedGraph(int maxVertices);
~DirectedGraph();
void AddVertex(Vertex& v);
void AddEdge(Vertex& source, Vertex& target, int weight);
int getMaxVertices() const;
list<Vertex> getVertexNames()const;
void PrintGraph();
};
#endif // DIRECTEDGRAPH_H_INCLUDED
Directed Graph Implementation (only the constructor):
DirectedGraph::DirectedGraph(int maxV){
this->maxVertices = maxV;
//initialize the array
this->adjacencyMatrix = new TwoDimArray(maxV, maxV);
int i = 0;
int j = 0;
for(i = 0; i <= maxVertices - 1; i++){
for(j = 0; j <= maxVertices - 1; j++){
// ==> the fatal assignment
//fails at i = 1 and j = 0
*adjacencyMatrix[i][j]=0;
cout << "assigned " << i << " " << j << "with 0"<<endl;
}
}
}
any suggestions?
i guess its not okay to declare the class member as TwoDimArray* instead of TwoDimArray, but otherwise it does not compile.
What i´ve also tried is:
DirectedGraph::DirectedGraph(int maxV){
this->maxVertices = maxV;
//try to instantiate TwoDimArray
TwoDimArray myArr(maxV, maxV);
this->adjacencyMatrix = myArr;
int i = 0;
int j = 0;
for(i = 0; i <= maxVertices - 1; i++){
for(j = 0; j <= maxVertices - 1; j++){
// ==> the fatal assignment
//fails at i = 1 and j = 0
myArr[i][j]=0;
cout << "assigned " << i << " " << j << "with 0"<<endl;
}
}
}
but it fails at the same point.
i am not very familiar with pointer logic in c++ i must admit...
any suggestions?
thanks in advance
Roland
You have violated the Rule of Three. The easiest way to solve that is to avoid directly allocating memory:
class TwoDimArray{
private:
std::vector<int> arr;
int rows;
int cols;
public:
TwoDimArray(int rows, int cols) : arr(rows * cols);
int* operator[](int row) { return &arr[cols*row]; }
};
One problem is that you're not providing a copy constructor and assignment operator for TwoDimArray.
This breaks the following:
TwoDimArray myArr(maxV, maxV);
this->adjacencyMatrix = myArr;
and possibly other code.
See What is The Rule of Three?

Converting multidimensional arrays to pointers in c++

I have a program that looks like the following:
double[4][4] startMatrix;
double[4][4] inverseMatrix;
initialize(startMatrix) //this puts the information I want in startMatrix
I now want to calculate the inverse of startMatrix and put it into inverseMatrix. I have a library function for this purpose whose prototype is the following:
void MatrixInversion(double** A, int order, double** B)
that takes the inverse of A and puts it in B. The problem is that I need to know how to convert the double[4][4] into a double** to give to the function. I've tried just doing it the "obvious way":
MatrixInversion((double**)startMatrix, 4, (double**)inverseMatrix))
but that doesn't seem to work. Is that actually the right way to do it?
No, there's no right way to do specifically that. A double[4][4] array is not convertible to a double ** pointer. These are two alternative, incompatible ways to implement a 2D array. Something needs to be changed: either the function's interface, or the structure of the array passed as an argument.
The simplest way to do the latter, i.e. to make your existing double[4][4] array compatible with the function, is to create temporary "index" arrays of type double *[4] pointing to the beginnings of each row in each matrix
double *startRows[4] = { startMatrix[0], startMatrix[1], startMatrix[2] , startMatrix[3] };
double *inverseRows[4] = { /* same thing here */ };
and pass these "index" arrays instead
MatrixInversion(startRows, 4, inverseRows);
Once the function finished working, you can forget about the startRows and inverseRows arrays, since the result will be placed into your original inverseMatrix array correctly.
For given reason that two-dimensional array (one contiguous block of memory) and an array of pointers (not contiguous) are very different things, you can't pass a two-dimensional array to a function working with pointer-to-pointer.
One thing you could do: templates. Make the size of the second dimension a template parameter.
#include <iostream>
template <unsigned N>
void print(double a[][N], unsigned order)
{
for (unsigned y = 0; y < order; ++y) {
for (unsigned x = 0; x < N; ++x) {
std::cout << a[y][x] << ' ';
}
std::cout << '\n';
}
}
int main()
{
double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}};
print(arr, 3);
}
Another, a bit clumsier way might be to make the function accept a pointer to a single-dimensional array, and both width and height given as arguments, and calculate the indexes into a two-dimensional representation yourself.
#include <iostream>
void print(double *a, unsigned height, unsigned width)
{
for (unsigned y = 0; y < height; ++y) {
for (unsigned x = 0; x < width; ++x) {
std::cout << a[y * width + x] << ' ';
}
std::cout << '\n';
}
}
int main()
{
double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}};
print(&arr[0][0], 3, 3);
}
Naturally, a matrix is something that deserves a class of its own (but the above might still be relevant, if you need to write helper functions).
Since you are using C++, the proper way to do something like this would be with a custom class and some templates. The following example is rather rough, but it gets the basic point across.
#include <iostream>
using namespace std;
template <int matrix_size>
class SquareMatrix
{
public:
int size(void) { return matrix_size; }
double array[matrix_size][matrix_size];
void copyInverse(const SquareMatrix<matrix_size> & src);
void print(void);
};
template <int matrix_size>
void SquareMatrix<matrix_size>::copyInverse(const SquareMatrix<matrix_size> & src)
{
int inv_x;
int inv_y;
for (int x = 0; x < matrix_size; x++)
{
inv_x = matrix_size - 1 - x;
for (int y = 0; y < matrix_size; y++)
{
inv_y = matrix_size - 1 - y;
array[x][y] = src.array[inv_x][inv_y];
}
}
}
template <int matrix_size>
void SquareMatrix<matrix_size>::print(void)
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
cout << array[x][y] << " ";
}
cout << endl;
}
}
template <int matrix_size>
void Initialize(SquareMatrix<matrix_size> & matrix);
int main(int argc, char * argList[])
{
SquareMatrix<4> startMatrix;
SquareMatrix<4> inverseMatrix;
Initialize(startMatrix);
inverseMatrix.copyInverse(startMatrix);
cout << "Start:" << endl;
startMatrix.print();
cout << "Inverse:" << endl;
inverseMatrix.print();
return 0;
}
template <int matrix_size>
void Initialize(SquareMatrix<matrix_size> & matrix)
{
for (int x = 0; x < matrix_size; x++)
{
for (int y = 0; y < matrix_size; y++)
{
matrix.array[x][y] = (x+1)*10+(y+1);
}
}
}
Two dimensional array is not a pointer to pointer or something similar. The correct type for you startMatrix is double (*)[4]. For your function, the signature should be like:
MatrixInversion( double (*A)[4], int order, double (*B)[4] );
There is a solution using the pointer to point by bobobobo
William Sherif (bobobobo) used the C version and I just want to show C++ version of bobobobo's answer.
int numRows = 16 ;
int numCols = 5 ;
int **a ;
a = new int*[ numRows* sizeof(int*) ];
for( int row = 0 ; row < numRows ; row++ )
{
a[row] = new int[ numCols*sizeof(int) ];
}
The rest of code is the same with bobobobo's.
You can definitely do something like the code below, if you want.
template <typename T, int n>
class MatrixP
{
public:
MatrixP operator()(T array[][n])
{
for (auto i = 0; i < n; ++i) {
v_[i] = &array[i][0];
}
return *this;
}
operator T**()
{
return v_;
}
private:
T* v_[n] = {};
};
void foo(int** pp, int m, int n)
{
for (auto i = 0; i < m; ++i) {
for (auto j = 0; j < n; ++j) {
std::cout << pp[i][j] << std::endl;
}
}
}
int main(int argc, char** argv)
{
int array[2][2] = { { 1, 2 }, { 3, 4 } };
auto pa = MatrixP<int, 2>()(array);
foo(pa, 2, 2);
}
The problem is that a two-dimensional array is not the same as an array of pointers. A two-dimensional array stores the elements one row after another — so, when you pass such an array around, only a pointer to the start is given. The receiving function can work out how to find any element of the array, but only if it knows the length of each row.
So, your receiving function should be declared as void MatrixInversion(double A[4][], int order, double B[4][]).
by nice coding if c++:
struct matrix {
double m[4][4];
};
matrix startMatrix;
matrix inverseMatrix;
so the interface would be
void MatrixInversion(matrix &A, int order, matrix &B);
and use it
MatrixInversion(startMatrix, 4, inverseMatrix);
The benefit
the interface is very simple and clear.
once need to modify "m" of matrix internally, you don't need to update the interface.
Or this way
struct matrix {
void Inversion(matrix &inv, int order) {...}
protected:
double m[4][4];
};
matrix startMatrix;
matrix inverseMatrix;
...
An ugly way in c
void MatrixInversion(void *A, int order, void *B);
MatrixInversion((void*)startMatrix, 4, (void*)inverseMatrix);
EDIT: reference code for MatrixInversion which will not crash:
void MatrixInversion(void *A, int order, void *B)
{
double _a[4][4];
double _b[4][4];
memcpy(_a, A, sizeof _a);
memcpy(_b, B, sizeof _b);
// processing data here
// copy back after done
memcpy(B, _b, sizeof _b);
}

Is there a way to initialize an array with non-constant variables? (C++)

I am trying to create a class as such:
class CLASS
{
public:
//stuff
private:
int x, y;
char array[x][y];
};
Of course, it doesn't work until I change int x, y; to
const static int x = 10, y = 10;
Which is impractical, because I am trying to read the values of x and y from a file. So is there any way to initialize an array with non-contant values, or declare an array and declare its size on different statements? And I know this would probably require the creation of an array class, but I'm not sure where to start on this, and I don't want to create a 2D dynamic list when the array itself is not dynamic, just the size is not known at compile-time.
use vector.
#include <vector>
class YourClass
{
public:
YourClass()
: x(read_x_from_file()), y(read_y_from_file())
{
my_array.resize(x);
for(int ix = 0; ix < x; ++ix)
my_array[ix].resize(y);
}
//stuff
private:
int x, y;
std::vector<std::vector<char> > my_array;
};
The compiler need to have the exact size of the class when compiling, you will have to use the new operator to dynamically allocate memory.
Switch char array[x][y]; to char** array; and initialize your array in the constructor, and don't forget to delete your array in the destructor.
class MyClass
{
public:
MyClass() {
x = 10; //read from file
y = 10; //read from file
allocate(x, y);
}
MyClass( const MyClass& otherClass ) {
x = otherClass.x;
y = otherClass.y;
allocate(x, y);
// This can be replace by a memcopy
for( int i=0 ; i<x ; ++i )
for( int j=0 ; j<x ; ++j )
array[i][j] = otherClass.array[i][j];
}
~MyClass(){
deleteMe();
}
void allocate( int x, int y){
array = new char*[x];
for( int i = 0; i < y; i++ )
array[i] = new char[y];
}
void deleteMe(){
for (int i = 0; i < y; i++)
delete[] array[i];
delete[] array;
}
MyClass& operator= (const MyClass& otherClass)
{
if( this != &otherClass )
{
deleteMe();
x = otherClass.x;
y = otherClass.y;
allocate(x, y);
for( int i=0 ; i<x ; ++i )
for( int j=0 ; j<y ; ++j )
array[i][j] = otherClass.array[i][j];
}
return *this;
}
private:
int x, y;
char** array;
};
*EDIT:
I've had the copy constructor
and the assignment operator
Not in that manner, as in c++, c-style array sizes have to be known at compile time, with some vendor specific extensions allowing certain runtime sizes (to enhance compatibility with C99), but not in the situation you are describing (if you are interested, here's a description). The easiest thing to do would be:
std::vector< std::vector<char> > array;
And apply the size in the constructor:
array.resize(x);
for(std::vector< std::vector<char> >::iterator curr(array.begin()),end(array.end());curr!=end;++curr){
curr->resize(y);
}
There are many advantages of vector over c style arrays, see here
Put all the memory into one block.
Because it is private you can then get your access methods to retrieve the correct value.
Quick example:
#include <vector>
#include <iostream>
class Matrix
{
public:
class Row
{
public:
Row(Matrix& p,unsigned int x)
:parent(p)
,xAxis(x)
{}
char& operator[](int yAxis)
{
return parent.data(xAxis,yAxis);
}
private:
Matrix& parent;
unsigned int xAxis;
};
Matrix(unsigned int x,unsigned int y)
:xSize(x)
,ySize(y)
,dataArray(x*y)
{}
Matrix::Row operator[](unsigned int xAxis)
{
return Row(*this,xAxis);
}
char& data(unsigned int xAxis,unsigned int yAxis)
{
return dataArray[yAxis*xSize + xAxis];
}
private:
unsigned int xSize;
unsigned int ySize;
std::vector<char> dataArray;
};
int main()
{
Matrix two(2,2);
two[0][0] = '1';
two[0][1] = '2';
two[1][0] = '3';
two[1][1] = '4';
std::cout << two[1][0] << "\n";
std::cout << two.data(1,0) << "\n";
}
Take a look at boost::multi_array.
You can't allocate or initialize a global or static array declaratively using non-constant values (compile-time). It's possible for local arrays though (C99 variable sized arrays, as their initializer essentially runs at runtime every time the function is executed).
For your situation, I suggest using a pointer instead of an array and create the actual array dynamically at runtime (using new):
class CLASS
{
public:
CLASS(int _x, int _y) : x(_x), y(_y) {
array = new char*[x];
for(int i = 0; i < x; ++i)
array[i] = new char[y];
}
~CLASS() {
for (int i = 0; i < x; ++i)
delete[] array[i];
delete[] array;
}
//stuff
private:
int x, y;
char **array;
};
You can allocate memory to your 2-dimensional array in the constructor and free it in the destructor. The simplest way:
array = (char **)malloc(sizeof(char *) * x);
if (array) {
for (i = 0; i < x; i++) {
array[i] = (char *)malloc(sizeof(char) * y);
assert(array[i]);
}
}
If the size is not known at compile time, the array is dynamic. What you could do to keep it static is to make them larger than your largest expected size.
If you want a dynamically sized array as a class member, you need to array new it and assign that value to a pointer. The char array[size] syntax is only for statically-sized arrays.
Better yet, you really should use an std::vector< std::vector<char> >, there are very few good reasons to manually work with dynamically sized arrays these days.