Using two dimensional arrays as parameters - c++

I am trying to make some functions working on two dimensional arrays:
void display_matrix(int**, int, int);
void gen_matrix(int**, int, int);
int main()
{
srand(time(0));
int m=5, n=3;
int my_matrix[m][n];
gen_matrix(my_matrix, m, n);
display_matrix(my_matrix, m, n);
}
I don't know what's wrong, but I get the following error when I call the functions:
[Error] cannot convert 'int ()[(((sizetype)(((ssizetype)n) + -1)) + 1)]' to 'int*' for argument '1' to 'void gen_matrix(int**, int, int)'
I know I can use vector but I am trying to practise and remember the use of pointers and arrays.

Declaring a matrix in the form <type> <name>[<dim1>][<dim2>] defines a block of memory with an implicit stride of dim1. Internally elements are accessed by using multiples of dim1 to reach the correct row and offsetting from there by the second dimension.
the type <type> <name>** is a pointer to an array of pointers - very different. The structure consists of an array of pointers to rows of data. These have to be allocated and linked appropriately before calling the subroutine. There is also no requirement that they are contiguously allocated, and an indirect lookup needs to be done to each an element on each new row.
The advantage is that the rows can be different lengths suiting some algorithms that do not have rectangular structure.

Change the code the following way
const int n = 3;
void display_matrix( int ( * )[n], int );
void gen_matrix( int ( * )[n], int);
int main()
{
srand(time(0));
const int m = 5;
int my_matrix[m][n];
gen_matrix( my_matrix, m );
display_matrix(my_matrix, m );
}
Or you can keep your functions as defined but call them for example as
gen_matrix( reinterpret_cast<int **>( my_matrix ), m, n);

Related

Pointer casting with unknown array size in C++

