views:

319

answers:

7

I'd like to test a function that takes runtime-allocated multidimensional arrays, by passing it a hardcoded array.

The function has a signature of void generate_all_paths(int** maze, int size) and the array is defined as int arr[5][5] = {REMOVED}.

I'm not exactly sure how to properly coerce the array for the function (or if that is impossible). Any help would be great.

Thanks.

+6  A: 

This multi dimensional array topic unfortunately confuses so many C++ programmers. Well, here is the solution:

void generate_all_paths(int (*maze)[5], int size);

That is what the function declaration has to look like. An alternative, but fully equivalent is

void generate_all_paths(int maze[][5], int size);

Both are creating a parameter that is a pointer to an array of 5 integers. You can then pass your array of arrays of 5 integers to that function:

generate_all_paths(arr, 5);

Because your array's first element is an array of 5 integers, it will be converted automatically (implicitly) to a pointer to that first element when passed to that function.

In the comments, you have shown you are bound to an int**, because both your inner and outer dimension must have runtime values. A multi-dimensional array can not be used anymore. What you can do for testing purposes then is to create an array of pointers like this:

int store[5 * 5] = { ..... };
int *arr[5] = { store, store + 5, store + 10, store + 15, store + 20 };

Then, actually, you can have your function accept a int**. As the first element of you array then is a int*, it will be converted to a int** automatically. Another way of doing this is keeping the data in the 2 dimensional array, but just creating a "view" structured of pointers to that array:

int *arr[5] = { store[0], store[1], store[2], store[3], store[4] };

Where store is your int[5][5] array. Since store[n] accesses the n'th sub-array of that two-dimensional array and the element type of it is int, the pointer-converted type of it is int*, which will be compatible again.

Johannes Schaub - litb
Is there no way to do this without redefining the function? The static array is just there to test the function, usually I am passing it int** variables (randomly generated, size defined at runtime).
Mike Douglas
you mean, both the inner and outer dimension have different size? or just the inner?
Johannes Schaub - litb
well, then you have to use a int** , and can't use a multi dimensional array. to simulate, you can create an int*[5], and assign to each pointer the address of the next 5-integer area. all integers will be held in a int[5 * 5] array. that's what i would do for testing, then.
Johannes Schaub - litb
Both dimensions are the same size, but the size is passed in as an argument. http://pastie.org/385792 <- is the function that is usually generating the maze.
Mike Douglas
It's because an int[n][n] isn't actually structured the same way as an int**. The second dimension is more or less faked.
chaos
litb, defining int **arr2 and building it based off arr. Worked. Thanks.
Mike Douglas
A: 

arr is a pointer to the multi-dimesional array you have and is actually a pointer to an int. Now since your function accepts a pointer to an int pointer, you need to get the address of arr using: &arr and pass that to the function so that you will have this code:

To coerce the array: Pass &arr to the function. To reference the array inside the func: *maze[x][y]

Lonzo
+1  A: 

And also, why is array a reserved word?

It isn't. You are probably using Visual Studio where it's displayed as a keyword due to its use in C++/CLI as a native managed type. However, this is irrelevant for C++ and Visual Studio is misleading in that regard.

As to your problem: You can simply pass a pointer-to-pointers-to-char and then pass your nested array directly (provided you are working with a dynamically allocated array):

void display(char** array) …

That said, your function assumes a fixed, known array length and some other details. Better would be to use a nested std::vector, or std::string (for instance). Using such existing data types makes your life much easier.

void display(std::vector<std::string> const& array) {
    for (size_t i = 0; i < array.length(); ++i)
        cout << array[i] << endl;
}

To take advantage of this, your calling code needs to be changed as well to use these data structures instead of plain C arrays on chars.

