12 Replies - 19008 Views - Last Post: 01 October 2011 - 09:01 AM Rate Topic: -----

#1 Crimson Wings  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 13
  • View blog
  • Posts: 215
  • Joined: 11-July 09

Multidimensional Arrays as Parameters to Functions.

Posted 30 September 2011 - 08:24 PM

Hi guys, I found a little problem that I cannot seem to solve without using an ugly solution, so I want your help with this.

I have a function that needs to be passed a multidimensional (a x * m array to be more with specific), and print all the elements of the array. I have everything figured out except how to pass the actual multidimensional array itself.

My whole code looks like this so far:

/**
3.Elabore un programa que lea una matriz de orden m x n y la escriba poniendo las columnas como renglones y los renglones como columnas.

Por ejemplo, si la matriz que da el usuario es:

4	7	1	3	5
2	0	6	9	7
3	1	2	6	4

entonces el programa debe escribir la matriz transpuesta:

4	2	3
7	0	1
1	6	2
3	9	6
5	7	4

*/

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

void imprimirMatriz(int mat[][], int filas, int columnas)
{
    for(int i = 0; i < filas; i++)
    {
        for(int j = 0; j < columnas; j++)
        {
            cout << mat[i][j] << ' ';
        }
        cout << endl;
    }
}

int main()
{
    srand(time(NULL));
    int n, m;
    cin >> n >> m;
    int mat[n][m];
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            mat[n][m] = rand() % (9 - 0 + 1) + 0;
        }
    }
    cout << endl;
    imprimirMatriz(mat, n, m);
    return 0;
}



When I attempt to compile that, I get the following errors:

Quote

3.cpp|25|error: declaration of 'mat' as multidimensional array must have bounds for all dimensions except the first
3.cpp|25|error: expected ')' before ',' token
3.cpp|25|error: expected unqualified-id before 'int'


At first, I had no idea of what was going on. My main concern is the first error, because I know why I am getting the other two. Now I have googled a bit about this (how to pass a multidimensional array to a function) in Google, but everyone suggests that I specify a constant number for the second part of the array in the signature of the function itself, a like this:

void func(int x[][2]);


Apparently, this solution works for most people, but I have two problems with it.

1) It's not exactly a solution for me since I am generation both sides of the array dynamically without constant values.
2) Even if I try to compile with the following function:

void imprimirMatriz(int mat[][5], int filas, int columnas)
{
    for(int i = 0; i < filas; i++)
    {
        for(int j = 0; j < columnas; j++)
        {
            cout << mat[i][j] << ' ';
        }
        cout << endl;
    }
}


I get an error I have never seen in 5 years I have been programming with C++:

Quote

3.cpp|51|error: cannot convert 'int (*)[(((unsigned int)(((int)m) + -0x000000001)) + 1)]' to 'int (*)[5]' for argument '1' to 'void imprimirMatriz(int (*)[5], int, int)'


So can someone please aid me with this? Everything I want to do is to pass a multidimensional array with sizes created dynamically.

This post has been edited by Crimson Wings: 30 September 2011 - 08:35 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Multidimensional Arrays as Parameters to Functions.

#2 CTphpnwb  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 3001
  • View blog
  • Posts: 10,393
  • Joined: 08-August 08

Re: Multidimensional Arrays as Parameters to Functions.

Posted 30 September 2011 - 08:34 PM

First, arrays need to be declared with constants unless you use dynamic memory. Then you need to pass the size of each dimension past the first when calling a function. So you might have an array like:
int x[5][10][15];

which you initialize with this function:
void initialize( int myarray[][10][15]) {
	int i,j,k;
	for(i= 0; i<5; i++) {
		for(j= 0; j<10; j++) {
			for(k= 0; k<15; k++) {
				testarray[i][j][k] = 0;
			}
		}
	}
}

Was This Post Helpful? 0
  • +
  • -

#3 Crimson Wings  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 13
  • View blog
  • Posts: 215
  • Joined: 11-July 09

Re: Multidimensional Arrays as Parameters to Functions.

Posted 30 September 2011 - 08:43 PM

View PostCTphpnwb, on 30 September 2011 - 11:34 PM, said:

