@JavaEnthusiast : if you are already familiar with part 1, you may want to go directly to part 2.
part 1
------
it helps to first realize that arrays are *never* actually passed to functions. for example,
Code:
void foo( int array[] )
{
// ...
}
int main()
{
int a[20] ;
}
the type of the argument to foo is not "array of int", it is "pointer to int". in fact, it would be exactly the same if it were written as
Code:
void foo( int* array )
{
// ...
}
the name of an array is almost always converted to a pointer to the first element of that array. for example:
Code:
int b[20] ;
b[3] = 100 ;
the second line is equivalent to *( b + 3 ) = 100 ; where b is a pointer to the first element, and pointer arithmetic is used to reach the 3rd element. that line could just as well have been written this way:
Code:
3[b] = 100 ; // perfectly valid.
this is equivalent to *( 3 + b ) = 100 ; which is equivalent to *( b + 3 ) = 100 ;
once you grasp that array names almost always decay to a pointer to the first element, take another look at the function call from main() above: foo(a) ;. you should understand what this is really doing - it's *not* passing an int array named a to a function that expects an int array. it's passing an int pointer to a function that expects an int pointer. foo(a) ; is equivalent to foo( &( a[0] ) ) ;
now, consider the case of a function (apparently) taking a two-dimensional array:
Code:
enum { SIZE = 10 } ;
void bar( int array2d[][SIZE] )
{
// ...
}
we know better - this function does not take an array at all, but a pointer. we should think of multidimensional arrays in a different way in C:
a 2d array is really a 1d array, each of whose elements is itself a 1d array. it could be equivalently written this way:
Code:
enum { SIZE = 10 } ;
void bar( int (*array2d) [SIZE] )
{
// ...
}
it should begin to become clear now. the type of array2d is "pointer to array of SIZE ints". why does SIZE have to be specified? because it is required for evaluating array subscript operator which requires pointer arithmetic.
array2d actually points to the first of several arrays of ints, and we want to access the third of those arrays: array2d[3] ; this is equivalent to *( array2d + 3 ). note that we are adding 3 to a pointer, and recall that because of pointer arithmetic the address required is 3 * sizeof( *array2d ) bytes past array2d.
in order for the compiler to generate code for this, it needs to know ahead of time what sizeof( *array2d ) is. sizeof( *array2d ) is equivalent to sizeof( int[SIZE] ), therefore the compiler needs to know SIZE at compile time.
it follows that any time you declare a function with an argument which is a multi-dimensional array, you need to specify the size of every dimension except the first; the sizes of those dimensions must be constants known at compile time.
part 2
------
if it's not possible to know the sizes of the dimensions until run time, there are several options. the simplest is to use a std::vector<> (which is much like a java array):
Code:
#include <vector>
void foobar( std::vector< std::vector<int> >& two_d_vec )
{
// set all elements to 8
for( std::size_t i = 0 ; i < two_d_vec.size() ; ++i )
for( std::size_t j = 0 ; j < two_d_vec[i].size() ; ++j )
two_d_vec[i][j] = 8 ;
}
int main()
{
typedef std::vector<int> array1d_type ;
typedef std::vector<array1d_type> array2d_type ;
// create a 5 X 4 array of int initialized to zero
array2d_type a( 5U, array1d_type( 4U ) ) ;
foobar(a) ;
}
a second option is to use an array of pointers:
Code:
void foobar2( int** array, ind rows, int cols )
{
// set all elements to 8
for( int i = 0 ; i < rows ; ++i )
for( int j = 0 ; j < cols ; ++j )
array[i][j] = 8 ;
}
int main()
{
int ROWS = 5, COLS = 4 ;
int** array = new int* [ ROWS ] ;
for( int i = 0 ; i < ROWS ; ++i )
array[i] = new int[COLS] ;
foobar2( array ) ;
for( int i = 0 ; i < ROWS ; ++i )
delete[] array[i] ;
delete[] array ;
}
a third option is to just use a one dimensional array to simulate a 2d array, and do the pointer arithmetic on our own:
Code:
void foobar3( int* array, int rows, int cols )
{
// set all elements to 8
for( int i = 0 ; i < rows ; ++i )
for( int j = 0 ; j < cols ; ++j )
array [ i*cols + j ] = 8 ;
}
int main()
{
int ROWS = 5, COLS = 4 ;
int* array = new int[ ROWS * COLS ] ;
foobar3( array ) ;
delete[] array ;
}
an option which combines the above two ideas:
Code:
void foobar2( int** array, ind rows, int cols )
{
// set all elements to 8
for( int i = 0 ; i < rows ; ++i )
for( int j = 0 ; j < cols ; ++j )
array[i][j] = 8 ;
}
int main()
{
int ROWS = 5, COLS = 4 ;
int** array = new int* [ROWS] ;
array[0] = new int[ ROWS * COLS ] ;
for ( int i = 1 ; i < ROWS ; ++i )
array[i] = array[i-1] + COLS ;
foobar2( array ) ;
delete[] array[0] ;
delete[] array ;
}
Bookmarks