Sign in to follow this  
bnosam

Passing a 2D array to a function

Recommended Posts

I have a two dimensional array of chars for a map. But the maps will have varying size depending on the map currently loaded. But when I try something like: void Func(char cMap[][]); I get a lovely error (regarding the subscript of the array). What is the proper way to pass a two dimensional array that you don't know the size of to a function? Thank you! P.s. Please don't suggest a one dimensional array or for me to use boost's multi array.

Share this post


Link to post
Share on other sites
For n dimensional array, you need to specify n-1 dimensions.
void func(char cMap[][255])
Which means hard-coding them at compile-time.

Quote:
Please don't suggest a one dimensional array or for me to use boost's multi array.

I suggest one-dimensional array or boost multi-array. The reason is outlined above - C arrays are hard-coded.

Messing with multiple levels of indirection doesn't solve this problem in a useful way, at least no more than the alternatives would do better or cleaner.

Share this post


Link to post
Share on other sites
Use a pointer to array instead. You could also use a pointer to pointer.

// pointer to array
void Func(char *cMap[]);

// or a pointer to pointer
void Func(char **cMap);

Share this post


Link to post
Share on other sites
Quote:
P.s. Please don't suggest a one dimensional array or for me to use boost's multi array.
Why not?

I'm assuming you're using C++ here. Even if you don't want to use Boost, I think it's generally accepted that the optimal way to handle variable-size multi-dimensional (non-jagged) arrays in C++ is by way of a single 1-d array that is then indexed appropriately.
Quote:
What is the proper way to pass a two dimensional array that you don't know the size of to a function?
This sort of implies the question, 'what is the proper way to create a two-dimensional array that you don't know the size of'? You can do this by creating a dynamic array of pointers and then allocating memory for each entry in the array. Realistically this will most likely work fine, but it can introduce unnecessary overhead in terms of run-time efficiency (more memory allocations, possibly decreased locality of reference), memory usage (potentially greater fragmentation), and code maintenance (both allocating and freeing the memory become more complicated than they would be otherwise). The first two items may or may not matter in practice, but personally I'd consider the third reason to be a sufficient argument for favoring a 1-d array over a 2-d array.

If you don't want to use multi_array for some reason, it's easy enough to create a simple wrapper class or struct that stores the data in a std::vector object and provides indexed access via operator()().

Share this post


Link to post
Share on other sites
I want to be able to pass game maps (of various sizes) to the drawing engine. The maps are 2D arrays. So, I can't hard code in any values because that would make the maps display improperly. When I use
void func(char **cMap);
I get the following error: cannot convert parameter 3 from 'char [30][40]' to 'char **'

Share this post


Link to post
Share on other sites
Quote:
Original post by bnosam
cannot convert parameter 3 from 'char [30][40]'

This looks like your dimensions are fixed at compile time at the call site. In that case, you can use a function template and pass the array by reference.

template<int height, int width>
void Func(const char (&cMap)[height][width])
{
// ...
}

Share this post


Link to post
Share on other sites
Quote:
Original post by bnosam
I want to be able to pass game maps (of various sizes) to the drawing engine. The maps are 2D arrays. So, I can't hard code in any values because that would make the maps display improperly. When I use
void func(char **cMap);
I get the following error: cannot convert parameter 3 from 'char [30][40]' to 'char **'
That doesn't work because the type char[30][40] can only be converted to the type char*[40]. The two methods that match your criteria of no 1D array or no boost multi array is to either make a vector< vector<char> > or to allocate an array of char*s like this:
char **map = new char*[column];
then initialize each char* in the allocated array to like this:
for(int i = 0; i < column; i++)
{
map[i] = new char[width];
}
with caveats galore about dealing with allocation errors and deleting the memory when you are done with it.

edit: I forgot to say that if you allocate your array like this then you can make use the function
void func(char **cMap);

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
Quote:
Original post by bnosam
cannot convert parameter 3 from 'char [30][40]'

This looks like your dimensions are fixed at compile time at the call site. In that case, you can use a function template and pass the array by reference.