Konrad Rudolph
If you don't specify the number of columns, how does the compiler know how to compute array[i][j]?
Bastien Léonard
Konrad, i think it doesn't happen too often, but your post is at least a bit misleading :) The compiler is only converting the most outer dimension to a pointer to its first element. If he has got a int a[1][2], your function parameter still needs to be void display(int (*array)[2]), still preserving the inner dimension. Or are you referring to this trick: int *v[1] = { a[0], a[1] }; display(v); ? (of course, then void display(int **array) would be fine)
Johannes Schaub - litb
litb: I was referring to dynamically allocated arrays. Not good in hindsight, I'll grant.
Konrad Rudolph
+3  A: 

You can write:

void display(char **a)

And then use a[i][j] to refer to elements in it.

The declaration char ** means "pointer to pointer to integer". To break it down into steps:

char *b = a[i];

That gets you a pointer to the first element of the i'th array in the array-of-arrays.

char c = b[j];

That gets you the j'th element in the array b.

The next problem you'll have is of allocating such an array-of-arrays.

char **arrayOfArrays = new char *[10];

for (int n = 0; n < 10; n++)
    arrayOfArrays[n] = new char[20];

That allocates an array of 10 arrays, each "child" array having 20 characters.

In C/C++, array access syntax is just a way of retrieving a value some distance away from a pointer.

char *p = "Hello";

char *pl = p + 2;   // get pointer to middle 'l'
char l = *pl;       // fetch

char o = p[4];      // use array syntax instead
Daniel Earwicker
+1  A: 

void display(char ** array) should work. Also I don't think that it is a reserved word in standard C/C++.

cagribal
A: 

The best is to use pointers, but Borland C++ admits passing arrays as parameters for functions. Look at this code (includes: iostream and conio):

////////////////////////////////////////////

void ReceivedArray(char x[5]){

for (int i=0; i<5; i++ ) cout << x[i];

}

void main(){

char *x = new char[5];

for (int i=0; i<5; i++ ) x[i]='o';

ReceivedArray(x); getchar(); }

///////////////////////////////////////////////////////////////

For passing 2D arrays (oops! some lines in spanish, sorry!):

(includes: iostream, stdlb, stdio and math)

/////////////////////////////////////////////////

using namespace std;

void ver(int x[][20]){ for(int i=0; i<15; i++) { for(int j=0; j<20; j++) { cout<< x[i][j] <<" "; } cout << "\n"; }

}

void cambiar0(int x[][20]){ int n[255]; for (int i=255; i>=0; i--) n[255-i]=i;

for(int i=0; i<15; i++) for(int j=0; j<20; j++) for(int k=0; k<255; k++) if(x[i][j]==n[k]) { x[i][j]=k; break; }
}

int main(int argc, char* argv[]){ int x[15][20]; char a;

for(int i=0; i<15; i++) for(int j=0; j<20; j++) x[i][j]=rand()%255;

cout << "¿desea ver la matriz? s/n "; cin >> a; if(a=='s') ver(x);

cambiar0(x);

cout << "\n\n"; cout << "¿desea ver la matriz? s/n "; cin >> a; if(a=='s') ver(x);

system("PAUSE"); return 0; }

///////////////////////////////////

Hope this is what you meant.

yelinna
A: 

The Earwicker's answer is missing an important fact. What he is proposing is an array of arrays. For the first this wastes memory for the array of pointers ("char **arrayOfArrays = new char *[10]" is the creation point of this). For the second the array of chars may then not be a continuous block of memory, which is often a problem. The only workaround in C++ is to create a one dimensional array and calculate the indexes when you need them.

char *b = new char[width*height];

then you can refer to element x,y (x is along width, y along height) like this

char c=b[width*y+x];

This may be however a bit slower than the solution above (measured on GCC 3.4.5), so if you are not interested in continuous memory (for example you always access the elements with [][], never by adding integer to a pointer and dereferencing it), then you should use the array af arrays. However, if you are interested in having the continuous memory, e.g. to pass it as initializer to an std::string object or to send it as a whole through a network, you should use the second one.

poliklosio