Function call with 2d array as argument - c++

I have to call a function which passes 2d array as argument. Function call:
int n;
char ch;
cin>>n;
bool b[n][n];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>ch;
if(ch=='X'){b[i][j]=1;} //reads input from a file
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cout<<evaluate(n,b, i, j); //shows error no matching function for call to evaluate
}
cout<<endl;
}
However,it displays an error no matching function to the call
Here's my function evaluate's declaration:
int evaluate(int n,bool** b,int x,int y){
//body
}
I have tried variations in function declaration as:evaluate(int n,bool b[n][n],int x,int y);
but it gives the same error. Also on removing the 2d array argument,the function works.
Please suggest what my mistake is.

Array names converted to pointer to first element of array when passed to a function. A 2D array is a 1D array having all its elements of type 1D array, i.e it is an array of arrays.
When 2D array name passed to a function then it decays to pointer to first element of the array. As explained above, the element itself is a 1D array, therefore the type of array name becomes pointer to array.
pointer to array and pointer to pointer both are of different types (incompatible with each other). To pass a pointer to array type, you need to declare your function as
int evaluate(int n, bool (*b)[n], int x, int y);
or simply
int evaluate(int n, bool b[][n], int x, int y);

What you need to understand is that a 2D array (a variable declared as int foo[m][n];) is something very different from a double pointer (a variable of type int **foo;). Even though you may use foo[i][j] in both cases, what happens is radically different:
In the case of a 2D array, foo[i][j] is effectively evaluated as foo[i*m + j], all the lines of the 2D array are contiguous in memory, and there is no index structure.
In the case of a double pointer, foo[i][j] first loads a pointer from memory at foo[i], then it loads an int from behind that loaded pointer. That is, foo must point to an array of pointers, that indices into the different line arrays. The line arrays may be independent of each other, they are connected via the index array.
Consequently, you cannot just pass a 2D array as an int** to a function since there is no index array in the 2D array.
However, you can pass a pointer to an array (pseudocode, I omitted declaring some variables):
const int width = ...;
void foo(int (*twoDArray)[width], int x, int y) {
//do something with twoDArray[x][y]
}
int main() {
int myArray[height][width];
foo(myArray, x, y);
}
Unfortunately, width has to be a compile time constant in C++. C can handle dynamic array size, C++ cannot. This severely limits the usability of this approach.

Do you defined your function (callee) before main (caller) function?
you should do like this:
int evaluate(int n,bool** b,int x,int y);
int main(){
//some code
evaluate(n, b, i, j);
//some code
}
int evaluate(int n,bool** b,int x,int y){
//body
}
or this way:
int evaluate(int n,bool** b,int x,int y){
//body
}
int main(){
//some code
evaluate(n, b, i, j);
//some code
}

Related

why do I have to use int &n instead of int n as parameter?

I have to define a function to delete an element in an array, here is the code
void delete_element(int a[], int n, int pos)
{
if (pos>=n)
pos=n-1;
else if (pos<0)
pos=0;
for (int i=pos-1;i<n-1;i++)
{
a[i]=a[i+1];
}
--n;
}
and here is an example:
int n;
printf("Enter the length of the array: ");
scanf("%d", &n);
int A[n]
for (int i=0;i<n;i++)
scanf("%d", &A[i]);
delete_element(A,n,2);
suppose that n=5 and A = {1,2,3,4,5}, after running the above code, it will print out {1,3,4,5,5}
When I use int n as parameter, the function deletes the element I want but the last element will appear twice in the array. I searched and then found out that by using int &n, the problem will be solved but I don't understand the reasons here. I would really appreciate if you could help me with this!
If you use void delete_element(int a[], int n, int pos), the arguments are copied to the function.
So if you decrease n by using --n;, it will only affect the "local" n, the copy.
If you use void delete_element(int a[], int& n, int pos), the parameter n is padded by referece. This means, there is no local copy used in the function but the variable n from the "outside world".
Therefore, --n; will now affect the variable which is given as a parameter to your function.
You could create the same behavior by passing a pointer to the variable. In that case, the address is copied, but instead of the copied address the memory location it points to, the original variable, will be modified.
This function doesn't delete an element in an array actually, because it just overlaps the data at pos with the next data, and the size is not changed.
It seems that n is array's size, so when you use int n, the size is passed as value, so outer n is not changed. And when you use int& n, the size is passed as reference, so n will be changed.
If you want to delete an element in array actually, you may refer to pop_back() or pop_front() function of vector.

How to have a function act on non-argument variables?

I am trying to write a function which will take in multiple indices and do something based on the values in an array at those indices. If I do not declare the arrays as arguments to the function (which will always operate on the same two arrays) I get X/Y was not declared in this scope, but if I do attempt to declare them, I get "error: declaration of ‘X’ as multidimensional array must have bounds for all dimensions except the first," and the bounds are not known until runtime.
Is there any way to do this in a function, or do I have to explicitly write the code in main every time?
Code:
double foo(int A, int B, int t){//A, B, and t are indices
int x = X[A][t]-X[B][t]; //X and Y are 2D arrays
int y = Y[A][t]-Y[B][t];
double d;
//do some math ...
return d;
}
int main{
.
.
.
int X[nPeople][tMax]={0};
int Y[nPeople][tMax]={0};
.
.
.
for(int t=0; t<tMax; t++){
for(int n=0; n<nPeople; n++){
foo(n,a,t);
}
}
.
.
.
return 0;
}
There are multiple ways:
1- Use built-in std::vector library with the following inclusion:
#include <vector>
Vectors are dynamic arrays so when you initialize them they do not have a strict capacity which you can never change. On constrast, they grow larger with each element you push or insert. As far as I can see you are dealing with matrices so you need two dimensional arrays, no problem. Here is the code for it:
std::vector<std::vector<int> >
2- Use global variables. Variables that are declared outside of the functions are considered global so they will be visible to every function beneath it. Altough it is not considered to be good coding practise because of the bugs it may cause in a large scale problem, if you are confident enough that it will not pose a threat to your code safety/cleanness, go ahead use it!
3- Use dynamically allocated arrays and pass the pointers as parameters so that you can deal with any size you want
There are several ways a function can work with data:
Use global data:
std::vector<std::vector<int>> X;
std::vector<std::vector<int>> Y;
double foo(int A, int B, int t){ //A, B, and t are indices
int x = X[A][t]-X[B][t]; // X and Y are global 2D arrays
int y = Y[A][t]-Y[B][t];
double d;
//do some math ...
return d;
}
unfortunately shown too many times in sample code, but (mutable) global have lot of issues (hard to test, hard to re-use the code, hard to reason about the code)
Pass them as arguments:
double foo(const std::vector<std::vector<int>>& X, // X and Y are 2D arrays
const std::vector<std::vector<int>>& Y, // As we can see, so unneeded comment
int A, int B, int t){ //A, B, and t are indices
int x = X[A][t]-X[B][t];
int y = Y[A][t]-Y[B][t];
double d;
//do some math ...
return d;
}
bind them using a class:
class C
{
std::vector<std::vector<int>> X;
std::vector<std::vector<int>> Y;
public:
double foo(int A, int B, int t){ //A, B, and t are indices
int x = X[A][t]-X[B][t]; // X and Y are member 2D arrays (it should be trivial (`this->` might help), so comment not needed neither)
int y = Y[A][t]-Y[B][t];
double d;
//do some math ...
return d;
}
};
care to create coherent classes and avoid god class (which have mostly same default as global).

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

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.

Using two dimensional arrays as parameters

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);