Passing a Static Array in a Function which accepts Double Pointer

Here is the code,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<iostream>
using namespace std;
void fun(int **ptr)
{
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 2; j++)
		{
			cout << ptr[i][j] << endl;
		}
	}
}
int main()
{
	int arr[2][2];
for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 2; j++)
			arr[i][j] = i + j; 
	} 
	fun(arr);
	system("pause");
	return 0;
}


This code is giving an error that "arr" can't be passed as an argument in the function. My question is why?

From what I understand, the name of the static array is actually a pointer, i.e. in this case, "arr" in int main is a double pointer and hence, the function should accept this as an argument. So why is it not? Can anyone explain, please?

And also, how can we pass this static array in such a function? Thank you!
Last edited on
multiple dimensional arrays can only be passed when all the dimensions except the last one are fixed/ known. you can pass it as int[2][2] or int[2][]. You can also collapse it to 1-d and reshape it back to 2-d inside, and pass in the sizes. vector < vector < int > > solves the issue too, but may create a page fault problem for some code (I wouldn't worry it here).

the unfortunately magic numbers required example ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<iostream>
void foo(int *f, int rows)
{
 typedef int x[2];  
   x* f2 = (x*)(f);   
   for(int i = 0; i < rows; i++)
   {
    for(int j = 0; j < 2; j++)
	  std::cout << f2[i][j] << " ";
    std::cout << std::endl;
   }        		
}
 
 int main()
 {
     int a[2][10];
	 int * ap = &a[0][0];
	 for(int i = 0; i < 20; i++) ap[i] = i;
	 foo(ap,2);
	 foo(ap,10);	 
 }


But its not trivial to make it work for [anything][anything]. This is kinda Cish .... not exactly modern recommended ideas... vector is the better c++ answer.
Note that the above fooling around is the same net result as passing it [2][] but the casting tricks I did are useful to know, so I did it the convoluted way to illustrate how memory works and how to abuse the syntax to get what you wanted. What if you passed in &a[0][3] and 3?
Last edited on
EDIT ... online compiler knew best...
5:20: warning: typedef naming array of runtime bound [-Wvla]
6:6: warning: pointer to array of runtime bound [-Wvla]
6:13: warning: pointer to array of runtime bound [-Wvla]

I played with it a little more, and was a bit concerned that I got no warnings on my local computer with this version.
Is the VLA in a typedef legal? I turned up all the warnings etc but it did not complain about anything on my work computer. I even did x duh; to see if this hackaround for a VLA would trigger a warning but no luck. Using it directly seems like a VLA and a problem. Using it as a cast mechanic seems safe to me, but I still expected some resistance. If this is well defined, its kinda cool.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

#include<iostream>
void foo(int *f, int rows, int cols)
{
 typedef int x[cols];   // I expected complaining here
  x* f2 = (x*)(f);   
   for(int i = 0; i < rows; i++)
   {
    for(int j = 0; j < cols; j++)
	  std::cout << f2[i][j] << " ";
    std::cout << std::endl;
   }        		
}
 
 int main()
 {
     int a[2][10];
	 int * ap = &a[0][0];
	 for(int i = 0; i < 20; i++) ap[i] = i;
	 foo(ap,2,2);
	 foo(ap,2,5);	 
	 foo(ap,5,2);	 
      	 foo(ap,1,20);	   
 }

Last edited on
I'm sure GCC "correctly" supports it as an extension, but anything with the diagnostic message under -Wvla isn't going to be standard C++.
I've noticed differences in the online compiler's warnings vs. my own compiler's warnings as well. I guess it's just a version thing... I assume you tried -Wall -Wextra -Wpedantic.
@sindu,
If you want to pass a multi-dimensional array then you will need to declare in the function at least all the bounds except the first. (You can declare the first as well if you want to.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
using namespace std;

void fun(int ptr[][2])
{
   for (int i = 0; i < 2; i++)
      for (int j = 0; j < 2; j++) cout << ptr[i][j] << '\n';
}

int main()
{
   int arr[2][2];
   for (int i = 0; i < 2; i++)
      for (int j = 0; j < 2; j++) arr[i][j] = i + j; 
   fun(arr);
}




Assuming storage order (I don't know whether that is enforced by the c++ standard or not), you can also "flatten" it (although I personally see dangers in flipping between 1-d and 2-d arrays).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
using namespace std;

void fun(int *ptr)
{
   for (int i = 0; i < 2; i++)
      for (int j = 0; j < 2; j++) cout << ptr[2*i+j] << '\n';
}

int main()
{
   int arr[2][2];
   for (int i = 0; i < 2; i++)
      for (int j = 0; j < 2; j++) arr[i][j] = i + j; 
   fun(arr[0]);
}



If you are dead set on double pointers (I hope you aren't) then you can do
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
using namespace std;

void fun(int **ptr)
{
   for (int i = 0; i < 2; i++)
      for (int j = 0; j < 2; j++) cout << ptr[i][j] << '\n';
}

int main()
{
   int **arr = new int *[2];   for ( int i = 0; i < 2; i++ ) arr[i] = new int[2];
   
   for (int i = 0; i < 2; i++)
      for (int j = 0; j < 2; j++) arr[i][j] = i + j; 
   fun(arr);
   
   for ( int i = 0; i < 2; i++ ) delete [] arr[i]; delete [] arr;
}



A 1-d array may decay to a "single" pointer in circumstances like passing through function arguments. (This makes array passing efficient - think of the horrendous amounts of copying otherwise.) However, a 2-d array doesn't decay to a double pointer: if you want a double pointer ... then pass a double pointer.
Last edited on
My question is why?
The point is that an 2-dimensional array is not organized like that.

To ensure that a 2-dimensional array of that required size is passed you can do this:
1
2
3
4
5
6
7
8
9
10
void fun(const int (&arr)[2][2])
{
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 2; j++)
		{
			cout << arr[i][j] << endl;
		}
	}
}
Ganado (3943)
I'm sure GCC "correctly" supports it as an extension, but anything with the diagnostic message under -Wvla isn't going to be standard C++.
I've noticed differences in the online compiler's warnings vs. my own compiler's warnings as well. I guess it's just a version thing... I assume you tried -Wall -Wextra -Wpedantic.

I agree. Its wonky code, and probably not safe.

Yes, I had those flags; but I think my install is corrupted in minor ways after a recent update. I need a wipe and redo soon. Its also blowing up sometimes looking for p-threads to compile with some flags, though I used no threads at all in the code (these are like 1/2 page programs).

I am still curious.. is it mad that I made a type that will be bad news if used to make a variable, or is it mad about the typedef or casting? I am probably one of the worst about fully understanding all the undefined behavior traps. This of course was just playing around with the bytes; there isnt a lot of need to reshape memory like this anymore.
Last edited on
Topic archived. No new replies allowed.