C++: Two Dimensional Array as class member - c++

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?

Related

Question regarding initialization of an array

My problem:
I have the following piece of code that is a wrapper for 2D square matrices in order to transpose them and print them. I cannot understand why we can write this:
arrayNN(T DATA[N][N]){
n = N;
data = DATA; }
In particular this line of code:data = DATA;.
My thoughts:
As far as i know, in C/C++ you cannot give the values of a matrix to another matrix. For example this piece of code doesn't work, no matter how we write the definition of b:
double array[3][3] = { {11,12,13},{21,22,23},{31,32,33}};
//only one definition
//double **b;
//double *b[3]
double b[3][3];
b = array;
Code: It works.
#include <iostream>
using namespace std;
template <typename T, size_t N>
class arrayNN {
private:
int n;
T (*data)[N]; # a vector of N elements of pointers to datatype T = 2d matrix
public:
arrayNN(): n(N), data(NULL) {};
arrayNN(T DATA[N][N]){
n = N;
data = DATA;
}
void print(ostream &out){
for(int i = 0;i<N;i++){
for(int j=0;j<N; j++){
cout << data[i][j] << '\t';
}
cout << endl;
}
}
void transpose(){
for(int i = 0;i<N;i++){
for(int j=0;j<i; j++){
T temp = data[i][j];
data[i][j] = data[j][i] ;
data[j][i] = temp;
}
}
}
};
int main(){
double array[3][3] = { {11,12,13},{21,22,23},{31,32,33}};
arrayNN<double,3> A(array);
A.print(cout);
A.transpose();
A.print(cout);
return 0;
}
T (*data)[N]; # a vector of N elements of pointers to datatype T = 2d matrix
No, data is not a vector or an array. Instead it is a pointer to an array of size N with elements of type T.
This means that when you wrote data = DATA; you're actually assigning the pointer DATA to the pointer data. Note that the function parameter DATA is a pointer and not an array. You can refer to What is array to pointer decay? for seeing why DATA is a pointer.

how to copy Int array to int pointer using constructor in C++

I am trying to insert int array x to int *v. here is my code . please provide me with optimal solutions and the reason behind it.
there is an error in this line. Instead of copying array value its taking garbage value. line v1=x;
class vector
{
int *v;
int size;
public:
vector(int m)
{
v = new int[size = m];
for (int i = 0; i < size; i++)
v[i] = 0;
}
vector(int *a)
{
for (int i = 0; i < size; i++)
v[i] = a[i];
}
int operator *(vector &y)
{
int sum = 0;
for (int i = 0; i < size; i++)
sum += v[i] * y.v[i];
return sum;
}
void disp()
{
for (int i = 0; i < size; i++)
cout << v[i] << " ";
cout << "\n";
}
};
int main()
{
clrscr();
int x[3] = { 1,2,3 };
int y[3] = { 4,5,6 };
vector v1(3);
//v1.disp();
vector v2(3);
v2.disp();
v1 = x;
v1.disp();
//v2=y;
v2.disp();
int r = v1 * v2;
cout << "R = " << r;
getch();
return 0;
}
You forgot to add the assignment operator in your vector class:
vector & operator=(int *a)
{
for (int i = 0; i < size; i++)
v[i] = a[i];
return *this;
}
In the the line
v1=x;
May be, you are expecting it to invoke the second constructor which takes int* as argument. But it won't happen.
It can be seen as Type Conversion from Basic type to Class type. where we expect appropriate constructor will get invoked.
see http://www.hexainclude.com/basic-to-class-type-conversion/
But remember, Constructor will be invoked only once after the creation of object.
Here, in the line
vector v1(3);
the first constructor was already invoked. Then the line
v1=x;
won't invoke the second constructor now.
For every class, = operator is default overloaded . That is the reason why we can easily assign objects to one another.
Therefore, the line v1=x invokes default overloaded assignment = operator.
Here, it treats address of array x i.e., &x[0] as address of class object. As it is not address of vector class object
=> it results a Segmentation fault.
YOUR ANSWER
To assign int array to int pointer i.e., to the member variable int* v of the vector class,
overload assignment operator = inside the class .
or
Initialize the class object to array in first line itself. i.e.,
vector v1=x; // modify the class constructor to have size as a constant.

