• Advertisement

Archived

This topic is now archived and is closed to further replies.

quick 2-dimensional array question in C

This topic is 5906 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

i want to pass a 2-dimentional array to a function "by reference" or "by ptr" what is the correct way to do this i have: //----------------------- void func(int Arr[][]) int main() { int Arr[20][20]; func(Arr); } //---------------------- what goes into prototype arg list? thanks

Share this post


Link to post
Share on other sites
Advertisement
quote:
Original post by shizik
i want to pass a 2-dimentional array
to a function "by reference" or "by ptr"

what is the correct way to do this

i have:
//-----------------------
void func(int Arr[][])

int main()
{
int Arr[20][20];
func(Arr);
}
//----------------------

what goes into prototype arg list?

thanks


Well, if you want to pass it by pointer, then,

func(Arr); works just fine because all Arr is is a pointer to a 2D array.

If you want to pass by ref, then in the Prototype, you should have

void func( int &Arr[][]);

-Jason

Share this post


Link to post
Share on other sites
quote:
Original post by scubabbl
If you want to pass by ref, then in the Prototype, you should have

void func( int &Arr[][]);




No, that won't work (besides, AFAIK there are no references in C). You have to specify all array dimensions except the first in the prototype:

void func(int Arr[][20]);

Arrays are always passed "by pointer" in C and C++. If the dimensions are unknown, you should use a pointer argument and pass the dimensions seperately:

void func(int *Arr, int x, int y);



Edited by - spock on November 18, 2001 11:15:19 PM

Share this post


Link to post
Share on other sites
Does that really matter, Oluseyi? I mean isn't a pointer to a pointer to the first element of the array the same as just the pointer to the first element of the array? That's not very well-worded I know, but you know what I mean?
If you have a 2-dimensional array of 3 times 4 integers then wouldn't that basically be just a one-dimensional array of 12 integers?

EDIT: Okay, I just realized that a pointer to a pointer is NOT the same as just a pointer, but still, I do think he could just pass a pointer to the first element of the array along with the dimension of the array, and then do whatever he wants to do with the array in his function.

Edited by - Red Ant on November 19, 2001 5:59:58 AM

Share this post


Link to post
Share on other sites
quote:
Original post by Red Ant
EDIT: Okay, I just realized that a pointer to a pointer is NOT the same as just a pointer, but still, I do think he could just pass a pointer to the first element of the array along with the dimension of the array, and then do whatever he wants to do with the array in his function.

Well, it''s just that you might have problems dereferencing a pointer twice. As far as the function is concerned, it is only obtaining a pointer (which can only be deref''d once), so to be able to do Arr[x][y] you''d have to cast from a pointer to a double pointer, which may not be permitted and so on and so forth.

Then when you''re tired of battling the compiler, you''ll make it a double pointer and get on with life.

Share this post


Link to post
Share on other sites
quote:
Original post by Oluseyi
Shouldn''t that be
void func(int **Arr, int x, int y);  

?


That might be a convenient (syntax-wise) way of doing it, but with that declaration you''re not really passing a 2-dimensional array of ints anymore, are you?

Share this post


Link to post
Share on other sites
quote:
Original post by spock
That might be a convenient (syntax-wise) way of doing it, but with that declaration you''re not really passing a 2-dimensional array of ints anymore, are you?

*sigh...*
  
#include <iostream>

using namespace std;
void function(int *arr, int x, int y)
{
for(int i = 0; i < x; ++i)
{
for(int j = 0; j < y; ++j)
arr[i][j] = i * j;
}
}

void display(int *arr, int x, int y)
{
for(int i = 0; i < x; ++i)
{
for(int j = 0; j < y; ++j)
cout << arr[i][j] << endl;
}
}

int main(int argc, char *argv[])
{
int arr[10][12];
function(arr, 10, 12);
display(arr, 10, 12);
return 0;
}



--------------------Configuration: arr_ptr - Win32 Debug--------------------
Compiling...
arr_ptr.cpp
d:\microsoft visual studio\arr_ptr.cpp(9) : error C2109:
subscript requires array or pointer type
d:\microsoft visual studio\arr_ptr.cpp(9) : error C2106:
''='' : left operand must be l-value
d:\microsoft visual studio\arr_ptr.cpp(18) : error C2109:
subscript requires array or pointer type
d:\microsoft visual studio\arr_ptr.cpp(25) : error C2664:
''function'' : cannot convert parameter 1 from ''int [10][12]'' to ''int *''
Types pointed to are unrelated; conversion requires reinterpret_cast,
C-style cast or function-style cast
d:\microsoft visual studio\arr_ptr.cpp(26) : error C2664:
''display'' : cannot convert parameter 1 from ''int [10][12]'' to ''int *''
Types pointed to are unrelated; conversion requires reinterpret_cast,
C-style cast or function-style cast
Error executing cl.exe.

arr_ptr.exe - 5 error(s), 0 warning(s)

Are we done?

Share this post


Link to post
Share on other sites
Oluseyi, I understand what it is you are trying to prove - it''s just that it''s totally beside the point. When more than one array dimension is unknown you can''t access the elements through the [][] notation anymore, because this requires knowledge of the element layout that the compiler simply doesn''t have.

For the benefit of shizik and other readers, here''s how you might define func():


void func(int *arr, int x, int y)
{
for(int i = 0; i < x; ++i)
{
for(int j = 0; j < y; ++j)
arr[i * y + j] = i * j;
}
}


Oh, and when using C++ (as opposed to C) there''s little reason for messing around with multidimensional arrays like this - use std::vector instead.

