So I count with the following excerpt of code:
template<class DT>
class AdjMat
{
protected:
DT** myMatrix;
int noOfNodes;
int noOfEdges;
public:
AdjMat(int _noOfNodes, int _noOfEdges);
//Destructor, constructors and other methods
};
template<class DT>
AdjMat<DT> :: AdjMat(int _noOfNodes, int _noOfEdges)
{
myMatrix = new DT*[_noOfNodes+1];
for(int i = 0; i < _noOfNodes+1; i++)
{
myMatrix[i] = new DT[_noOfNodes+1];
for(int j = 0; j < noOfNodes+1; j++)
myMatrix[i][j] = 0;
}
noOfNodes = _noOfNodes;
noOfEdges = _noOfEdges;
}
int main()
{
adjMat<int> m(5, 9);
}
The problem occurs in the constructor. The array doesn't seem to be initialized at all and much less the inner arrays, I have tried to go in different ways, but it won't initialize anything. Could anyone give me a hint of whatever I am doing wrong?
The error is in this line.
for(int j = 0; j < noOfNodes+1; j++)
noOfNodes has not been initialized yet. You probably meant:
for(int j = 0; j < _noOfNodes+1; j++)
You can avoid such errors by following a safer practice. Initialize as many members as you can in the initializer list.
template<class DT>
AdjMat<DT> :: AdjMat(int _noOfNodes, int _noOfEdges) : noOfNodes(_noOfNodes),
noOfEdges(_noOfEdges),
myMatrix(new DT*[_noOfNodes+1])
{
for(int i = 0; i < noOfNodes+1; i++)
{
myMatrix[i] = new DT[noOfNodes+1];
for(int j = 0; j < noOfNodes+1; j++)
myMatrix[i][j] = 0;
}
}
Related
When I use a string type dynamic 2D array, there is memory leak after deleting the array.
Please view the following code:
#include <string>
using namespace std;
#define NEW2D(H, W, TYPE) (TYPE **)new2d(H, W, sizeof(TYPE))
void* new2d(int h, int w, int size)
{
register int i;
void **p;
p = (void**)new char[h*sizeof(void*) + h*w*size];
for(i = 0; i < h; i++)
{
p[i] = ((char *)(p + h)) + i*w*size;
}
return p;
}
If I use the following code:
string** pstr = NEW2D(2, 4, string);
memset(pstr[0], 0, sizeof(string)*2*4);
delete [] pstr;
There is no memory leak; however, if I use the following code:
string** pstr = NEW2D(2, 4, string);
memset(pstr[0], 0, sizeof(string)*2*4);
for (int j = 0; j < 2; j++)
for (int i = 0; i < 4; i++)
pstr[j][i] = "test";
for (int j = 0; j < 2; j++)
for (int i = 0; i < 4; i++)
pstr[j][i].clear();
delete [] pstr;
The memory leak is happened, even if I have called pstr[j][i].clear().
What should I do to avoid memory leak after having
for (int j = 0; j < 2; j++)
for (int i = 0; i < 4; i++)
pstr[j][i] = "test";
in my code?
The problem with your code because it treats non-trivial types like std::string as if they were trivial. Probably you could create something using placement new that was legal C++ and worked in a similar way to the code you've written
But here's an simple alternative that (hopefully) works
template <typename T>
T** new2d(int h, int w)
{
T** p = new T*[h];
T* q = new T[h*w];
for (int i = 0; i < h; i++)
p[i] = q + i*w;
return p;
}
And to delete
template <typename T>
void free2d(T** p, int h)
{
if (h > 0)
delete[] p[0];
delete[] p;
}
Untested code.
Thanks to John. I have tried the following code, it works well:
int i;
int data_height = 2, data_width = 4;
string **data;
data = new string*[data_height];
for(i = 0; i < data_height; i++)
data[i] = new string[data_width];
for (int j = 0; j < 2; j++)
for (int i = 0; i < 4; i++)
data[j][i] = "test";
for(i = 0; i < data_height; i++)
delete [] data[i];
delete [] data;
First of all, I made this class.
class Matrix
{
public:
double ele[4][4];
int numOfRow;
int numOfColumns;
public:
Matrix() {
numOfRow = 0;
numOfColumns = 0;
ele[4][4] = 0;
}
Matrix(double mat[][4], int Row, int Col) {
numOfRow = Row;
numOfColumns = Col;
for (int i = 0; i < numOfRow; i++) {
for (int j = 0; i < numOfColumns; j++) {
ele[i][j] = mat[i][j];
}
}
}
Matrix Add(Matrix m) {
Matrix output;
for (int i = 0; i < numOfRow; i++) {
for (int j = 0; j < numOfColumns; j++) {
output.ele[i][j] = ele[i][j] + m.ele[i][j];
}
}
return output;
}
Matrix Subtract(Matrix m);
Matrix Multiply(Matrix m);
Matrix Transpose(void);
};
This is part of the main function. In this way, I'm going to bring up the values of the txt files that I've already made in matA and matB and replace them. It's just a process of putting numbers in.
double matA[4][4];
for (int i = 0; i < RowA; i++) {
for (int j = 0; j < ColA; j++) {
fscanf(fpInput, "%lf", &matA[i][j]);
}
}
double matB[4][4];
for (int i = 0; i < RowB; i++) {
for (int j = 0; j < ColB; j++) {
fscanf(fpInput, "%lf", &matB[i][j]);
}
}
And we substitute matrixA and matrixB class objects, respectively.
Matrix matrixA(matA, RowA, ColA);
Matrix matrixB(matB, RowB, ColB);
I tried substitute Value obtained by 'Add' function into class object called matrixO. but, The substituted values did not work smoothly. For example, if matrixA contains (1, 2, 3) in order and matrixB has (4, 5, 6), then the 'add function' requires that the array of matrixO contains (5, 7, 9), but it does not. The value of the matrixO.ele is not output at all.
Matrix matrixO = matrixA.Add(matrixB);
for (int i = 0; i < RowA; i++) {
for (int j = 0; j < ColA; j++) {
fprintf(fpOutput, "%lf ", matrixO.ele[i][j]);
printf("%lf", matrixO.ele[i][j]);
}
fprintf(fpOutput, "\n");
}
In the Matrix constructor section, I changed it like this.
public:
Matrix() {
numOfRow = 0;
numOfColumns = 0;
ele[4][4] = ele[0][0];
}
public:
Matrix() {
numOfRow = 0;
numOfColumns = 0;
ele[4][4] = {};
}
But both of these cases are wrong. How do we solve this issue?
You are assigning a value to your matrix out-of-bounds:
ele[4][4] = 0;
The last element of double ele[4][4]; is ele[3][3];
This is undefined behavior, so it makes no sense to analyze what happens after it.
You can 0-initialize your Matrix in its constructor like this:
Matrix(): ele(), numOfRow(), numOfColumns() {}
I am trying to write a matrix class for linear algebra calculations. I have almost finished writing what I wanted. but I have a little trouble in creating a constructor that uses list initialization to create a matrix.
this is my class data members:
template <typename T>
class Matx
{
private:
// data members
//rows and columns of matrix
int rows, cols;
//pointer to pointer to type T
T** matrix;
and this is my code for initialization:
template <typename T>
Matx<T>::Matx(T* ptM[], int m, int n) : rows(m), cols(n)
{
matrix = new T*[rows];
for (int i = 0; i < rows; i++)
matrix[i] = new T[cols];
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
matrix[i][j] = *(ptM[i] + j);
}
in main:
double mat[][5] = { {5,5,-1,7,54},{4,-9,20,12,-6},{9,-18,-3,1,21},{ 61,-8,-10,3,13 },{ 29,-28,-1,4,14 } };
double* pm[5];
for (int i=0;i<5;i++)
pm[i]=mat[i];
Matx<double> yourMat = Matx<double>(pm, 5,5);
but I think there is a better way to do it.
what I want is to be able to initialize it like arrays. something like this:
Matx<double> yourMat = { {5,5,-1,7,54},{4,-9,20,12,-6},{9,-18,-3,1,21},{ 61,-8,-10,3,13 },{ 29,-28,-1,4,14 } };
Is it possible?
It is definitely possible, I have made constructors that use initializer lists for similar classes. A constructor like this should do the job:
template <typename T>
Matx<T>::Matx(std::initializer_list<std::initializer_list<T>> listlist) {
rows = (int)(listlist.begin())->size();
cols = (int)listlist.size();
matrix = new T*[rows];
for (int i = 0; i < rows; i++) {
matrix[i] = new T[cols];
for (int j = 0; j < cols; j++) {
matrix[i][j] = ((listlist.begin()+i)->begin())[j];
}
}
}
For anyone with similar issue, this version has some minor corrections to the other answer. Tried this and it works in gcc 7.3, ubuntu 16.04.
template <typename T>
Matx<T>::Matx(std::initializer_list<std::initializer_list<T>> listlist) {
rows = (int)(listlist.begin())->size(); /* pointer correction here */
cols = (int)listlist.size();
matrix = new T*[rows];
for (int i = 0; i < rows; i++) {
matrix[i] = new T[cols];
for (int j = 0; j < cols; j++) {
matrix[i][j] = ((listlist.begin()+i)->begin())[j]; /* again minor correction */
}
}
}
I am trying to create a 2d array pointer with my own class, Tile, as type. I have looked at the code example at How do I declare a 2d array in C++ using new?. The following code works perfectly:
int** ary = new int*[sizeX];
for(int i = 0; i < sizeX; ++i)
ary[i] = new int[sizeY];
for(int i = 0; i < 8; i++)
for(int j = 0; j < 8; j++)
ary[i][j] = 5;
for(int i = 0; i < 8; i++)
for(int j = 0; j < 8; j++)
cout << ary[i][j];
However when I try to change type from int to my own class, Tile, I get an
No viable overloaded '='
error in XCode, and I can't figure out what this means. I use the following code:
Tile** t;
t = new Tile*[8];
for(int i = 0; i < 8; ++i)
t[i] = new Tile[8];
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
t[i][j] = new Tile(new NoPiece());
}
}
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
cout << (t[i][j].get_piece()).to_string();
}
}
Here is the code for Tile.cpp:
#include "Tile.h"
Tile::Tile() {
}
Tile::Tile(Piece p) {
piece = &p;
}
Piece Tile::get_piece() {
return *piece;
}
And the code for Tile.h:
#include <iostream>
#include "Piece.h"
class Tile {
Piece * piece;
public:
Tile();
Tile(Piece p);
Piece get_piece();
};
The difference between two code snippets is that the one using int treats array elements like values, i.e. assigns
ary[i][j] = 5;
while the one using Tile treats array elements like pointers:
t[i][j] = new Tile(new NoPiece()); // new makes a pointer to Tile
Change the assignment to one without new to fix the problem:
t[i][j] = Tile(new NoPiece());
There is nothing wrong to making a 2D array of pointers, too - all you need is to declare it as a "triple pointer", and add an extra level of indirection:
Tile*** t;
t = new Tile**[8];
for(int i = 0; i < 8; ++i)
t[i] = new Tile*[8];
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
t[i][j] = new Tile(new NoPiece());
}
}
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
cout << (t[i][j]->get_piece()).to_string();
}
}
// Don't forget to free the tiles and the array
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
delete t[i][j];
}
delete[] t[i];
}
How can I create a array with dinamic size like this:
int sentLen = sentences.size();
double a[sentLen][sentLen];
for (int i = 0; i < sentLen; i++)
{
for (int j = 0; j < sentLen; j++)
{
a[i][j] = somefunction(i, j);
}
}
My research led me to malloc which isn't recommended or other too complicated methods. After I realised that size must be constant, I tried using unordered_map, and I have tried the following:
std::unordered_map <int, int, double> a;
for (int i = 0; i < sentLen; i++)
{
for (int j = 0; j < sentLen; j++)
{
a.insert({ i, j, somefunc(i, j) });
}
}
but still unsuccessful.
You don't really want to use arrays.
std::vector<std::vector<double>> a{
sentLen, std::vector<double>{ sentLen, 0.0 } };
for (int i = 0; i < sentLen; ++i)
{
for (int j = 0; j < sentLen; ++j)
{
a[i][j] = somefunc(i, j);
}
}
You're getting an error because you can't use variables as static array sizes. They must be known at compile time. You have to allocate dynamically or use a vector instead.