9

My Matrx class is defined as

class Matrx
{
 double A[50][50];
 int m,n;
public:
 Matrx(void);
 Matrx(int a, int b)
 {
  m=a;
  n=b;
 }
 Matrx operator +(Matrx b);
 Matrx Transpose(Matrx b);
 Matrx operator *(Matrx b);
 CString printMatrx();
 void readMatrx(double a[][]);
 Matrx TransposeMat(Matrx b);
};

void Matrx::readMatrx(double a[][])
{
 for(int i=0;i< m;i++)
  {
   for(int j=0;j< n;j++)
    A[i][j]=a[i][j];
  }
}

The intellisense gives error like the below

1 IntelliSense: an array may not have elements of this type d:\bmadaptive_dd_v1.02\matrx.h 17 27 TestServer

Why?

How to pass a two dimensional array as argument of the function?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
user543265
  • 129
  • 1
  • 1
  • 6
  • 3
    While the code you present is not valid C++, do not rely on Intellisense for finding syntax errors. Intellisense is an autocompletion tool, not a syntax checker. It only does a "quick look" at your code and may not give the most accurate error messages. You should instead try to compile it (with an actual compiler of course) and post the actual compiler error message(s) verbatim, if any. – In silico Jan 26 '11 at 08:54
  • 3
    I am sure there are many duplicates and questions around this one. Search in the box above for `[c++] bidimensional array` or similar and go over the different questions/answers. Even if they are not exactly the same, they will surely provide some insight. – David Rodríguez - dribeas Jan 26 '11 at 09:06

6 Answers6

25

The problem is that when passing multidimensional arrays as parameters in C++, you must specify the dimension of the outermost array. For example:

void ThisIsIllegal(int arr[][]); // Wrong!
void ThisIsAlsoIllegal(int arr[10][]); // Also wrong
void ThisIsLegal(int arr[][10]); // Okay

If you want to be able to have a function that takes in an array of any size, you can use templates:

template <size_t N, size_t M>
void ThisIsAlsoLegal(int (&arr)[M][N]);

This last version accepts any multidimensional array of the right type, and is probably what you're looking for.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 2
    class Matrx { ----------------------template void readMatrx(double (&a)[M][N]); Matrx TransposeMat(Matrx b); }; I have changed my class like that and my function like template void Matrx::readMatrx(double a[M][N]) { for(int i=0;i< m;i++) { for(int j=0;j< n;j++) A[i][j]=a[i][j]; } still the compiler gives the error Error 2 error C2244: 'Matrx::readMatrx' : unable to match function definition to an existing declaration d:\bmadaptive_dd_v1.02\matrx.cpp 67 1 TestServer on this line Wtest.readMatrx(W); – user543265 Jan 26 '11 at 09:09
  • 2
    "…you must specify all but the innermost dimension" to generalize to all arrays (including a single dimension), but otherwise ThisIsAlsoLegal is also what I would suggest. – Fred Nurk Jan 26 '11 at 09:14
  • @user543265- did you update the function declaration in the body of the class? – templatetypedef Jan 26 '11 at 09:27
  • 1
    Very clever use of primitive template parameter values. :) – Mephane Jan 26 '11 at 12:41
  • You seem to have a funnny definition of "outer most" in this context. I would have said "inner most". – sellibitze Jan 26 '11 at 14:17
  • thank you templatetypedef for your suggestion. Although selliblitz's code is much robust..I am following your suggestion as it is upto the level of my knowledge... I can't understand the problem the compiler issues me when I use the code sellibitz given to me.... – user543265 Jan 27 '11 at 05:07
4

You need to properly learn about arrays and pointers. This includes the lesson "huh! They are not as useful as I thought they were". After you've gotten familiar with how arrays and pointers work exactly you should rethink your design.

For example, in my opinion, the following design has lots of advantages:

#ifndef MATRIX_HPP_INCLUDED
#define MATRIX_HPP_INCLUDED

#include <vector>
#include <algorithm>

class matrix
{
public:
    typedef std::vector<double>::size_type st;
    matrix() : rows_(0), cols_(0) {}
    matrix(int r, int c) : rows_(r), cols_(c), coeffs_(st(r)*c,0.0) {}
    void reset(int r, int c)
    { rows_=r; cols_=c; coeffs_.clear(); coeffs_.resize(st(r)*c,0.0); }
    int rows() const {return rows_;}
    int cols() const {return cols_;}
    double const& operator()(int i, int j) const {return coeffs_[indexof(i,j)];}
    double      & operator()(int i, int j)       {return coeffs_[indexof(i,j)];}
    double const* operator[](int i) const {return &coeffs_[indexof(i,0)];}
    double      * operator[](int i)       {return &coeffs_[indexof(i,0)];}
    void swap(matrix& that)
    {
      std::swap(this->rows_,that.rows_);
      std::swap(this->cols_,that.cols_);
      this->coeffs_.swap(that.coeffs_));
    }