First, arrays need to be declared with constants unless you use dynamic memory. [/code]


Really? I mean, I have read that in books before, but my college teacher always creates dynamic arrays the way I did above... I guess I am being mentally mutilated by him. I have changed the declaration to a pointer now. Thanks for pointing it out.

Regarding the snippet itself. Is there no other way? Because it is exactly what I want to avoid, and if I must specify the size of the array past the first in the function declaration, then there's no way at all to create a function that deals with dynamically created multidimensional arrays.

After all, I am being asked to read an array sized n x m and I absolutely need to print it with a function to save time. Not to mention, I really want to figure out a way to pass an array as big as I want, not an array limited to x[][costant][another_constant].

EDIT:

Woah, on another note, I cannot do this:

int *mat = new int[n][m];


Or

int mat[] = new int[n][m];


Because m is a variable and not a constant, but I can do this just fine?:

int mat[n][m];

This post has been edited by Crimson Wings: 30 September 2011 - 08:48 PM

Was This Post Helpful? 0
  • +
  • -

#4 blackcompe  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1155
  • View blog
  • Posts: 2,534
  • Joined: 05-May 05

Re: Multidimensional Arrays as Parameters to Functions.

Posted 30 September 2011 - 08:51 PM

If you don't know the size up front, your forced to use pointers.

int** mat = new int*[n]; //allocate a column of int pointers, each of which will point to the start of a row
for(int i = 0; i < n; i++) { //traverse column of pointers
    mat[i] = new int[m]; //allocate a row of integers, assign this pointer to this row
    for(int j = 0; j < m; j++) { //traverse the row
        //populate with random integers
    }
}



void imprimirMatriz(int** mat, int filas, int columnas)


You can print the contents of the array how your doing it now.
Was This Post Helpful? 1
  • +
  • -

#5 Crimson Wings  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 13
  • View blog
  • Posts: 215
  • Joined: 11-July 09

Re: Multidimensional Arrays as Parameters to Functions.

Posted 30 September 2011 - 09:07 PM

Haha wow, I have never seen something like this before:

int** mat = new int *[n];


What exactly is the "new int *[n]" part saying? An array of int pointers right? Good to see I can always learn something new :)!

Leaving that aside, everything compiles wonderfully now, although it crashes when it tries to assign a number to the array. I may be going out of bounds, but I want to double-check this to be sure. I can still access the array like I normally would right?

mat[n][m] = rand() % (9 - 0 + 1) + 0;


I may be going out of bounds to get this crash, but I want to confirm the syntax either way.

Thanks a lot for your help blackcompe :). I appreciate it a lot.

This post has been edited by Crimson Wings: 30 September 2011 - 09:09 PM

Was This Post Helpful? 0
  • +
  • -

#6 CTphpnwb  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 3001
  • View blog
  • Posts: 10,393
  • Joined: 08-August 08

Re: Multidimensional Arrays as Parameters to Functions.

Posted 30 September 2011 - 09:09 PM

You could use vectors instead of arrays if you're using C++. They're objects and they have some useful methods.
Was This Post Helpful? 0
  • +
  • -

#7 blackcompe  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1155
  • View blog
  • Posts: 2,534
  • Joined: 05-May 05

Re: Multidimensional Arrays as Parameters to Functions.

Posted 30 September 2011 - 09:19 PM

Quote

I may be going out of bounds to get this crash, but I want to confirm the syntax either way.


Your indexing the array with n and m, use i and j. Glad I could help! :bananaman:

This post has been edited by blackcompe: 30 September 2011 - 09:20 PM

Was This Post Helpful? 1
  • +
  • -

#8 Crimson Wings  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 13
  • View blog
  • Posts: 215
  • Joined: 11-July 09

Re: Multidimensional Arrays as Parameters to Functions.

Posted 30 September 2011 - 09:25 PM

View Postblackcompe, on 01 October 2011 - 12:19 AM, said:

Quote

I may be going out of bounds to get this crash, but I want to confirm the syntax either way.


Your indexing the array with n and m, use i and j. Glad I could help! :bananaman:


