I have an array transpose function that mirrors arrays like so:
[1][2][3] [1][4][7]
[4][5][6] ===> [2][5][8]
[7][8][9] [3][6][9]
Here is the concept of the algorithm I came up:
size_t numvars = variables.size(), numsegs = segments.size();
for (int v = 0; v < numvars; ++v) {
for (int s = 0; s < numsegs; ++s) {
float * row = in + (s * numvars);
out[v][s] = *(row + v);
}
}
When proceeding through the algorithm by hand, all works as expected. I would like to implement the function such that it takes two pointers to two-dimensional arrays, one with the source array and the second to a memory buffer that will hold the transposed array. When I try to implement the algorithm in C++ in a function I get the following error:
void transposeArray(float * in, float * out) throw()
{
size_t numvars = variables.size(), numsegs = segments.size();
for (int v = 0; v < numvars; ++v) {
for (int s = 0; s < numsegs; ++s) {
float * row = in + (s * numvars);
out[v][s] = *(row + v);
}
}
}
out[v][s] = *(row + v);
invalid types ‘float[int]’ for array subscript
Is this because the compiler does not know that it should treat the second float * out as a 2-dimensional array? If so, what's the fix?
Well, your out variable is a pointer to a float, so derefencing it in out[v] yields a float value. And you can't subscript a float value.
What you need to do, is to calculate the array index for the out 2D array the same way you calculated it for the in 2D array:
void transposeArray(float * in, float * out) throw() {
size_t numvars = variables.size(), numsegs = segments.size();
for (int v = 0; v < numvars; ++v) {
for (int s = 0; s < numsegs; ++s) {
out[v*numsegs + s] = in[s*numvars + v];
}
}
}
Note:
It's a pity that you are apparently writing this code in C++, and not in C. Because in C, you can do this in a quite nice way:
void transposeArray(int numvars, int numsegs, float (*in)[numvars], float (*out)[numsegs]) {
for (int v = 0; v < numvars; ++v) {
for (int s = 0; s < numsegs; ++s) {
out[v][s] = in[s][v];
}
}
}
The trick here is that the in and out arguments are declared to be pointers to line arrays, which allows the language to invoke the same pointer arithmetic magic that it uses when you declare an array with float myArray[numvars][numsegs];. This pointer arithmetic boils down to do the same thing implicitly which v*numsegs + s does explicitly.
The advantage of C is, that it allows for array types with run time sizes, something C++ does not do. Of course, if numvars and numsegs are compile time constants, you can do the equivalent in C++.
Here is how you can write your function if you want to use the same function signature as the one you gave in the question:
void transposeArray(float * in, float * out) throw() {
size_t numvars = variables.size(), numsegs = segments.size();
float (*in2D)[numvars] = (void*)in;
float (*out2D)[numsegs] = (void*)out;
for (int v = 0; v < numvars; ++v) {
for (int s = 0; s < numsegs; ++s) {
out2D[v][s] = in2D[s][v];
}
}
}
The problem is already solved but I wanted to post a C++-ish solution to your 2D array handling problem. If you want to treat a pointer (basically a 1 dimensional array) as a 2D array whose size is known only at runtime then you could employ one of the following helper templates. They not only make your code look much nicer but they also help you to catch wrong out-of-range indexes in debug mode and in release they compile basically to the same code as your hand-written harder-to-read code. Today's C++ compilers are extremely good at optimizing away such simple methods/functions:
#include <assert.h>
#include <stdio.h>
// An implementation that performs range checking on both dimension and
// has nice array subscript syntax. This has some performance overhead
// in debug mode but in release the compiler does the optimization magic.
template <typename T>
class PtrArray2D
{
public:
class SubDim
{
public:
SubDim(T* p, int d1) : m_Ptr(p), m_D1(d1) {}
T& operator[](int d1)
{
assert(d1>=0 && d1<m_D1);
return m_Ptr[d1];
}
const T& operator[](int d1) const
{
assert(d1>=0 && d1<m_D1);
return m_Ptr[d1];
}
private:
T* m_Ptr;
int m_D1;
};
PtrArray2D(T* p, int d0, int d1) : m_Ptr(p), m_D0(d0), m_D1(d1) {}
SubDim operator[](int d0)
{
assert(d0>=0 && d0<m_D0);
return SubDim(m_Ptr + m_D1*d0, m_D1);
}
const SubDim operator[](int d0) const
{
assert(d0>=0 && d0<m_D0);
return SubDim(m_Ptr + m_D1*d0, m_D1);
}
int GetD0() const { return m_D0; }
int GetD1() const { return m_D1; }
private:
T* m_Ptr;
int m_D0;
int m_D1;
};
template <typename T>
inline PtrArray2D<T> MakePtrArray2D(T* p, int d0, int d1)
{
return PtrArray2D<T>(p, d0, d1);
}
template <typename T>
void Transpose(const PtrArray2D<T>& src, PtrArray2D<T>& dest)
{
assert(src.GetD0() == dest.GetD1() && src.GetD1() == dest.GetD0());
for (int i=0,i_e=src.GetD0(); i<i_e; ++i)
{
for (int j=0,j_e=src.GetD1(); j<j_e; ++j)
{
dest[j][i] = src[i][j];
}
}
}
int test()
{
const int DIMENSION0 = 5;
const int DIMENSION1 = 2;
const int ARRAY_SIZE = DIMENSION0*DIMENSION1;
float* p = new float[ARRAY_SIZE];
for (int i=0; i<ARRAY_SIZE; ++i)
p[i] = (float)i;
PtrArray2D<float> arr0(p, DIMENSION0, DIMENSION1);
printf("%f, %f, %f\n", arr0[0][0], arr0[0][1], arr0[1][0]);
arr0[1][0] = 8;
// The statement below will cause an assert as the second dimension is out of range.
//arr0[0][2];
float* q = new float[ARRAY_SIZE];
PtrArray2D<float> arr1(q, DIMENSION1, DIMENSION0);
Transpose(arr0, arr1);
// OR if you want to create helper array object on-the fly only for the time of execution of Transpose():
//Transpose(MakePtrArray2D(p, DIMENSION0, DIMENSION1), MakePtrArray2D(q, DIMENSION1, DIMENSION0));
printf("%f, %f, %f\n", arr1[0][0], arr1[0][1], arr1[1][0]);
return 0;
}
The compiler doesn't know the dimensions of the array.
So if you keep your simple pointers then you need to do the same addressing arithmetic for out as you currently do for in.
Namely, calculate a row pointer, use an offset into that row, instead of out[v][s].
Technically,
the expression out[v] produces a reference to a float, and
if the float is denoted f, the expression f[s] is then just invalid: you can't index a float value.
As general advice, unless you're using some framework that uses float everywhere, such as SFML, then just use double. That's the default floating point type in C and C++. E.g., the literal 3.14 is of type double, not float.
Related
Is there a way to implement an operator like [][] for a 1D array?
I want to change the implementation of a 2D vector to a 1D vector in my code (cause this increases the execution speed by about %50 in my program). 2D vector supports [y][x]. How can I have such functionality for a 1D vector?
I can do it like this:
const size_t Y_Axis { 20 };
const size_t X_Axis { 30 };
std::vector<char> vec( Y_Axis * X_Axis );
size_t row { 5 };
size_t col { 28 };
vec[ row * X_Axis + col ] = 't'; // assign a value to a specific row-column
However, typing this formula multiple times throughout a source file seems like violating DRY (don't repeat yourself). How can I do this in an efficient and idiomatic way? I want to hide the complexity and make things a bit abstracted just like operator[][] of 2D vector does.
C++ does not allow virtual containers. So the operator [] is expected to return a true object of the expected size, if you want all the goodies like true iterators to work smoothly.
Here is a post of mine about the iterator question for multi-dimensional containers and a more general question on Code Review
If you only want to build an operator[](int) that returns something that can accept a second [], it can easily be done for a 2D vector, by returning a plain pointer inside the internal data array of a vector:
template <typename T>
class vec2d {
std::vector<T> data;
size_t _cols;
public:
vec2d(int rows, int cols, T* src = nullptr)
: data(rows * cols), _cols(cols) {
if (src != nullptr) {
for (T& val : data) {
val = *src++;
}
}
}
T* operator [] (size_t row) {
return data.data() + row * _cols;
}
const T* operator [] (size_t row) const {
return data.data() + row * _cols;
}
size_t rows() const {
return data.size() / _cols;
}
size_t cols() const {
return _cols;
}
};
And here is an example usage:
int main() {
vec2d<char> v(3, 4, "ABCDEFGHIJKL");
for (size_t i = 0; i < v.rows(); i++) {
for (size_t j = 0; j < v.cols(); j++) {
std::cout << v[i][j] << ' ';
}
std::cout << "\n";
}
}
I am trying to compile ORBSLAM2 on Windows with Visual Studio 2015 vc14 x64 compiler. The project was originally developed for GNU GCC. I now have the following issue:
// Compute distances between them
const size_t N = vDescriptors.size();
float aDistances[N][N];
for(size_t i=0;i<N;i++) {
aDistances[i][i]=0;
for(size_t j=i+1;j<N;j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i],vDescriptors[j]);
aDistances[i][j]=distij;
aDistances[j][i]=distij;
}
}
I get the this error while compiling:
C2131 expression did not evaluate to a constant
... on this line of code:
const size_t N = vDescriptors.size();
Subsequently the two dimensional array definition fails too (float Distances[N][N];).
What's the best way to solve this in Visual-C++ ?
UPDATE: Here's the complete function code:
void MapPoint::ComputeDistinctiveDescriptors() {
// Retrieve all observed descriptors
vector<cv::Mat> vDescriptors;
map<KeyFrame*,size_t> observations;
{
unique_lock<mutex> lock1(mMutexFeatures);
if(mbBad)
return;
observations=mObservations;
}
if(observations.empty())
return;
vDescriptors.reserve(observations.size());
for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++) {
KeyFrame* pKF = mit->first;
if(!pKF->isBad())
vDescriptors.push_back(pKF->mDescriptors.row(mit->second));
}
if(vDescriptors.empty())
return;
// Compute distances between them
const size_t N = vDescriptors.size();
float aDistances[N][N];
for(size_t i=0;i<N;i++) {
aDistances[i][i]=0;
for(size_t j=i+1;j<N;j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i],vDescriptors[j]);
aDistances[i][j]=distij;
aDistances[j][i]=distij;
}
}
// Take the descriptor with least median distance to the rest
int BestMedian = INT_MAX;
int BestIdx = 0;
for(size_t i=0;i<N;i++) {
vector<int> vDists(aDistances[i], aDistances[i]+N);
sort(vDists.begin(),vDists.end());
int median = vDists[0.5*(N-1)];
if(median<BestMedian) {
BestMedian = median;
BestIdx = i;
}
}
{
unique_lock<mutex> lock(mMutexFeatures);
mDescriptor = vDescriptors[BestIdx].clone();
}
}
Your Problem
You tried to create a 2D array on the stack (this is not standard C++, even though it might work on some compilers). For this the size needs to be know at compile time, which is not the case as you call size() on an object which likely is not a constexpr.
QUICK FIX
A quick fix that works out of the box is to just allocate the memory on the heap (do not forget to delete array later on) by doing
float** aDistances = new float[N][N];
The deletion can be done in a function which looks like this
template <typename T>
void delete2DArray(T** ptr, size_t NumRows)
{
for (size_t i = 0; i < NumRows; i++)
{
delete[] ptr[i];
}
delete[] ptr;
}
FIX
You will haveto use dynamic memory allocation. For this you can try the following approach by adding a wrapper class around std::vector (this should be possible as you said the scope is very manageable)
template <typename T>
class Array2D
{
public:
Array2D(size_t numrows, size_t numcols) :
rows(numrows), columns(numcols), array2d(rows * columns)
{}
T& operator()(size_t row, size_t column)
{
return array2d[row * columns + column];
}
const T& operator()(size_t row, size_t column) const
{
return array2d[row * columns + column];
}
T* getRow(size_t row)
{
return &array2d[row * columns];
}
private:
size_t rows;
size_t columns;
std::vector<T> array2d;
};
Than you have to modify your code like this:
// Compute distances between them
const size_t N = vDescriptors.size();
Array2D<float> aDistances(N,N);
for (size_t i = 0; i < N; i++) {
aDistances(i,i) = 0;
for (size_t j = i + 1; j < N; j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i], vDescriptors[j]);
aDistances(i,j) = distij ;
aDistances(j,i) = distij ;
}
}
As you can see the syntax to access elements has slightly changed [x][y] -> (x,y).
EDIT
As the OP has modified the question, I have noticed that the Distances is used a second time which needs attention as well. For this you will have to add a getColumn method (see above) to the Array2D class. Than you further have to modify
// Take the descriptor with least median distance to the rest
int BestMedian = INT_MAX;
int BestIdx = 0;
for(size_t i=0;i<N;i++) {
vector<int> vDists(aDistances.getRow()[i], aDistances.getRow()[i]+N);
sort(vDists.begin(),vDists.end());
int median = vDists[0.5*(N-1)];
if(median<BestMedian) {
BestMedian = median;
BestIdx = i;
}
}
NOTE: I am not perfectly sure if I got it right -- maybe you have to get a
columns instead of a rows (too late to think straight). If this is the case you should also change the memory layout of the Array2D class, i.e. sorting the elements differently in the underlaying 1D-Vector.
I am trying to write a function to extract a slice from a given matrix, where the input is 1D and the slice can be 1D or 2D.
I am trying to use the push_back function for this purpose but for some reasons the push_back does not work.
I receive an error in my line OutPut.push_back(DumyValue);
Can anyone help me why I am receiving this error?
Also, it would be appreciated if you can tell me how to solve this issue.
Also, if the first part becomes clear, can anyone tell me how I should use the push_back for inserting an integer in a specific location so I can use it for extracting a 2D slice?
If you remove the line OutPut.push_back(DumyValue); the code should work.
#include<iostream>
#include<vector>
using namespace std;
int MatrixSlice(vector<vector<int>> Input, int Row1, int Row2, int Col1, int Col2) {
//define the slice size, if it is iD or 2D
if (abs(Row1-Row2)>1 && abs(Col1-Col2)>1){
vector<vector<int>> OutPut;
}else{
vector<int> OutPut;
}
int i2;
int j2;
for (int i = Row1; i <= Row2; i++) {
i2=0;
for (int j = Col1; j <= Col2; j++) {
int DumyValue=Input[i][j];
OutPut.push_back(DumyValue);
i2++;
//cout << Input[i][j] << endl;
}
j2++;
}
return 0;
}
int main() {
//Define a matrix for test:
vector<vector<int>> Matrix2(4, vector<int>(5, 1));
int R = 4;
int C = 4;
vector<vector<int>> MatrixInput(R, vector<int>(C, 1));;
for (int i = 0; i < MatrixInput.size(); i++) {
for (int j = 0; j < MatrixInput[0].size(); j++) {
int temp;
temp = i^2+j^2;
MatrixInput[i][j] = temp;
}
}
MatrixSlice(MatrixInput, 0, 3, 1, 1);
printf("\n");
return 0;
}
Matrix slice has a couple problems:
It is impossible define a variable with two possible types and have both active in the same scope.
The return type of int makes little sense. The matrix is sliced up, but then what? It can't be handed back to the caller to do anything with it.
This can be fixed with a union, but yikes! The bookkeeping on that will be a Smurfing nightmare. Don't do it!
The next is to always use a vector of vectors, but I don't like that idea for a couple reasons I'll get into below.
Instead I pitch a simple wrapper object around a single vector. This is done for two reasons:
It preserves the ability to back a 1 dimensional matrix with a 1 dimensional container. If you have many rows of one column, all of the row data remains contiguous and cache friendly.
It tends to be much faster. The data of one vector is contiguous in memory and reaps the rewards of cache friendliness. A vector of vectors is basically a list of pointers to arrays of data, sending the poor CPU on an odyssey of pointer-chasing through memory to find the columns. If the columns are short, this can really, really hurt performance.
Here we go:
template<class TYPE>
class Matrix
{
private:
size_t mNrRows; // note size_t. This is unsigned because there is no reason
// for a matrix with a negative size. size_t is also guaranteed
// to fit anything you can throw at it.
size_t mNrColumns;
std::vector<TYPE> mVec;
public:
// make a default-initialized matrix
Matrix(size_t nrRows, size_t nrColumns) :
mNrRows(nrRows), mNrColumns(nrColumns), mVec(mNrRows * mNrColumns)
{
}
// make a def-initialized matrix
Matrix(size_t nrRows, size_t nrColumns, TYPE def) :
mNrRows(nrRows), mNrColumns(nrColumns), mVec(mNrRows * mNrColumns,
def)
{
}
// gimme a value and allow it to be changed
TYPE & operator()(size_t row, size_t column)
{
// could check for out of bounds and throw an exception here
return mVec[row * mNrColumns + column];
}
//gimme a value and do not allow it to be changed
TYPE operator()(size_t row, size_t column) const
{
return mVec[row * mNrColumns + column];
}
// gimme the number of rows
size_t getRows() const
{
return mNrRows;
}
// gimmie the number of columns.
size_t getColumns() const
{
return mNrColumns;
}
// printing convenience
friend std::ostream & operator<<(std::ostream & out, const Matrix & mat)
{
int count = 0;
for (TYPE val: mat.mVec)
{
out << val;
if (++count == mat.mNrColumns)
{
out << '\n';
count = 0;
}
else
{
out << ' ';
}
}
return out;
}
};
The vector member handles all of the heavy lifting so the Rule of Zero recommends leaving the copy and move constructors, assignment operators, and destructor up to the compiler.
What does this do to MatrixSlice? Well, first it now received and returns a Matrix instead of vector<vector> and int. The insides use Matrix and the confusion about 1D or 2D is just plain gone, resulting in a simpler function.
Matrix<int> MatrixSlice(const Matrix<int> & Input,
int Row1,
int Row2,
int Col1,
int Col2)
{
Matrix<int> OutPut(Row2-Row1 + 1,
Col2-Col1 + 1); // but what if Row1 > Row2?
int i2;
int j2= 0; // definitely need to initialize this sucker.
for (int i = Row1; i <= Row2; i++) // logical problem here: What if Row2 >= input.getRows()?
{
i2 = 0;
for (int j = Col1; j <= Col2; j++) // similar problem here
{
int DumyValue = Input(i, j);
OutPut(j2, i2) = DumyValue;
i2++;
}
j2++;
}
return OutPut;
}
Not that this completely ignores the very logical option of making slice a Matrix method. While it makes sense, it doesn't need to be a method and the stock recommendation is to prefer a free function. One good improvement is to make the function a template so that it can handle all sorts of Matrix in addition to Matrix<int>.
And finally, what happens to main?
int main()
{
//Define a matrix for test:
Matrix<int> Matrix2(4, 5, 1); // initialize matrix to all 1s
int R = 4;
int C = 4;
Matrix<int> MatrixInput(R, C); // default initialize the matrix
for (int i = 0; i < MatrixInput.getRows(); i++)
{
for (int j = 0; j < MatrixInput.getColumns(); j++)
{
int temp;
temp = i ^ 2 + j ^ 2;
// WARNING: ^ is XOR, not exponent. Maybe OP wants i XOR 2, but not
// likely. But if XOR is the desired operation, there is a lurking
// order of operation bug that needs to be addressed
MatrixInput(i, j) = temp;
}
}
std::cout << MatrixInput << '\n';
std::cout << MatrixSlice(MatrixInput, 0, 3, 1, 1);
return 0;
}
In your code
if (abs(Row1-Row2)>1 && abs(Col1-Col2)>1){
vector<vector<int> > OutPut;
// OutPut dies here
}else{
vector<int> OutPut;
// OutPut dies here
}
// here is no OutPut
OutPut lives only to the end of IF statement.
You either use it without the if statement or you add all code that uses it to the if statement.
I'm writing a matrix program and am currently trying to multiply a point and a matrix. I keep getting an error over my objects(result and P) "Expression must have pointer to object type" in this function:
//Point Class functions
Point Matrix44::operator*(const Point & P){
Point result;
for (int i = 0; i < 4; i++) {
for (int k = 0; k < 4; k++) {
result.element[i][k] = 0;
for (int j = 0; j < 4; j++) {
result.element[i][k] = element[i][j] * P.element[j][k] + result.element[i][k];
}
}
}
return result;
}
My two classes are:
//Matrix class
class Point;
class Matrix44 {
private:
double element[4][4];
public:
Matrix44(void);
Matrix44 transpose(void) const;
friend istream& operator>>(istream& s, Matrix44& t);
friend ostream& operator<<(ostream& s, const Matrix44& t);
Matrix44 operator *(Matrix44 b);
Point operator*(const Point & P);
};
//Point class
class Point {
double element[4];
friend class Matrix44;
public:
Point(void) {
element[0] = element[1] = element[2] = 0;
element[3] = 1;
}
Point(double x, double y, double z){
element [0]=x;
element [1]=y;
element [2]=z;
element [3]=1;
}
};
In your Point class, you have the element member defined as:
double element[4];
This is a one-dimensional array. However, in your function, you're trying to access it as if it were a two-dimensional array:
result.element[i][k]
P.element[j][k]
I think you need to rethink exactly how your matrix multiplication is supposed to work.
result.element is a 1 dimensional array. You are using two indices with it. That will not compile. You should look at the definition of matrix multiplication.
Point Matrix44::operator*(const Point & P){
Point result;
for (int i = 0; i < 4; i++) {
result.element[i] = 0;
for (int j = 0; j < 4; j++) {
result.element[i] += element[i][j] * P.element[j];
}
}
return result;
}
Point::element is a double[4]. In your code, you have Point result; result.element[i][k] = 0;. Since element is not a two dimensional array, the compiler tries to convert the double to an array to use [] on it, but it can't. I would guess this is copy-pasted code from Matrix44 Matrix44::operator*(const Matrix44& M)
It always helps to tell us what line has the problem in your sample code too.
Also, the function will have the incorrect result, you set result.element[i][k] to zero, then set it to 4 different values. I think you meant to add instead of assign in the innermost loop.
You're trying to access:
result.element[i][k] = element[i][j] * P.element[j][k] + result.element[i][k];
When Point itself only have a one-level array:
double element[4];
same error might appear misleadingly if you point to a struct that is not accessible to the source, such as,
header.h
define struct myStruct;
source1.c
include header.h
myStruct structX;
source2.c
include header.h
uint8_t * ptr2Struct = &structX;
if that is a case then you get this arror with line "
uint8_t * ptr2Struct = &structX;
How do you dynamically allocate a 2D matrix in C++?
I have tried based on what I already know:
#include <iostream>
int main(){
int rows;
int cols;
int * arr;
arr = new int[rows][cols];
}
It works for one parameter, but now for two. What should I do?
A matrix is actually can be represented as an array of arrays.
int rows = ..., cols = ...;
int** matrix = new int*[rows];
for (int i = 0; i < rows; ++i)
matrix[i] = new int[cols];
Of course, to delete the matrix, you should do the following:
for (int i = 0; i < rows; ++i)
delete [] matrix[i];
delete [] matrix;
I have just figured out another possibility:
int rows = ..., cols = ...;
int** matrix = new int*[rows];
if (rows)
{
matrix[0] = new int[rows * cols];
for (int i = 1; i < rows; ++i)
matrix[i] = matrix[0] + i * cols;
}
Freeing this array is easier:
if (rows) delete [] matrix[0];
delete [] matrix;
This solution has the advantage of allocating a single big block of memory for all the elements, instead of several little chunks. The first solution I posted is a better example of the arrays of arrays concept, though.
You can also use std::vectors for achieving this:
using: 'std::vector< std::vector >'
Example:
#include <vector>
std::vector< std::vector<int> > a;
//m * n is the size of the matrix
int m = 2, n = 4;
//Grow rows by m
a.resize(m);
for(int i = 0 ; i < m ; ++i)
{
//Grow Columns by n
a[i].resize(n);
}
//Now you have matrix m*n with default values
//you can use the Matrix, now
a[1][0]=1;
a[1][1]=2;
a[1][2]=3;
a[1][3]=4;
//OR
for(i = 0 ; i < m ; ++i)
{
for(int j = 0 ; j < n ; ++j)
{ //modify matrix
int x = a[i][j];
}
}
Try boost::multi_array
#include <boost/multi_array.hpp>
int main(){
int rows;
int cols;
boost::multi_array<int, 2> arr(boost::extents[rows][cols] ;
}
arr = new int[cols*rows];
If you either don't mind syntax
arr[row * cols + col] = Aij;
or use operator[] overaloading somewhere. This may be more cache-friendly than array of arrays, or may be not, more probably you shouldn't care about it. I just want to point out that a) array of arrays is not only solution, b) some operations are more easier to implement if matrix located in one block of memory. E.g.
for(int i=0;i < rows*cols;++i)
matrix[i]=someOtherMatrix[i];
one line shorter than
for(int r=0;i < rows;++r)
for(int c=0;i < cols;++s)
matrix[r][c]=someOtherMatrix[r][c];
though adding rows to such matrix is more painful
const int nRows = 20;
const int nCols = 10;
int (*name)[nCols] = new int[nRows][nCols];
std::memset(name, 0, sizeof(int) * nRows * nCols); //row major contiguous memory
name[0][0] = 1; //first element
name[nRows-1][nCols-1] = 1; //last element
delete[] name;
#include <iostream>
int main(){
int rows=4;
int cols=4;
int **arr;
arr = new int*[rows];
for(int i=0;i<rows;i++){
arr[i]=new int[cols];
}
// statements
for(int i=0;i<rows;i++){
delete []arr[i];
}
delete []arr;
return 0;
}
or you can just allocate a 1D array but reference elements in a 2D fashion:
to address row 2, column 3 (top left corner is row 0, column 0):
arr[2 * MATRIX_WIDTH + 3]
where MATRIX_WIDTH is the number of elements in a row.
Here is the most clear & intuitive way i know to allocate a dynamic 2d array in C++. Templated in this example covers all cases.
template<typename T> T** matrixAllocate(int rows, int cols, T **M)
{
M = new T*[rows];
for (int i = 0; i < rows; i++){
M[i] = new T[cols];
}
return M;
}
...
int main()
{
...
int** M1 = matrixAllocate<int>(rows, cols, M1);
double** M2 = matrixAllocate(rows, cols, M2);
...
}
The other answer describing arrays of arrays are correct.
BUT if you are planning of doing a anything mathematical with the arrays - or need something special like sparse matrices you should look at one of the many maths libs like TNT before re-inventing too many wheels
I have this grid class that can be used as a simple matrix if you don't need any mathematical operators.
/**
* Represents a grid of values.
* Indices are zero-based.
*/
template<class T>
class GenericGrid
{
public:
GenericGrid(size_t numRows, size_t numColumns);
GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue);
const T & get(size_t row, size_t col) const;
T & get(size_t row, size_t col);
void set(size_t row, size_t col, const T & inT);
size_t numRows() const;
size_t numColumns() const;
private:
size_t mNumRows;
size_t mNumColumns;
std::vector<T> mData;
};
template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns):
mNumRows(numRows),
mNumColumns(numColumns)
{
mData.resize(numRows*numColumns);
}
template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue):
mNumRows(numRows),
mNumColumns(numColumns)
{
mData.resize(numRows*numColumns, inInitialValue);
}
template<class T>
const T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx) const
{
return mData[rowIdx*mNumColumns + colIdx];
}
template<class T>
T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx)
{
return mData[rowIdx*mNumColumns + colIdx];
}
template<class T>
void GenericGrid<T>::set(size_t rowIdx, size_t colIdx, const T & inT)
{
mData[rowIdx*mNumColumns + colIdx] = inT;
}
template<class T>
size_t GenericGrid<T>::numRows() const
{
return mNumRows;
}
template<class T>
size_t GenericGrid<T>::numColumns() const
{
return mNumColumns;
}
Using the double-pointer is by far the best compromise between execution speed/optimisation and legibility. Using a single array to store matrix' contents is actually what a double-pointer does.
I have successfully used the following templated creator function (yes, I know I use old C-style pointer referencing, but it does make code more clear on the calling side with regards to changing parameters - something I like about pointers which is not possible with references. You will see what I mean):
///
/// Matrix Allocator Utility
/// #param pppArray Pointer to the double-pointer where the matrix should be allocated.
/// #param iRows Number of rows.
/// #param iColumns Number of columns.
/// #return Successful allocation returns true, else false.
template <typename T>
bool NewMatrix(T*** pppArray,
size_t iRows,
size_t iColumns)
{
bool l_bResult = false;
if (pppArray != 0) // Test if pointer holds a valid address.
{ // I prefer using the shorter 0 in stead of NULL.
if (!((*pppArray) != 0)) // Test if the first element is currently unassigned.
{ // The "double-not" evaluates a little quicker in general.
// Allocate and assign pointer array.
(*pppArray) = new T* [iRows];
if ((*pppArray) != 0) // Test if pointer-array allocation was successful.
{
// Allocate and assign common data storage array.
(*pppArray)[0] = new T [iRows * iColumns];
if ((*pppArray)[0] != 0) // Test if data array allocation was successful.
{
// Using pointer arithmetic requires the least overhead. There is no
// expensive repeated multiplication involved and very little additional
// memory is used for temporary variables.
T** l_ppRow = (*pppArray);
T* l_pRowFirstElement = l_ppRow[0];
for (size_t l_iRow = 1; l_iRow < iRows; l_iRow++)
{
l_ppRow++;
l_pRowFirstElement += iColumns;
l_ppRow[0] = l_pRowFirstElement;
}
l_bResult = true;
}
}
}
}
}
To de-allocate the memory created using the abovementioned utility, one simply has to de-allocate in reverse.
///
/// Matrix De-Allocator Utility
/// #param pppArray Pointer to the double-pointer where the matrix should be de-allocated.
/// #return Successful de-allocation returns true, else false.
template <typename T>
bool DeleteMatrix(T*** pppArray)
{
bool l_bResult = false;
if (pppArray != 0) // Test if pointer holds a valid address.
{
if ((*pppArray) != 0) // Test if pointer array was assigned.
{
if ((*pppArray)[0] != 0) // Test if data array was assigned.
{
// De-allocate common storage array.
delete [] (*pppArray)[0];
}
}
// De-allocate pointer array.
delete [] (*pppArray);
(*pppArray) = 0;
l_bResult = true;
}
}
}
To use these abovementioned template functions is then very easy (e.g.):
.
.
.
double l_ppMatrix = 0;
NewMatrix(&l_ppMatrix, 3, 3); // Create a 3 x 3 Matrix and store it in l_ppMatrix.
.
.
.
DeleteMatrix(&l_ppMatrix);