1

I am trying to pass a 2d array to a function in c++. The problem is that its dimension is not universal constant. I take the dimension as an input from the user and then try to pass the array. Here is what i am doind:

/*
 * boy.cpp
 *
 *  Created on: 05-Oct-2014
 *      Author: pranjal
 */
#include<iostream>
#include<cstdlib>
using namespace std;


class Queue{
private:
    int array[1000];
    int front=0,rear=0;
public:
    void enqueue(int data){
        if(front!=(rear+1)%1000){
            array[rear++]=data;
        }
    }
    int dequeue(){
        return array[front++];
    }
    bool isEmpty(){
        if(front==rear)
            return true;
        else
            return false;
    }
};

class Graph{
public:
    void input(int matrix[][],int num_h){ //this is where I am passing the matrix
        int distance;
        char ans;

        for(int i=0;i<num_h;i++){
            for(int j=0;j<num_h;j++)
                matrix[i][j]=0;
        }
        for(int i=0;i<num_h;i++){
            for(int j=i+1;j<num_h;j++){
                cout<<"Is there route between houses "<<i<<" and "<<j<<": ";
                cin>>ans;
                if(ans=='y'){
                    cout<<"Enter the distance: ";
                    cin>>distance;
                    matrix[i][j]=matrix[j][i]=distance;
                }
            }
        }
        cout<<"The matrix is: \n";
        for(int i=0;i<num_h;i++){
            cout<<"\n";
            for(int j=0;j<num_h;j++)
                cout<<matrix[i][j]<<"\t";
        }
    }
};

int main(){
    Graph g;
    int num_h;
    cout<<"Enter the number of houses: ";
    cin>>num_h;
    int matrix[num_h][num_h];
    g.input(matrix,num_h); //this is where I get an error saying
                           // Invalid arguments ' Candidates are: void input(int (*)[], 
                           // int) '
    return 0;
}

Help much appreciated. Thank you.

6
  • possible duplicate of Passing multidimensional arrays as function arguments in C Commented Oct 6, 2014 at 5:17
  • You're already using non-standard extensions with that VLA declaration of matrix in main(). If you want the same in your parameter list, num_h is going to have to come along for the ride. Commented Oct 6, 2014 at 5:17
  • @WhozCraig, sorry but I am not getting you Commented Oct 6, 2014 at 5:39
  • @dandan78, ya we can do that one. But I don't want it to be so complicated. Already I am working on a graph problem wherein I have to use BFS and Prims algorithms. Doing what you suggested will kill my time Commented Oct 6, 2014 at 5:41
  • @Pranjal What I mean is the caller side is already using a non-standard VLA extension (likely you're using gcc or some such) when declaring int matrix[num_h][num_h];. You could continue that usage by simply declaring input as input(int num_h, int matrix[][num_h]). For standard compliance a different, non-VLA solution would be in-order (such as a vector of vectors or simple array of vectors). Commented Oct 6, 2014 at 13:45

3 Answers 3

7

Problems in your code:

Problem 1

void input(int matrix[][],int num_h){

is not valid C++. In a multi-dimensional array, all but the first dimension must be constants. A valid declaration would be:

// Define a constant at the start of the file.
const int MATRIX_SIZE 200;


void input(int matrix[][MATRIX_SIZE],int num_h){

Problem 2

int matrix[num_h][num_h];

is not valid C++. VLA are not supported in C++.

Suggested Solution

Use std::vector<std::vector<int>> to capture the 2D array.

Change

void input(int matrix[][],int num_h){

to

void input(std::vector<std::vector<int>>& matrix){
// You can get the size by calling matrix.size()
// There is no need to pass num_h as an argument.

Change the calling code to:

int main(){
    Graph g;
    int num_h;
    cout<<"Enter the number of houses: ";
    cin>>num_h;

    // Construct a 2D array of size num_h x num_h using std::vector
    std::vector<std::vector<int>> matrix(num_h, std::vector<int>(num_h));

    g.input(matrix);
    return 0;
}
Sign up to request clarification or add additional context in comments.

5 Comments

That was the best solution. Thank you very much
Can you please help me with one more thing? How should I return that matrix from the input function ?
@Pranjal, you don't need to. If you pass it by reference, as I have suggested in my answer, the changes you make in input will be visible in main.
Great! I just tried it and it really works. Thanks for that. But I still wanted to know how to return that array. Maybe helpful for me in future
@Pranjal, you can change the return type to std::vector<std::vector<int>>& and use return matrix; in the function.
0

I had a similar problem, where I was trying to ingest an array that was specified as a double[4][4] into my own C++ matrix class which handled arbitrary dimensions, and thus stored the matrix internally as a double**. As everyone has stated earlier, these are not equivalent -- double ** can be fragmented, where double[4][4] occupies contiguous memory.

But if you realize that a double[4][4] is simply a double[16], where the array is written in row-major order (e.g. read across each row, then move to the second row, etc), you can pass the double[][] as a double* as an argument. Here is a subset of the code from my matrix class, and how I was able to pass a double[4][4] 2-D array into that class.

class CMatrix
{
  public:
    CMatrix(unsigned int nRows, unsigned int nCols);
    Set(unsigned int nRows, unsigned int nCols, double* array, bool columnMajor=false)
  protected:
   double** m_M;
}

CMatrix(unsigned int nRows, unsigned int nCols)
{
    unsigned int i = 0;

    m_M = new double*[nRows];
    for (i = 0;i<nRows;i++)
      m_M[i] = new double[nCols];
}

CMatrix::Set(unsigned int nRows, unsigned int nCols, double* array, bool columnMajor)
{
   unsigned int i = 0;
   unsigned int row = 0;
   unsigned int col = 0;

  if (columnmajor) // e.g. FORTRAN
  {
    // same as below but switch order between rows and columns
  }
  else // row major (e.g. C/C++)
  {
    for (i=0;i<nRows*nCols;i++)
    {
      m_M[row][col] = array[i];
      col++;
      if (col % nCols == 0)
      {
         row++;
         col = 0;
      }
    }
  }
}

int main()
{
   CMatrix M(4,4);
   double oldMat[4][4];

   M.Set(4,4,reinterpret_cast<double*>(oldMat));
}

Not pretty, but by reintrepreting the double[][] as a double*, I am able to pass the value. But when you do this, you lose the information about the # of rows and columns, which is why I made those explicit arguments in my Set() function. With that knowledge, you can now convert the 2-D array elements into whatever internal format you need. I added a flag for column-major (which defaults to row major if unspecified), because I am often converting FORTRAN code to C++, and unlike C/C++, FORTRAN converts 2-D arrays to 1-D arrays in column-major form (i.e. reads down a column before moving to the next column), while C/C++ converts using row-major form (reading across a row before moving to the next row).

Hopefully this provides another useful alternative to using the std::vector<> approach above. That approach didn't work for me, because I did not have the flexibility to change the structure of the initial matrix -- it was a member within a class created by someone else.

Comments

-1

Instead of passing the entire matrix, pass a pointer to the matrix. To do this effectively, you need to either treat the matrix as 2D, but manage it as a vector, or use a vector of vectors.

Considering the first case, you would:

int matrix[num_h * num_h];

and

g.input(matrix,num_h)

to

void input(int *matrix,int num_h)

and access the elements using

matrix[i * num_h + j] = 0;

1 Comment

But then it would become a 1d array. I want to use 2d array

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.