Whoops wonder how I missed that *facepalms*. Thanks a lot again. I am particularly happy because I learned a sweet technique that is bound to dumbfound that teacher. Not to mention I understand it now. I owe you a lot more than what you think. :)

@CTphpwb I thought that class was limited to unidimensional vectors? Haven't played with it much, but based on the few times I played with it I would say it's the case... Correct me if I'm wrong though.
Was This Post Helpful? 0
  • +
  • -

#9 #define  Icon User is offline

  • Duke of Err
  • member icon

Reputation: 1353
  • View blog
  • Posts: 4,660
  • Joined: 19-February 09

Re: Multidimensional Arrays as Parameters to Functions.

Posted 30 September 2011 - 09:48 PM

Another way :


#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

void imprimirMatriz(int mat[], int filas, int columnas)
{
    for(int i = 0; i < filas; i++)
    {
        for(int j = 0; j < columnas; j++)
        {
            cout << mat[(i*columnas)+j] << ' ';
        }
        cout << endl;
    }
}

int main()
{
  srand(time(NULL));
  int n, m;

  cout << "Enter rows and columns : ";
  cin >> n >> m;

  int *mat = new int[n*m];

  for(int i = 0; i < n; i++)
  {
    for(int j = 0; j < m; j++)
    {
       mat[(i*m)+j] = rand() % (9 - 0 + 1) + 0;
    }
  }

  cout << endl;
  imprimirMatriz(mat, n, m);

  cin.ignore();
  cin.get();
  return(0);
}


Was This Post Helpful? 1
  • +
  • -

#10 Bench  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 856
  • View blog
  • Posts: 2,339
  • Joined: 20-August 07

Re: Multidimensional Arrays as Parameters to Functions.

Posted 01 October 2011 - 12:48 AM

Playing around with raw arrays and pointers when you want a dynamic array in C++ is a bit like playing with fire. It's a really out-dated way of doing things and should be avoided in C++ because it comes with too many caveats and 'danger' signs attached.

Vectors are a much simpler and easier solution to almost any problem which needs an array.

A 2D array in C++ is essentially an 'array of arrays', and a vector is semantically nothing more than a C++ dynamic array, therefore the same semantics apply if you want to create a 2D vector.
It is possible to create a dynamic array/vector up-front with each element initialised to a particular value using one of the overloaded constructors. e.g. for an array of 10 int's all initialised to zero, you would use
vector<int>(10,0); 
Where the first argument is the number of elements, the second argument is the initialiser

Exactly the same logic applies for a 2D 'vector of vectors' whose sizes are known up-front (All elements initialised to zero); You create a vector whose default initialiser for each element is another vector. This is exactly the same logic as creating an array-of-pointers for a so-called 2D array.
int n = 10;
int m = 20;
vector< vector<int> > fred(n, vector<int>(m,0)); 

for(int i(0); i!=fred.size(); ++i)
{
    for(int j(0); j!=fred.at(i).size(); ++j)
    {
        cout << fred.at(i).at(j) << ' ';
    }
    cout << '\n';
} 
You can replace the .at() syntax with subscript [], although 'at' is bound-checked.


Or, to use #define's approach of imposing 2D-array arithmetic across a single array (again, all elements initialised to zero)
int n = 10;
int m = 20;
vector< vector<int> > v(n*m, 0); 

This post has been edited by Bench: 01 October 2011 - 12:55 AM

Was This Post Helpful? 1
  • +
  • -

#11 Karel-Lodewijk  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 449
  • View blog
  • Posts: 849
  • Joined: 17-March 11

Re: Multidimensional Arrays as Parameters to Functions.

Posted 01 October 2011 - 05:37 AM

If you pass a multidimensional array, then you have to pass all but the 1st dimension to the function. It needs this information to properly calculate the index. For example to element a[2][4] == a[2+4*COLUMNS], so COLUMNS must be provided.

There are 2 possible situations when it comes to passing multi-dimensional arrays to functions.

1) The dimensions are known at compile time.

If this the case then we can just supply put the column size in the function parameter like this.

const int ROWS = 5;
const int COLUMNS = 10;

void example(int mat[][COLUMNS]) {}

