Create 2D Array Using Size from Parameters in C++

Create 2D array using size from parameters in C++

I like a simple wrapper around a 1D vector:

#include <vector>

class Matrix
{
private:
size_t rows, columns;
std::vector<double> matrix;
public:
Matrix(size_t numrows, size_t numcols) :
rows(numrows), columns(numcols), matrix(rows * columns)
{
}

double & operator()(size_t row, size_t column)
{
return matrix[row * columns + column]; // note 2D coordinates are flattened to 1D
}

double operator()(size_t row, size_t column) const
{
return matrix[row * columns + column];
}

size_t getRows() const
{
return rows;
}
size_t getColumns() const
{
return columns;
}
};

Documentation for std::vector

Usage:

Matrix noiseMap(mapWidth, mapHeight);

C - Can I set the size of a multidimensional array in a function parameter list to something higher than its actual size?

For starters such a declaration of the function main

static void main()

is not standard.

The function should be declared like

int main( void )

If your compiler supports variable length arrays then you may declare the function like

static void fill_array( size_t rows, size_t cols, int ar[][cols] );

and pass a two-dimensional array of any sizes.

Here is a demonstrative program.

#include <stdio.h>

static void fill_array( size_t rows, size_t cols, int a[][cols] )
{
for ( size_t i = 0; i < rows; i++ )
{
for ( size_t j = 0; j < cols; j++ )
{
a[i][j] = i * cols + j;
}
}
}

int main(void)
{
size_t rows;
size_t cols;

printf( "Enter the number of rows: " );
scanf( "%zu", &rows );

printf( "Enter the number of columns: " );
scanf( "%zu", &cols );

int a[rows][cols];

fill_array( rows, cols, a );

for ( size_t i = 0; i < rows; i++ )
{
for ( size_t j = 0; j < cols; j++ )
{
printf( "%2d ", a[i][j] );
}
putchar( '\n' );
}

return 0;
}

Its output might look for example like

Enter the number of rows: 3
Enter the number of columns: 5
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14

How to declare a 2D vector parameter which will accept any size?

For statically sized arrays, use std::array. For dynamically sized arrays use std::vector. Don't ever use raw C arrays unless some weird situation forces it on you.

If you need a multi dimensional array, you can of course use std::vector<std::vector<int>> or similar for std::array. This is easy and convenient since you can do myarray[row][column] (and possibly good enough). But a better performing option is usually to just declare a 1D std::vector<int> with a size of "dimension 1 * dimension 2" and then, when indexing into it, do myvector[row_number * size_of_row + column]. Treating a 1D array as a 2D one is as easy as that and it is likely to perform better since it's friendlier to your CPUs prefetcher and cache hierarchy.

As for declaring a function to accept such arrays - it's straight forward. For example:

void f(const std::array<int, 666>& myarray);
void f(const std::array<std::array<int, 42>, 666>& myarray);
void f(const std::vector<int>& myarray);
void f(const std::vector<std::vector<int>>& myarray);

Why do we need to specify the column size when passing a 2D array as a parameter?

When it comes to describing parameters, arrays always decay into pointers to their first element.

When you pass an array declared as int Array[3] to the function void foo(int array[]), it decays into a pointer to the beginning of the array i.e. int *Array;. Btw, you can describe a parameter as int array[3] or int array[6] or even int *array - all these will be equivalent and you can pass any integer array without problems.

In case of arrays of arrays (2D arrays), it decays to a pointer to its first element as well, which happens to be a single dimensional array i.e. we get int (*Array)[3].

Specifying the size here is important. If it were not mandatory, there won't be any way for compiler to know how to deal with expression Array[2][1], for example.

To dereference that a compiler needs to compute the offset of the item we need in a contiguous block of memory (int Array[2][3] is a contiguous block of integers), which should be easy for pointers. If a is a pointer, then a[N] is expanded as start_address_in_a + N * size_of_item_being_pointed_by_a. In case of expression Array[2][1] inside a function (we want to access this element) the Array is a pointer to a single dimensional array and the same formula applies. The number of bytes in the last square bracket is required to find size_of_item_being_pointed_by_a. If we had just Array[][] it would be impossible to find it out and hence impossible to dereference an array element we need.