template<int height, int width>
void Func(const char (&cMap)[height][width])
{
// ...
}
If the size is fixed that would work, but I am fairly sure that the OP will be reading this data from a file and therefore won't know the size at compile time.

Share this post


Link to post
Share on other sites
It sounds to me that you don't really want to be passing arrays around. What you really should be passing is a map object of some sort.

Share this post


Link to post
Share on other sites
Quote:
Original post by nobodynews
Quote:
Original post by DevFred
Quote:
Original post by bnosam
cannot convert parameter 3 from 'char [30][40]'

This looks like your dimensions are fixed at compile time at the call site. In that case, you can use a function template and pass the array by reference.

template<int height, int width>
void Func(const char (&cMap)[height][width])
{
// ...
}
If the size is fixed that would work, but I am fairly sure that the OP will be reading this data from a file and therefore won't know the size at compile time.

Yeah, I planned on making it read map files. Would changing this to a 1D array make the entire thing a lot simpler?

Share this post


Link to post
Share on other sites
Quote:
Original post by bnosam
Yeah, I planned on making it read map files. Would changing this to a 1D array make the entire thing a lot simpler?
Most likely. One possible idea is to do what SiCrane suggested, and wrap up the data into an actual Map object. And really, you shouldn't be using new and delete directly but std::vector for the most part as it will keep things simple for you. I would lean toward doing something like this:
class Map
{
std::vector<char> grid;
int width;
int height;
public:
Map(int width, int height) : grid(width*height), width(width), height(height) {}
char & GetXY(int x, int y)
{
assert(x >= 0);
assert(x < width);
assert(y >= 0);
assert(y < height);
return grid[y+x*width];
}
// read up on const correctness to understand this function
const char & GetXY(int x, int y) const
{
assert(x >= 0);
assert(x < width);
assert(y >= 0);
assert(y < height);
return grid[y+x*width];
}
int Width() const { return width;}
int Height() const { return height;}
};

Then you could use it like this:
void PrintMap(const Map &map)
{
for(int j = 0; j < map.Height(); j++)
{
for(int i = 0; i < map.Width(); i++)
{
std::cout << map.GetXY(i, j);
}
std::cout << "\n";
}
}

Although what you'd probably want is a member function like Map::Print instead.

Share this post


Link to post
Share on other sites
In C++, here's how you pass any dimension of arrays:

Let's say you have a 2D array:

char two_darray[50][50] = { 0 };

To pass that array to a function, you would type:

function(two_darray);

Your function declaration/header would need to look like this:

void function(char two_darray[][50] );

When making your functions, the first [] is empty, the rest require the size of that dimension.

When passing an array to the function, the only thing you need to pass is the function name, not the [][] associated with it.
--------------------------------------------------------------------------------

This is why it is a good idea to adhere to standards, by the way. Make all of your maps the same size. Just because they don't all have the same things, the arrays can be the same size.

Share this post


Link to post
Share on other sites
Yea it's good to know the C rules, even if you don't need to use them usually.

Superior solution was already given, to pass game map objects instead. That is what the OP wanted anyway. Then you can easily change the underlying implementation from static size to dynamic and how its implemented, boost::array, std::vector, etc.

Share this post


Link to post
Share on other sites
Quote:
Original post by dalindeck
void function(char two_darray[][50] );
The very first response showed an almost identical example. Also, while that is legal C++ I wouldn't really consider that the the preferred C++ solution.

Share this post


Link to post
Share on other sites
I dont have anything new to add here but I would probably go for making the most of C++ and use objects.

You could create a nice templated 2d array class and it will be usefull for years to come. Some of the functionality you could include would be to resize a array, construct arrays, get the number of rows and columns a array has and provide access to entries in the array.

Share this post


Link to post
Share on other sites
Quote:
You could create a nice templated 2d array class and it will be usefull for years to come. Some of the functionality you could include would be to resize a array, construct arrays, get the number of rows and columns a array has and provide access to entries in the array.
Not to discourage you or anyone else from implementing this sort of thing from scratch if that's what you prefer, but you've basically just described multi_array, which has the advantage of already existing and being widely used and thoroughly tested.