Void pointer to a class object: Initialization inside a function

I am trying to create a void pointer to a class object and have it be initialized inside a function. Unfortunately, the array member of the class cannot escape the function i.e. it cannot be accessed after initialization.
In the code below, the first call to print positions (inside the initialize function) works properly, however, the second call to print positions from outside the initialization function fails. I have a feeling that the array object created in the initialization function is destroyed and not passed along but I am not sure and also don't know how to fix it.
Any help would be greatly appreciated.
#include <iostream>
#include <iomanip>
#include <string>
class Atoms
{
double * positions;
int nAtoms;
public:
// Standard constructor prividing a pre-existant array
Atoms(int nAtoms, double * positionsArray)
{
this->nAtoms = nAtoms;
this->positions = positionsArray;
}
// Print positions to screen
void print_positions()
{
std::cout<< "nAtoms: " << this->nAtoms << std::endl;
int nDim = 3;
for (int i = 0; i < nAtoms; i++)
{
for (int j = 0; j < nDim; j++)
{
std::cout << std::setw(6) << this->positions[i * nDim + j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
};
void initialize_Atoms_void_pointer(void ** voidAtomsPointer)
{
//Create a new instance of Atoms by a pointer
int numAtoms = 5;
int numDim = 3;
int elemN = numAtoms * numDim;
double data_array[elemN];
for (int i = 0; i < numAtoms; i++)
for (int j = 0; j < numDim; j++)
{
data_array[i * numDim + j] = i * numDim + j + 10;
}
Atoms *atoms = new Atoms(numAtoms, data_array);
// Set the vPointer that the void pointer points to a pointer to Atoms object
*voidAtomsPointer = static_cast<void *>(atoms);
//Test call
std::cout << std::endl << "Initializing atoms" << std::endl;
static_cast<Atoms *>(*voidAtomsPointer)->print_positions();
}
void print_Atoms_pointer_positions(void * voidAtomsPointer)
{
//Cast the pointer as an atoms pointer
Atoms *atomsPointer = static_cast<Atoms *>(voidAtomsPointer);
atomsPointer->print_positions();
}
int main()
{
//Use the initializer function for getting a pointer
void *testVoidAtomsPointer;
initialize_Atoms_void_pointer(&testVoidAtomsPointer);
print_Atoms_pointer_positions(testVoidAtomsPointer);
}
The problem is that in
Atoms *atoms = new Atoms(numAtoms, data_array);
data_array is a local array, which is destroyed when initialize_Atoms_void_pointer quits.
Instead of copying the raw pointer, make a new allocation in Atoms's constructor and copy the content:
Atoms(int nAtoms, double * positionsArray)
{
this->nAtoms = nAtoms;
this->positions = new double[nAtoms];
for (int ii = 0; ii < nAtoms; ++ii)
this->positions[ii] = positionsArray[ii];
}
~Atoms()
{
delete[] this->positions;
}
A safer implementation would include the use of a std::unique_ptr, which will automatically de-allocate the memory for you when Atoms is destroyed:
#include <memory>
class Atoms {
std::unique_ptr<double[]> positions;
// ...
public:
Atoms(int nAtoms, double * positionsArray) :
positions(new double[nAtoms]) {
this->nAtoms = nAtoms;
for (int ii = 0; ii < nAtoms; ++ii)
this->positions[ii] = positionsArray[ii];
}
// ...
};
You'd need also to check if nAtoms is 0 or negative, if the input array is null, etc., but I think it falls out of the scope of the question.
If you need to access the raw pointer, you can use the positions.get() method (do not try to delete it or your application will crash due to a double delete).
Update
Of course, another more straightforward solution is simply to use a std::vector<double> instead ;)
#include <vector>
class Atoms {
std::vector<double> positions;
// int nAtoms; -- no longer necessary
public:
Atoms(int nAtoms, double * positionsArray) :
positions(nAtoms) {
for (int ii = 0; ii < nAtoms; ++ii)
this->positions[ii] = positionsArray[ii];
}
// ...
};
If you need to access the raw pointer, you can use the positions.data() method (do not try to delete it or your application will crash due to a double delete). The number of atoms can be checked using positions.size().
As mentioned in a comment, if the only purpose of the Atoms class is to store doubles but not to add any other operation, then just forget about it and directly use the std::vector<double>.

How can you print a dynamic array in C++?

Below is my current code for my latest assignment and I cannot figure out what the problem is printing the array. Forgive me for the crappy code, in my class we were thrown into C++ and none of us have ever used it before so it may be a simple mistake but no one in the house can help me.
Header file DynamicArray.h:
//
// DynamicArray.h
///#include <rpcndr.h>
#ifndef DYNAMIC_DYNAMICARRAY_H
#define DYNAMIC_DYNAMICARRAY_H
#endif //DYNAMIC_DYNAMICARRAY_H
// union
// intersection
// relative complement
// insertion - if the element is already in the set, then nothing happens
// deletion - if the element is not in the set, then nothing happens
// query to check whether an element is in a set
// query to find the number of number of elements in a set
// display the set
//destructor
// copy constructor
// ***********************************overloading assignment operator***************************************************
class DynamicArray{
public:
DynamicArray(int size);
DynamicArray(const DynamicArray &original, int Size);
/// DynamicArray(int Size);
~DynamicArray();
void Union();
void Intersection();
void Complement();
int Insert(int position, int entry, int size);
int Delete(int position, int entry, int size);
bool Qelement(int size, int entry);
int Qset(int size);
int size = 20;
int *array;
};
//
//
//
Source file DynamicA.cpp- here I define the constructors and member functions:
//
// DynamicA.cpp
//
//Union();
//Intersection();
//Complement();
//Insert();
//Delete();
//Qelement();
//Qset();
#include <iostream>
#include "DynamicArray.h"
using namespace std;
DynamicArray::DynamicArray(int &size = 30){
size = 20;
*array = new int[size];
for(int i = 0; i < size; i++){
array[i] = 0;
};
}
/// DynamicArray::DynamicArray(int Size) {
///
/// }
DynamicArray::DynamicArray(const DynamicArray &original, int size) {
size = original.size;
array = new int[size];
for (int i = 0; i < size; i++) {
array[i] = original.array[i];
}
}
DynamicArray::~DynamicArray(){
delete[] array;
}
void DynamicArray::Union(){
}
void DynamicArray::Intersection() {
}
void DynamicArray::Complement(){
}
int DynamicArray::Insert(int position, int entry, int size) {
if(!Qelement()){
for(int i = size+1; i > position+1; i--){
array[i] = array[i-1];
}
array[position] = entry;
}
}
int DynamicArray::Delete(int position, int entry, int size){
for(int i = 0; i < size; i++){
if(array[i] == entry) {
for(int x = i; x < size; i++){
array[x] = array[x+1];
}
size--;
}
}
}
bool DynamicArray::Qelement(int size, int entry) {
for(int i = 0; i < size; i++){
if(array[i] == entry){
return true;
}
}
}
int DynamicArray::Qset(int size){
return size;
}
main.cpp - this is where my issue is. The error I continue to receive is that dArray is not an array.
//main.cpp
#include <iostream>
//#include <DynamicArray.h>
#include "DynamicArray.h"
//#include "DynamicA.cpp"
//using namespace std;
int main() {
DynamicArray dArray();
for(int i = 0; i < array; i++) {
cout << dArray[i];
}
}
Your class DynamicArray is not an array, the compiler has it right. It's just a class you've defined. For your code to work, you need to overload DynamicArray::operator[](int), for example, like so:
#include <cassert>
int DynamicArray::operator[](int idx)
{
assert(idx < size);
return array[i];
}
The reason is that operator[] is only defined for the built-in array type, where it has an established meaning and understood by the compiler. But you have defined an arbitrary class, and your understanding that it is an array is only your understanding, i.e. an assumption, which in no way is perceived by the compiler, so to say.
Now, let me point this one out before you run into issues caused by that mistake: the fields size and array must be private or at least protected! Read up on encapsulation in C++, as well as the other two or three founding principles of this language. You may wonder how to access the size of the array form the outside given this change, well that's where the so-called getter-setter methods come into play. Define int DynamicArray::size() const { return size; } to let the array tell its size to its clients.
Now you can use the previously defined operator[](int) with int size():
DynamicArray myArray(5);
for(int i = 0; i < myArray.size(); ++i)
std::cout << myArray[i] << " ";
Other errors: two pointed out by#crashmstr: *array = new int[size]; should be array = new int[size]; and DynamicArray myArray(); isn't going to build, since this calls the undefined default constructor.

second Constructor called in c++ ( wrong output)

I am trying to do a simple thing but suddenly stuck in between .
Here in my code I am trying to call a constructor in which i would only pass the length, my first constructor initializes an array of size = length with all elements 0.
Then i am passing the array to the constructor to give the previously defined array its values
here is the sample :
class myvector
{
int *arr;
int length;
public :
myvector(int);
myvector(int *);
};
myvector :: myvector (int len)
{
arr = new int [length = len];
for ( int i=0;i< length;i++)
{
arr[i] = 0;
}
}
myvector :: myvector ( int *ex)
{
for ( int i=0;i< length;i++)
{
cout << ex[i] << " " << length <<" ";
arr[i] = ex[i];
cout << arr[i]<< " ";
}
}
int main()
{
myvector v1(5);
int x[5] = {2,3,4,45,6};
v1 = x;
}
Here in my second constructor length which was defined in first constrcutor lost its values , also array arr loses its values
Did I do something ?
Please elaborate me on this
I don't think you quite get what the circumstances are in which constructors are invoked. The line v1 = x doesn't put the values into the memory allocated during the first constructor call. Rather, it constructs a new myvector (using the second constructor) and copies it into v1. The stuff you do during the first constructor call is lost.
It sounds like you want to define an assignment operator, not a constructor taking an int* argument. Also, in general you should declare single-argument constructors as explicit to prevent this sort of thing from happening accidentally.
First of all, when specifying a size of array like this, you should provide a constant value. See here. And I really encourage you to use std::vector<> for such tasks.
But anyway, like Sneftel mentioned, seems like you want to define an assignment operator (see here for more information about overloading operators in tasks like yours).
Here how I'd implemented it(NOT and ideal solution, but it works, and gives a basic idea):
#include <iostream>
using namespace std;
class myvector
{
int *arr;
int length;
public :
//I completely removed second constructor
myvector(int);
~myvector();
void operator=(const int* otherArray);
void printArray();
};
myvector::myvector (int len)
{
length = len;
arr = new int[length]; // This is the way, how you can handle a non constant array sizes
for ( int i=0;i< length;i++)
{
arr[i] = 0;
}
}
void myvector::printArray()
{
for(unsigned i = 0; i < length; ++i)
cout<<"arr["<<i<<"] = "<<arr[i]<<endl;
}
//Here's an overloaded '=' operator.
//int x[5] = {2,3,4,45,6};
//myvector v;
//v = x; - here this function is called
void myvector::operator=(const int* otherArray)
{
for(unsigned i = 0; i < length; ++i)
arr[i] = otherArray[i];
}
myvector::~myvector()
{
delete []arr; // You should ALWAYS delete what you allocated with new
}
int main()
{
myvector v1(5);
int x[5] = {2,3,4,45,6};
v1 = x;
v1.printArray();
}