private:
    int rows_, cols_;
    std::vector<double> coeffs_;
    st indexof(int i, int j) const {return st(i)*cols+j;} // row major storage
};

inline void swap(matrix& a, matrix& b) {a.swap(b);}

matrix& operator+=(matrix& lhs, matrix const& rhs);
matrix operator+(matrix const& lhs, matrix const& rhs);
matrix operator*(matrix const& lhs, matrix const& rhs);
inline matrix& operator*=(matrix& lhs, matrix const& rhs)
{ matrix tmp = lhs * rhs; swap(tmp,lhs); return lhs; }
...

#endif

This way you won't waste any space for small matrices, and you can support large matrices. Also, the use of std::vector instead of a pointer member which points to dynamically allocated memory removes the need to define your own copy constructor, assignment operator and destructor.

Of course, you could use boost::multi_array as a matrix replacement but using a custom matrix class allows you to declare overloaded operators in your own namespace which is desirable due to ADL (argument dependent lookup).

You might think that this doesn't really answer your question. In that case, let me stress that I think you don't fully understand how arrays and pointers work / behave. This is something you should look up in a decent C++ book. One could write many pages about this topic. You can't expect to see a short answer explaining all the quirks.

Check out the Definite C++ Book Guide thread.

Community
  • 1
  • 1
sellibitze
  • 27,611
  • 3
  • 75
  • 95
  • thank you sellibitze...you are right...Please tell me now if I have to overload the +,*,/, - do I have to write the overloading functions separately as I did before? If yes please tell the declaration in the class that you have provided... – user543265 Jan 26 '11 at 09:21
  • Also, instead of reimplementing, using something standard like `boost::multi_array` is preferred. – Kos Jan 26 '11 at 09:24
  • sellibitze can you please tell me is there any special header file I need to include apart from iostream.h and apart from writting using namspace std; cause I am getting the error as 15 IntelliSense: namespace "std" has no member "vector" d:\bmadaptive_dd_v1.02\matrx.h 10 19 TestServer – user543265 Jan 26 '11 at 09:38
  • 1
    @user543265: `std::vector<>` is declared in the `` header. Also, you should not write `using namespace std;` in a header file! – sellibitze Jan 26 '11 at 09:52
1

You need to specify all but the first dimension, e.g.

void Matrx::readMatrx(double a[][50])

From this you should be able to see that you have a fundamental problem with the way you have implemented your class, but at least you should now be able to get the code to compile.

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • Thank you Paul....It worked but now get error message like this. 5 IntelliSense: argument of type "double (*)[4]" is incompatible with parameter of type "double (*)[50]" d:\bmadaptive_dd_v1.02\testserverdlg.cpp 1041 19 TestServer for the code double X[15][4],splusn[15],m_dC=1.0,y[15],W[15][4],WTrans[4][15]; Matrx Wtest(15,4),WtestTrans(4,15); for(int r=0;r<15;r++) { for(int q=0;q<4;q++) W[r][q]=0.1; Wtest.readMatrx(W); } – user543265 Jan 26 '11 at 09:00
  • 3
    @user543265: Writing the compiler error without the code where the compiler flags it is not too useful. Doing so in a comment makes it even harder to read. Either update the question adding this to the end or else create a separate question. Either one will make it easier for people to help. – David Rodríguez - dribeas Jan 26 '11 at 09:08
0

You can to specify all dimensions or only last dimension to pass an array:

void Matrx::readMatrx(double a[][50])
{
 for(int i=0;i< m;i++)
  {
   for(int j=0;j< n;j++)
    A[i][j]=a[i][j];
  }
}
SVGreg
  • 2,320
  • 1
  • 13
  • 17
  • 1
    You cannot pass a 2-dimensional array as a pointer to a pointer. Multi-dimensional arrays are *not* arrays of pointers! – Fred Nurk Jan 26 '11 at 09:12
  • This is a common error. A bidimensional array is a contiguous block of memory where all the elements of the first row are followed by the second row and so on. If the bidimensional array decays it does so by converting to a pointer to the first element that would be `array of N elements of type T`, not `pointer to T`. While before accessing the *row* array it will again decay into a pointer, that second pointer will have the address of the array. That is: `&array`, `&array[0]` and `&array[0][0]` are the same address. – David Rodríguez - dribeas Jan 26 '11 at 09:14
  • On the other hand, with a `pointer to pointer to T`, the array of the first element stored would be the result of dereferencing the first pointer `p[0]`, interpreting that as a pointer and dereferencing again `(p[0])[0]`, and unless it has been initialized with its own address it will differ from `&p[0][0]` – David Rodríguez - dribeas Jan 26 '11 at 09:17
  • 1
    Oh, sorry. I see. It was wrong example. I used pointer to pointer in other case and thought that it might work. I will correct the answer. – SVGreg Jan 26 '11 at 09:47