int main() {
    int a[ROWS][COLUMNS];
    example(a);
}



But we can also use this neat template trick, so you don't have to rewrite the function if you use it with matrices of different dimensions, as long as the dimensions are known at compile time.

template <unsigned int N>
void example(int mat[][N]) {}

int main() {
    int a[5][10];
    example(a);

    int b[2][20];
    example(b);
}



The mat in the function can now just be used like a multi-dimensional array.

1) The dimensions are not known at compile time. And this is the case in your example.

If you are using c++ you can use a vector in a vector like Bench already suggested and I would recommend that. You can use arrays but it is tricky. You would have to write something like this.

void example(int* test, int columns) {
    test[2 + 3*columns]; //access element [2][3]
}

int main() {
    int n = 5, m = 10;
    int a[n][m];
    example((int*)a, m);
    example(&a[0][0], m); //same thing phrased differently, use what you prefer
}



Not pretty, I know, but it will work as expected.

This post has been edited by Karel-Lodewijk: 01 October 2011 - 05:42 AM

Was This Post Helpful? 1
  • +
  • -

#12 baavgai  Icon User is online

  • Dreaming Coder
  • member icon

Reputation: 5848
  • View blog
  • Posts: 12,707
  • Joined: 16-October 07

Re: Multidimensional Arrays as Parameters to Functions.

Posted 01 October 2011 - 06:19 AM

I don't know how many ways I've done this; I should start a collection...

First, arrays suck. They do strange and unusual things. Passing them is tricky and they're too stupid to even know how big they are. Adding a dimension only compounds this. Always use an object. It needn't be a vector, I prefer a true array for what you're doing, since size is constant. However, wrapping it in a class makes it actually easy to use.

Here's one version that let's you use the [][] syntax. People are real attached to that syntax; I don't know why.

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

class Matriz {
	int *data;
public:
	const int ROWS, COLS;
	Matriz(int r, int c) : ROWS(r),COLS(c) { data = new int[ROWS*COLS]; }
	~Matriz() { delete [] data; }
	int *operator[] (int row) { return data + (row*COLS); }
};


void imprimirMatriz(Matriz &mat) {
	for(int i = 0; i < mat.ROWS; i++) {
		for(int j = 0; j < mat.COLS; j++) {
			cout << mat[i][j] << ' ';
		}
		cout << endl;
	}
}

Matriz fromUser() {
	int n, m;
	cin >> n >> m;
	return Matriz(n,m);
}

void randomFill(Matriz &mat) {
	for(int row = 0; row < mat.ROWS; row++) {
		for(int col = 0; col < mat.COLS; col++) {
			mat[row][col] = rand() % 10;
		}
	}
}

int main() {
	srand(time(NULL));
	
	// Matriz mat(3,4);
	Matriz mat = fromUser();
	randomFill(mat);
	imprimirMatriz(mat);
	return 0;
}



This is C++. If you should find yourself passing your object to a function, you might consider making those functions part of the class.

Something like:
class Matrix {
	int *data;
public:
	const int ROWS, COLS, SIZE;
	Matrix(int rows, int cols);
	~Matrix();
	int get(int row, int col) const;
	void set(int row, int col, int value);
	void print(std::ostream &) const;
	void fill(int);
	void fillRandom(int valueFrom, int valueTo);
};



Hope this helps.
Was This Post Helpful? 2
  • +
  • -

#13 Crimson Wings  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 13
  • View blog
  • Posts: 215
  • Joined: 11-July 09

Re: Multidimensional Arrays as Parameters to Functions.

Posted 01 October 2011 - 09:01 AM

I never imagined working with matrices was such a pain.
I have given a thought to this, and I came to the following conclusions:

1) In tests and competitions, unless I am allowed to carry my own 'library' around, I will use blackcompe's method, because it's a fast way to do it and in tests and competitions I usually don't have time to type up my library of code.
2) For "official" things, I will write my own Matrix class like baavgai suggested, because it's elegant and simple to work with.

Thanks a lot to everyone for your input. I may have been learning C++ for 5 years, but I never had a use to play with matrices before, except now that they need to be done in order to complete my programming homework. I really never thought working with them was such a pain haha.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1