Share this post


Link to post
Share on other sites
Or you could write func() like this:

  

void func (int** arr, int x, int y)
{
for(int i = 0; i < x; ++i)
{
for(int j = 0; j < y; ++j)
arr[i][j] = i * j;
}
}



And not have to worry about the i*y + j shiznit.

I''m pretty sure Oluseyi is right on this one. Sure you could do it the other way, but why would you want to?? This is much more clear. Plus if you are passing a 2D array to the other version then you might (I''m not sure) get a type warning/error, and you might have to cast the 2D array (int**) to a 1D array (int*).

And we haven''t even begun to get into semantics..

But whatever...

Share this post


Link to post
Share on other sites
quote:
Original post by Promiscuous Robot
Plus if you are passing a 2D array to the other version then you might (I''m not sure) get a type warning/error, and you might have to cast the 2D array (int**) to a 1D array (int*).


quote:
From my earlier post of the compiler output:
d:\microsoft visual studio\arr_ptr.cpp(25) : error C2664:	''function'' : cannot convert parameter 1 from ''int [10][12]'' to ''int *'' 



He''s absolutely right. Which, of course, means that I''m absolutely right :D.

Also, about using std::vector, the case is even more restrictive there. To declare and use a 2D vector you''d do this:
typedef vector<vector<int> > doublevec_int; // for convenience
doublevec_int arr;
//
void function(vector<int> &v)
{
...
v[j * y + k] = j * k;
...
}

The code above won''t even compile, and I don''t even need to pass it through my compiler to know that. Levels of indirection are very specific in C/C++, and are an integral part of the language. They''re absolutely not interchangeable.

Share this post


Link to post
Share on other sites
quote:
Original post by Promiscuous Robot
Or you could write func() like this:

void func (int** arr, int x, int y)
{
for(int i = 0; i < x; ++i)
{
for(int j = 0; j < y; ++j)
arr[ i ][ j ] = i * j;
}
}

And not have to worry about the i*y + j shiznit.



Perhaps not, but as I keep saying you can't pass that function a 2-dimensional array and expect it to work:


// with func() defined by Promiscuous Robot
int main()
{
int a[20][20];

func(a,20,20); // won't compile

func((int**)a,20,20); // won't work

return 0;
}


In order to get the int** parameter to work as you expect, you'd have to construct an array of pointers to integers:


// with func() defined by Promiscuous Robot
int main()
{
int *a[20];

for(int i = 0; i < 20; ++i)
a[ i ] = new int[20];

func(a,20,20);

return 0;
}


That will work, and while it's a valid technique the parameter to func() is not a 2-dimensional array anymore. In order to avoid the minor syntactic inconvenience of "the i*y + j shiznit" you require the caller to rearrange his data structures - which may be trivial, non-trivial, or even impossible depending on the circumstances.

quote:
Original post by Oluseyi
Also, about using std::vector, the case is even more restrictive there. To declare and use a 2D vector you'd do this:

typedef vector > doublevec_int; // for convenience
doublevec_int arr;
void function(vector &v)
//
{
...
v[j * y + k] = j * k;
...
}

The code above won't even compile, and I don't even need to pass it through my compiler to know that.



I've never stated you could (or should) do anything like that; that's just silly.

quote:

Levels of indirection are very specific in C/C++, and are an integral part of the language. They're absolutely not interchangeable.



Which is pretty much what I've been saying all along. There's a big difference between a 2-dimensional array and anything you can pass to func() as an int**.



Edited by - spock on November 20, 2001 2:13:30 AM

Share this post


Link to post
Share on other sites
Using gamedev's search with the words "multi" and "array", this ground has been covered in many places:
http://www.gamedev.net/community/forums/topic.asp?topic_id=53204
http://www.gamedev.net/community/forums/topic.asp?topic_id=51897
http://www.gamedev.net/community/forums/topic.asp?topic_id=63234

What it comes down to is that there are three ways to do multi-dimensional arrays:
- use an auto C array: int array[5][6][10].
- allocate a single block of memory and do the math of the dereferencing yourself (or write a class to do it).
- allocate multiple blocks in a loop; e.g. for a 2-d int array, you'd allocate col# of int*, then for each of those row blocks you allocate row# of int. This fragments memory and has more memory overhead than the prior example, but it gives you "natural" multi-dim. array semantics (e.g. array[3][5] will do the right thing). This method can also be extended to n dimensions, but requires n-1 loops to allocate/deallocate.

To pass these arrays into functions, you have to know the type. For the second type of array, you will have a Type* regardless of the dimensions you're faking because it was allocated to it. If you use the third type of array, you will have a Type** or Type***, where the number of # is the number of dimensions.

If you want to pass the first array into a function, e.g. int array[5][6][10], its type is int [][6][10]. This means that all but one dimension of the array must be nailed down by the function prototype in order to make it work; if you understand that C internally treats this array as a single block of memory, this should make sense.

If your function is going to work on arrays where the size of all but the first dimension are known, this is fine. If you need your function to work for arbitrary N-dimensional arrays, you need to choose one of the other methods listed above.

Edited by - Stoffel on November 21, 2001 1:04:38 PM

Share this post


Link to post
Share on other sites
Urgh. That looks nasty! Anyway, I got it sorted out a solution, which uses just a big 1d array, which the code can treat like a 2d array. I just cant believe C doesnt let do something like (without typecasting, etc.):

int array[10][10];
func(&array);

void func(int *array) {
...
}


Edited by - Ibanez on November 21, 2001 5:36:58 PM

Share this post


Link to post
Share on other sites

  • Advertisement