Now, the OP did say he didn't want to use Boost. He hasn't said why, but if he (or she) really doesn't want to use Boost, creating a class template as you've described might be the next best option.

Share this post


Link to post
Share on other sites
jyk -

I was speaking to my manager this morning who is quite a way older than me (easily 40 years) and he was telling me about back in the day when calculators cost £600 and a mini cost £500. He was saying that back then people couldnt afford calculators so they had to do arithmatic in their head - this made them better at arithmatic, unlike our generation.

The moral of the story is that the OP clearly isn't up to scratch with programming, using someone elses library is not going to improve his understanding either. I was taught from the ground up with C++, I wonder how much better I would be as a programmer if I had learnt assembly.

Sorry about the rant i'm just against creating a cut and paste culture.

Share this post


Link to post
Share on other sites
Quote:
I was speaking to my manager this morning who is quite a way older than me (easily 40 years) and he was telling me about back in the day when calculators cost £600 and a mini cost £500. He was saying that back then people couldnt afford calculators so they had to do arithmatic in their head - this made them better at arithmatic, unlike our generation.

The moral of the story is that the OP clearly isn't up to scratch with programming, using someone elses library is not going to improve his understanding either. I was taught from the ground up with C++, I wonder how much better I would be as a programmer if I had learnt assembly.

Sorry about the rant i'm just against creating a cut and paste culture.
Sure - I don't disagree with any of that, really. I do think though that gaining a degree of familiarity with the tools and solutions that are available isn't necessarily a bad thing (even if, for whatever reason, you decide not to make use of them).

Also, I wouldn't really consider using the standard library of the language you're programming in (or a library like multi_array, which is sort of close to being standard) to be an example of 'cut-and-paste' programming - it's more just an example of using an appropriate tool to solve a problem, IMO.

Share this post


Link to post
Share on other sites
I completely agree with you, I mean I use STL all the time and I have recently taken a liking to SFML, but if someone ever asked me to write a linked list i could do so with ease.

Share this post


Link to post
Share on other sites
Quote:
Original post by LionMX

You could create a nice templated 2d array class and it will be usefull for years to come.

So... boost multi_array.

Years to come? Then it makes sense to use an externally maintained library.

Quote:
I wonder how much better I would be as a programmer if I had learnt assembly.

Not much, you'd be worse since you'd spend too much time worrying about irrelevant details. Instead, learn economy, team management, statistics and probability. Honest advice. It will make you better than 95% of programmers.

Quote:
He was saying that back then people couldnt afford calculators so they had to do arithmatic in their head - this made them better at arithmatic, unlike our generation.

You are not thinking practically.

- Unlike current generation, don't use a calculator
- You will be better than 99% of all people
- ???
- Profit

But! Are you sure this is what will matter?

Or would it perhaps be more prudent to learn map/reduce, so you'll be able to fire off queries into the cloud where they run on dozens of machines and crunch terabytes of data in a matter of seconds.

Share this post


Link to post
Share on other sites
you can do something like that


void func(int *a, int w, int h){
...
int element = a[i*h+j];
...
}

int a[4][6];
func((int*)a,4,6);




you will create a 2d array but in the function but while sending it to functio you must use it as a 1d array.

sending 2d arrays to inline functions should be possible, why we can't use it?

Share this post


Link to post
Share on other sites
Quote:
Original post by shultays
you can do something like that

*** Source Snippet Removed ***

you will create a 2d array but in the function but while sending it to functio you must use it as a 1d array.

sending 2d arrays to inline functions should be possible, why we can't use it?
That seems kind of awkward and error-prone. Why fight the language like that? Having to track the width and height manually and pass them in as arguments seems like a step in the wrong direction to me (there's really no reason that I can think of to do it that way, given the alternatives that are available).

Why not just create a simple wrapper as suggested several times previously? (One of the previous posters even provided some example code...)

Share this post


Link to post
Share on other sites
Quote:
Original post by LionMX
Sorry about the rant i'm just against creating a cut and paste culture.


Using proper tools does not create a cut and paste culture. The culture is created by people who either do not understand, or refuse to accept, that programming is a thinking discipline.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this