Without the size, pointers arithmetics wouldn't work for arrays of arrays. What address would Array + 2 produce: advance the address in Array 2 bytes ahead (wrong) or advance the pointer 3* sizeof(int) * 2 bytes ahead?

How do I pass a 2D array into a function with unknown size in C?

You can pass a multidimensional array with sizes based on other parameters:

void invertImg(int height, int width, unsigned char img[height][width])
{
...

A declaration for this function without parameter names would look like this:

void invertImg(int, int, unsigned char img[*][*]);

Then you can call the function like this:

invertImg(height, width, pixels);

How to pass two dimensional array of an unknown size to a function

Multi-dimensional arrays are not very well supported by the built-in components of C and C++. You can pass an N-dimension array only when you know N-1 dimensions at compile time:

calculateDeterminantOfTheMatrix( int matrix[][123])

However, the standard library supplies std::vector container, that works very well for multi-dimension arrays: in your case, passing vector<vector<int> > &matrix would be the proper way of dealing with the task in C++.

int calculateDeterminantOfTheMatrix(vector<vector<int> > &matrix) {
int res = 0;
for (int i = 0 ; i != matrix.size() ; i++)
for(int j = 0 ; j != matrix[i].size() ; j++)
res += matrix[i][j];
return res;
}

As an added bonus, you wouldn't need to pass dimensions of the matrix to the function: matrix.size() represents the first dimension, and matrix[0].size() represents the second dimension.

why specify column size when pass 2d array into function

While passing an array as an argument to a function, compiler implicitly converts the array reference to the pointer. This can be clearly seen in the case of one dimensional array, like

    int method(int *a)
int method(int a[])

Both these lines are equivalent here (although pointer and array reference are different) because whenever an array appears in an expression, the compiler implicitly generates a pointer to the array's first element, just as if the programmer had written &a[0]. However this rule is not recursive i.e. passing a 2d array is treated as pointer to an array, not a pointer to a pointer.

    int method(int b[3][5]);

is converted to

    int method(int (*b)[5]);

And since the called function doesn't allocate space for the array so size of row is not important, however size of column is still important to provide the size of array. For further reference you can visit here.

How to pass a method the height and width of a 2d array as parameters?

This is a possible solution :

void blackandwhite(int* array, int height, int width)
{
// Array-processing done here.
// array is pointer to int,
// initially points to element myarray[0][0].
// variable height = 2;
// variable width = 4;

}

int main()
{
int myarray[2][4];
blackandwhite(&myarray[0][0], 2, 4);
}

One can find the size of an array i.e. the number of elements in it by the following construct :

int array[8];
int size = sizeof(array)/sizeof(array[0]);

Unfortunately, C arrays are native arrays and do NOT contain any metadata embedded in them. Rows and Columns are just a way of representing/accessing what is essentially linear storage space in memory. AFAIK, there is no way to automatically determine the number of rows/columns of a 2D-array, given a pointer to it (in C).

Hence one needs to pass the number of columns/rows as separate arguments along-with the pointer to the 2D-array as shown in the example above.

More info on a related question here.


UPDATE:

Common pitfall no.1 : Using int** array in param-list
Note that a pointer to a 2 dimensional array of integers is still a pointer to a int.

int** implies that the param refers to a pointer to a pointer to an int, which is NOT the case here.

Common pitfall no.2 : Using int[][] in param-list
Failing to pass the dimension(s) of the array. One need NOT pass the size of the array's 1st dimension (but you may but the compiler will ignore it). The trailing dimensions are compulsory though. So,

// is INVALID!
void blackandwhite(int array[][], int height, int width)

// is VALID, 2 is ignored.
void blackandwhite(int array[2][4], int height, int width)

// is VALID.
void blackandwhite(int array[][4], int height, int width)


Related Topics



Leave a reply



Submit