how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time? Is it somehow possible? (I am doing this because, I pass an 2d array of unknow size to a func. So I cast 2d array to a void pointer and then in that func I want it to recast back.)
int i = 5;
int tab1[i][i];
//cast to void pointer
void *p = (void *)tab1;
//and recast back
int (*tab2)[5] = (int (*)[5])p; //this is working
int (*tab3)[i] = (int (*)[i])p; // but this is not
First I suggest to don't use runtime size for array in C/C++, except you using STL vector as an array. so instead of:
int i = 5;
you must use:
const int i = 5;
except you use Vector that is safe and better than intrinsic arrays.
how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time? Is it somehow possible?
If we talk about C intrinsic array, It is not possible!
why it is not possible?
because C/C++ compiler not aware of your the array size, borders,.... so if you cast your 2d array to 1d array, it is possible. it is the reason that tab2 array can access to first 5th element of your array. really C/C++ compiler cannot distinguish the different of
int a[3][3]
with
int a[3*3]
so You must be aware of at least one dimension of your array:
int main() {
const int i = 3,j = 4;
int tab1[i][j] = {1,2,3,4,5,6,7,8,9,10,11};
//cast to void pointer
void *p = (void *)tab1;
auto a = (int (*)[i][12/i])p;
return 0;
}
In the above example, I aware about i and total count(12) and I calculate the second dimension.
I use auto keyword that very easily inferred the data type.
int i = 5; int tab1[i][i]; is a VLA. It's not standard C++ and should be avoided.
An array-of-pointers-to-arrays (and vector-of-vectors) won't be as efficient as a true 2D array since it's no longer contiguous (int tab1[5][5] is a true 2D array and is stored contiguously in memory, but the dimensions must be known at compile-time).
You can easily create a custom 2D container class that would store the data in a contiguous 1D vector and apply some simple math (x + y*width) to access the elements.
Example:
class Matrix {
std::vector<int> data;
public:
const int width;
const int height;
Matrix(int width, int height) : width(width), height(height), data(width*height) {}
int operator()(int x, int y) const {
return data[y * width + x];
}
int& operator()(int x, int y) {
return data[y * width + x];
}
};
void print(Matrix const& mat) {
for (int y = 0; y < mat.height; y++) {
for (int x = 0; x < mat.width; x++)
std::cout << mat(x, y) << " ";
std::cout << std::endl;
}
}
int main() {
Matrix mat(5, 5);
mat(1, 1) = 1;
mat(2, 2) = 2;
mat(3, 3) = 3;
print(mat);
}
For convenience this overloads the () operator. It's still possible with the [] operator but that will require a proxy class to access the inner dimension(s) and also putting y before x since the dimensions are actually reversed.
int tab1[i][i]; is a non-standard compiler extension for variable length arrays. It is better to avoid this because it is not portable and hard to deal with as you are seeing. You would be better with:
std::vector<std::vector<int>> tab1(i, std::vector<int>(i));
Then your function can simply take this vector:
void foo(const std::vector<std::vector<int>>& array) { ....
how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time?
You can't. You can only cast to a type that is known at compile time.
What you can do is convert to a pointer to first element of the first row: int* p = static_cast<int*>(tab1);. You can then treat the array as one dimensional1. Converting two dimensional indices to one dimensional requires some trivial math: x, y -> x + y * i.
1 As long as you don't mind the technicality that pointer arithmetic across the sub array boundary might technically not be allowed by the standard. But that rule is silly. If you're concerned about this, then you should create a one dimensional array in the first place.
The problem you are having here is that the size of an array must be defined at compile time.
In your case, you have multiple options:
make i a constexpr like constexpr int i = 5;
use a int ** instead:
int i = 5;
int tab1[i][i];
//cast to void pointer
void *p = (void *)tab1;
// cast to int **
auto tab1_p = (int **)p;
// use it like it was an array
tab1_p[1][3] = 5;

passing 2D arrays into a function

I want to pass two 2D arrays into a function in order to copy the whole array. I am using double pointers to do this but it is showing error.
void copy_arr(float **new_table,float **table,int m,int n)
{
//code
return;
}
It is showing error for the 2D array 'new_table' only.
The function calling :
void optimize(float **table,int m,int n)
{
int pivot[2];
find_pivot(table,m,n,pivot);
float new_table[m][n];
//code
copy_arr(new_table,table,m,n);
return;
}
error: cannot convert 'float (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]' to 'float**' for argument '1' to 'void copy_arr(float**, float**, int, int)'
In C doesn't natively exist the concept of multidimensional array. I.e. what we call a bidimensional array:
float fArray[10][10];
Is in reality interpreted by compiler as an array of 10 arrays of float. For this reason the operator [], that can only retrieve values from single arrays, needs to know all following dimensions to access a single element.
Said that you have two ways to pass a multidimensional array, the first case apply when the second dimension is known (extending the concept to multidimensional arrays all other dimensions, but the first, must be know):
void copy_arr(float new_table[][10], float table[][10], int m)
{
//code
return ;
}
If the dimensions are variable you must compute yourself the pointer to the element:
void copy_arr(float *new_table, float *table, int m, int n)
{
//code
memcopy (new_table, table, sizeof(float)*m*n);
//Access last element assuming table[m][n]
printf("This is the last element: %f\n", table + ((m-1)*n + (n-1))*sizeof(float));
return ;
}
In C++ you can use std::vector

Pass array by reference and modify values C++

I want to write a function which takes inArray[3] = {1,2,3,4} and an outArray[3], and modifies outArray[3] within the function to now contain values = {3,4,1,2}.
int main{
int inArray[4] = {1,2,3,4};
int outArray[4];
myFunction(&inArray, &outArray);
}
void myFunction(&inArray, &outArray){
outArray[0] = inArray[2];
outArray[1] = inArray[3];
outArray[2] = inArray[0];
outArray[3] = inArray[1];
}
I'm doing something wrong here, and I don't precisely understand how to pass an array by reference and manipulate the values inside the function.
The fiunction and its call can look the following way
const size_t N = 4;
void myFunction( int ( &inArray )[N], int ( &outArray )[N] )
{
outArray[0] = inArray[2];
outArray[1] = inArray[3];
outArray[2] = inArray[0];
outArray[3] = inArray[1];
}
int main()
{
int inArray[N] = {1,2,3,4};
int outArray[N];
myFunction( inArray, outArray );
}
Take into acccount that your definition of an array
int inArray[3] = {1,2,3,4};
contains a typo and will not be compiled. There must be at least like
int inArray[4] = {1,2,3,4};
or
int inArray[] = {1,2,3,4};
You arrays have size 3, but you try to store 4 elements in them and access the fourth element at [3] (which has undefined behaviour).
Make them bigger, either hardcoding 4 or making everything automatically adjust to the current length of the list of numbers you use to initialise inArray:
int inArray[] = {1,2,3,4}; // automatically sized
int outArray[sizeof inArray / sizeof *inArray];
Then, your function signature should specify the array-of-int of the arguments. There are many ways to do that:
void myFunction(const int inArray[], int outArray[]) // 1
void myFunction(const int* inArray, int* outArray) // 2
void myFunction(const int (&inArray)[4], int (&outArray)[4]) // 3
template <size_t N>
void myFunction(const int (&inArray)[N], int (&outArray)[N]) // 4
The first is clearly the simplest.
The second is equivalent, as when a caller passes array arguments they're allowed to decay to pointers, and that happens even for 1) as the array dimension can only be captured or enforced when accepting arrays by reference, as in the following cases...
The third additionally ensures the array parameters have exactly 4 elements (so suddenly you can't (easily) pass say an array of 10 elements and have it copy over only the first 4).
The fourth accepts any sizes of array, but if used from different calling code on different sized arrays it may create multiple copies of the myFunction code, potentially using more memory for a larger program.
As you're function body hardcodes operations on elements [0] to [3], it won't adjust to do things on elements further into larger arrays, but you have the option of using the N value inside the function body to work out how many elements to operate on.
Array are always passed by reference no need to pass it by reference manually.

Using a 2-d Array in a function

I am trying to solve a dynamic programming problem and I need to take the user input in the form of a 2-d array and use the values from the 2-d array inside the function.
The values of the 2-d array will not be changed when used inside the function.
In the function int dp i am getting the
error:
declaration of 'a' as multidimensional array must have bounds for all dimensions except the first
int max(int a,int b,int c)
{
if(a>=b && a>=c)return a;
if(b>=c && b>=a)return b;
else return c;
}
int max2(int a,int b)
{
if(a>b)return a;
else return b;
}
int dp(int i,int j,int a[][],int p,int q)
{
if((i-1)>=0 && (j-1)>=0 &&(i+1)<p &&(j+1)<q )
return max(a[i][j]+dp(i-1,j+1,a,p,q),a[i][j]+dp(i+1,j+1,p,q),
a[i][j]+dp(i,j+1,p,q));
if(i==0 && j!=0 && (j+1)<q)
return max2(a[i][j]+dp(i+1,j+1,p,q),a[i][j]+dp(i,j+1,p,q));
}
int main()
{
int p,q,r,s,T,a,b,i,j,k;
scanf("%d",&T);
for(a=0;a<T;a++)
{
scanf("%d %d",p,q);
int z[p][q];
int max=0;
for(i=0;i<q;i++)
{
for(j=0;j<p-1;j++)
scanf("%d ",&z[j][i]);
scanf("%d",&z[j+1][i]);
}
for(i=0;i<p;i++)
{
if(dp(i,0,z,p,q)>max)
max=dp(i,0,z,p,q);
}
}
}
It's all in the error message:
declaration of 'a' as multidimensional array must have bounds for all dimensions except the first
Your function signature does not have bounds for a's 2nd dimension:
int dp(int i,int j,int a[][],int p,int q)
// ^^^^^
You need to fill it in with a[][N] where N is whatever the correct bound is. The issue is that you are using VLAs here:
scanf("%d %d",p,q);
int z[p][q];
That is non-standard C++, and basically means you cannot write the signature of dp, since the second bound has to be known as a compile-time constant. You could either make it a single-dimensional array:
int* z = new int[p*q];
int dp(int i, int j, int* a, int p, int q)
// ^^^^^^
or dynamically allocate it in 2 dimensions and just pass it in that way:
int** z = new int*[p];
for (int i = 0; i < p; ++i) {
z[i] = new int[q];
}
int dp(int i, int j, int** a, int p, int q)
// ^^^^^^^
The function dp needs some information to perform meaningful index calculations, either done by the compiler or in the actual inplementation. Either a dimension must be specified in the type or the argument a could be of type int** while its dimensions are provided as separate arguments to dp. As this is C++, a type of std::vector< std::vector< int > > might be more suitable for the task.
You get that error because you cannot leave both the index(row,column) empty in int a[][] in your function declaration. You must have both specified or atleast the value of column index.
Use dynamic declaration
int **z = new int*[p];
for (int i = 0; i < p; i++)
z[i] = new int[q];
Change the parameter int a[][] to int **a
You can't dynamically declare an array on the stack as the size has to be known at compile time. The only way to do this would be by allocating memory for the array on the heap using the new keyword, then you could declare the size at run time.
Far easier, however, would be just to use a container class, or in your case, a container of containers like a vector of vector of ints;
#include <vector>
vector< vector<int> > arrArray(rows, vector<int>(columns));
The syntax might look a bit strange, but breaking it down;
vector<int> - a vector of type int
vector< vector<int> > - a vector of vectors of type int
arrArray(rows, vector<int>(columns)); - here in the first parameter, we are saying; create rows number of vector<int>'s in our array, and the second parameter initalises the array to some value. If it were just a 2D array of int, we might initalise it to 0, or omit the second parameter and rely on the default value of int. But, because our multidimensional vector also contains vectors, we set each row of our main vector to store a vector of int's which holds columns amount of integers.
Now you can access the array like you would any other;
arrArray[2][0] = 5;
You also get all the added benefits that container classes contain, including iterators and a lot of useful class methods for manipulating and checking your array. Once you understand the syntax of creating container classes, you'll find them much easier to work with than arrays. You also don't have to worry about having to manage your own memory, and have the ability to do bounds checking before accessing vector elements.

Passing an array of unknown size by reference in c++

I have 4 sorted integer arrays, which i'm trying to merge into one huge sorted array.
I merge A and B together which gives me another int array called X
Then I merge C and D together which gives me another int array called Y
Finally i merge X and Y together to get Z, which is the final product.
The merge function is doing exactly the same each time, just storing the results into a different array which i want to pass in by reference.
I want to do something like this:
void mergeSort(int arr1[], int arr2, int &result[]){
...
}
But i get the error "Array of reference is not allowed". What is the best way to do this?
The syntax to pass an array by reference in C++ is
int (&result)[size]
note that you need to know the size at compile time. This is probably not what you want to do here and I would suggest to use vector<int>.
You can not write such a way the function because arrays even if they have elements of the same type but with different sizes are different types.
You need to write a template function
For example
template <size_t N1, size_t N2>
void mergeSort( int ( &arr1 )[N1], int ( &arr2 )[N2], int ( &result )[N1+N2])
{
...
}
Otherwise you need to pass to the function sizes of the arrays. For example
void mergeSort( int arr1[], size_t n1, int arr2[], size_t n2, int result[])
{
...
}
In this case it is assumed that the size of array result at least is not less than n1 + n2.
void mergeSort( int *arr1, int *arr2, int sizeOfArray, int *result[] )
{
...
}
I think the answers above give you what is likely a better solution than what you are doing. But if you absolutely insist on taking arrays (by reference and want to leave the size "unspecified"), do the following:
template <unsigned int SIZE> void mergeSort(int arr1[], int arr2, int (&result)[SIZE]){
}
Then you can pass any size arrays to it and the template argument deduction process will figure out the size at compile time.
Please note that this will not work with VLA's if your implementation supports VLA's.