0

Thanks to all of you people...you were really helping...I have found myself a new definition of the class and the function definition for the matrix that fitted my need. I need you r comment on it...Below is the example of the class declaration..

#include<iostream>
#include"stdafx.h"
using namespace std;  
const int M=100; const int N=100;  
class Matrix  
{  
    double A[M][N];  
    int m,n;  
public:  
    Matrix(void);  
    Matrix(int a, int b)  
    {  
        m=a;  
        n=b;  
        for(int i=0;i<m;i++)  
        {  
            for(int j=0;j<m;j++)  
                A[i][j]=0.0;  
        }  
    }  
    Matrix operator +(Matrix b);  
    Matrix operator -(Matrix b);  
    Matrix operator *(Matrix b);  
    void TransPose(Matrix b);  
    CString printMatrix();  
    void readMatrix(double*);  
};

and then the function implementation

#include "stdafx.h"
#include "Matrix.h"

Matrix::Matrix(void)  
{  
}  

Matrix Matrix::operator *(Matrix b)  
{  
 Matrix c(m,m);  
 if(n!=b.m)  
 {  
    HWND hndOwner(0);   
    MessageBoxW(hndOwner,L"Multiplication not possible row and column does not match",L"Error",NULL);  
    Matrix errMat(1,0);  
    double er[1][1]={0}; errMat.readMatrix((double *)er);  
    return errMat;  
 }  
for(int i=0;i< m;i++)  
{  
for(int k=0;k< m;k++)  
{  
c.A[i][k]=0;  
for(int j=0;j< n;j++)  
{  
c.A[i][k] = c.A[i][k]+(A[i][j] * b.A[j][k]) ;  
}  
}  
}  
return c;  
}  
Matrix Matrix::operator +(Matrix b)  
{  
    Matrix c(m,n);  
    if((n!=b.n)||(m!=b.m))  
 {  
    HWND hndOwner(0);   
    MessageBoxW(hndOwner,L"Addition not possible row and column does not match",L"Error",NULL);  
    Matrix errMat(1,0);  
    double er[1][1]={0}; errMat.readMatrix((double *)er);  
    return errMat;  
 }  
    for(int i=0;i<m;i++)  
        {  
            for(int j=0;j< n;j++)  
                {  
                    c.A[i][j]=0.0;  
                }  
        }  
        for(int i=0;i< m;i++)  
        {  
            for(int j=0;j< n;j++)  
                {  
                    c.A[i][j]=A[i][j]+b.A[i][j];  
                }  
        }  
return c;  
}    
CString Matrix::printMatrix()  
{  
    CString strB(" "),strDisp;  
    for(int iRow=0;iRow<m;iRow++)  
    {  
        for(int iColumn=0;iColumn<n;iColumn++)  
        {  
            strB.Format(L"%lf ",A[iRow][iColumn]);  
            strDisp+=strB;  
        }  
            strDisp+="\r\n";  
    }  
        return strDisp;  
}  
void Matrix::readMatrix(double *ptrarr)  
{  
    for(int i=0;i< m;i++)  
        {  
            for(int j=0;j< n;j++)  
                A[i][j]=*(ptrarr+i*n+j);  
        }  
}  
void Matrix::TransPose(Matrix b)  
{  
    for(int i=0;i<b.n;i++)  
    {  
        for(int j=0;j<b.m;j++)  
            A[i][j]=b.A[j][i];  
    }  
}   

The simple codes in the above are working well till now...if you have any suggestion for the improvement please suggest..

Lazer
  • 90,700
  • 113
  • 281
  • 364
user543265
  • 129
  • 1
  • 1
  • 6
-1

You're lucky, then because:

for(int j=0;j<m;j++)
    A[i][j]=0.0;

should probably be:

for(int j=0;j<**n**;j++)
    A[i][j]=0.0;
j0k
  • 22,600
  • 28
  • 79
  • 90