I'm Java programmer and I'm struggling with this simple stuff.
How can I return this multidimensional array? Does it have to return a ** pointer? How can I get it in another file?
static MoveDirection ghost_moves[GHOSTS_SIZE][4];
MoveDirection** get_ghost_moves() {
return ghost_moves;
}
A 2D array is not a pointer to a pointer. Arrays and pointers are fundamentally different types in C and C++. An array decays into a pointer to its first element (hence the frequent confusion between the two), but it only decays at the first level: if you have a multidimensional array, it decays into a pointer to an array, not a pointer to a pointer.
The proper declaration of get_ghost_moves is to declare it as returning a pointer to an array:
static MoveDirection ghost_moves[GHOSTS_SIZE][4];
// Define get_ghost_moves to be a function returning "pointer to array 4 of MoveDirection"
MoveDirection (*get_ghost_moves())[4] {
return ghost_moves;
}
This syntax syntax is extremely confusing, so I recommend making a typedef for it:
// Define MoveDirectionArray4 to be an alias for "array of 4 MoveDirections"
typedef MoveDirection MoveDirectionArray4[4];
MoveDirectionArray4 *get_ghost_moves() {
return ghost_moves;
}
I believe that you want the following:
MoveDirection ( * get_ghost_moves() ) [GHOSTS_SIZE][4];
In the above get_ghost_moves is a function returning a pointer to an array of array of MoveDirection, with dimensions GHOSTS_SIZE and 4.
I found the following two sites very useful for learning how to understand C declarations:
Reading C type declarations
cdecl - converts C declarations into words.
#define MAX 20
char canopy[20][MAX];
typedef char frank[MAX];
frank friend[MAX];
frank *getList()
{
return friend;
}
void test(int n)
{
frank *list = getList();
int i;
for (i = 0; i < 5; i++ )
{
printf("list[%d] %s\n\r", i, list[i]);
}
}
int main(void)
{
int i, nf;
for (i = 0; i < 5; i++ )
{
snprintf(friend[i], MAX, "test%d", i);
printf("test[%d] %s \n\r", i, friend[i]);
}
test(5);
return 0;
}
No, just a single * is all you need. The key is to think about how your data is arranged in memory: an array is just a series of items of the same type, laid out contiguously in memory. In this context it doesn't matter what shape or size the array is - you're just returning a pointer to the start of it, which means you're returning the address of the first item.
Of course, whoever you're returning that pointer to will have to know what the shape and size of the array are.
One of the nice things about C and pointers is that everything's just a number, and memory is just a big array of bytes. Once you get comfortable thinking like that, it all falls into place.
A multidimensional array is not an array of pointers. It is a single memory block. It only has meaning inside the scope where it is declared.
You can't cleanly return that as you have here.. you would have to return a MoveDirection[GHOSTS_SIZE][4].
ghost_moves occupies a contiguous set of GHOSTS_SIZE*4 MoveDirections in memory: its equivalent to a MoveDirection*
It cannot be used with a pointer to pointer, but with a single pointer.
If you want to use two operator[]-s to index your array you've got two options:
use a variable of type: MoveDirection (*ghost_moves) [GHOST_SIZE] and then just do ghost_moves[i][j]
this is mostly to have a pointer to pointer, usually is not a good solution: have ghost_moves of type MoveDirection**
for example:
MoveDirection ghost_moves_original[GHOST_SIZE][4];
MoveDirection *ghost_moves[GHOST_SIZE];
ghost_moves[0] = ghost_moves_original;
ghost_moves[1] = ghost_moves_original + GHOST_SIZE;
...
Related
I am not very good at C and I am really confused about double array. Below is an outline of a code I have a question about. Main function calls CreateRandConn function and passes it a 2D array filled with 0 as an argument. CreateRandConn function takes a 2D array as a parameter, changes some of the value in 2DArray from 0 to 1 and returns the changed 2DArray back to main. I want to indicate in the function prototype the return type of CreateRandConn function is a 2D array. How do I indicate that? I don't really understand the syntax. Is what I wrote wrong? Is the way I am passing the 2DArray as a parameter in the function header incorrect? If so, how I do write it? I still get confused about the relationship between pointers and double arrays. Can someone explain it with the below code outline? Hopefully someone knows what my question is...
//Function prototype
int ** CreateRandConn(char * RandRoom[7], int my2DArray[7][7], char * room_dir);
//Function
int ** CreateRandConn(char * RandRoom[7], int my2DArray[7][7], char * room_dir)
{
...
return my2DArray;
}
int main()
{
int 2DArray[7][7] = {0};
2DArray = CreateRandConn(RandRoomArray, my2DArray[7][7], room_dir);
return 0;
}
I don't really understand the syntax.
Ok, so let's recap the basics:
One cannot assign to an array variable.
If an array gets passed to a function it "decays" to a pointer to its 1st element.
A multidimensional array is just an array of arrays. So a 2D-array is a 1D-array of 1D-arrays, a 3D-array is a 1D-array of 2D-arrays, a 4D-array is a 1D-array of 3D-arrays, and so on ...
A pointer p to an array of N elements of type T is to be defined as: T (*p)[N]
Now for you example:
You have
int 2DArray[7][7] = ...;
for the sake of clarity of the following explanations I change this to be
int a[5][7] = ...;
So this then is passed to a function. Where the following happens/applies:
Following 1. above, it is not possible to pass an array, as if it were possible one would assign it to the variable inside the function, as arrays cannot be assigned, one cannot pass an array.
Following 2. above, the function would need to define the related variable as "a pointer to the arrays 1st element".
Following 3. above, the a's 1st element is an int [7]
Following 4. above, a pointer to an int[7] will be defined as: int(*)[7].
So the function's relevant variable would look like:
... func(int (*pa)[7])
pa points to the 1st element of a. As a side note: From this pointer a the function cannot derive how many elements a actually "provides", will say: how many valid element after the one a points to will follow, so this needs to be passed to the function as well:
... func(int (*pa)[7], size_t rows)
From the steps so far we learned, that an array is not passed, but just a pointer to it's 1st element *1 is passed, is copied into the function's local variable (pa here).
From this directly follows that an array cannot be passed back as the function's return value, but just a pointer to an array's element (typically the 1st)
Looking at how a pointer to an array is defined: T (*p)[N] we know need to derive how a function returning a pointer to an array would look. The function's defalcation somewhat needs to become the p above. So taking T as int and N as 7 we then get:
int (*func(int (*pa)[7], size_t rows))[7];
The trivial implementation and usage then would be:
#include <stdlib.h> /* for size_t */
#define ROWS (5)
#define COLS (7)
int (*func(int (*pa)[COLS], size_t rows))[COLS];
int (*func(int (*pa)[COLS], size_t rows))[COLS]
{
for (size_t i = 0; i < rows; ++i)
{
for (size_t j = 0; j < COLS; ++j)
{
pa[i][j] = 0;
}
}
return pa;
}
int main(void)
{
int a[ROWS][COLS];
int (*pa)[COLS] = func(a, ROWS);
return EXIT_SUCCESS;
}
*1
(which sloppy, but wrongly spoken often is referred to as "a pointer to an array is passed", which in general it is not, but just here, as it's a 2D-array, will say the array's elements are arrays themselves).
If you understood the above, then just for completeness following a less strange looking (but also probably less educational ;-)) version of the above function declaration. It may be declared by using a typedef construct hiding away the somehow complicated declaration of the array-pointers as parameter and return type.
This
typedef int (*PA)[COLS];
defines a type pointing a an array of COLS of ints.
So using PA we can instead of
int (*func(int (*pa)[COLS], size_t rows))[COLS];
write
PA func(PA pa, size_t rows))[COLS];
This version is identical to the above.
And yes it looks simpler, but brings along the fact, that pointers pa and the function's return value) are not identifiable as being pointers by just looking at their definition. Such constructs are considered "bad practice" by many fellow programmers.
There are tons of similar questions, but still I could not find any answer relevant for the feature of variable length arrays in C99/C11.
How to pass multidimensional variable length array to a function in C99/C11?
For example:
void foo(int n, int arr[][]) // <-- error here, how to fix?
{
}
void bar(int n)
{
int arr[n][n];
foo(n, arr);
}
Compiler (g++-4.7 -std=gnu++11) says:
error: declaration of ‘arr’ as multidimensional array must have bounds for all dimensions except the first
If I change it to int *arr[], compiler still complains:
error: cannot convert ‘int (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]’ to ‘int**’ for argument ‘2’ to ‘void foo(int, int**)’
Next question, how to pass it by value and how to pass it by reference? Apparently, usually you don't want the entire array to be copied when you pass it to a function.
With constant length arrays it's simple, since, as the "constant" implies, you should know the length when you declare the function:
void foo2(int n, int arr[][10]) // <-- ok
{
}
void bar2()
{
int arr[10][10];
foo2(10, arr);
}
I know, passing arrays to functions like this is not a best practice, and I don't like it at all. It is probably better to do with flat pointers, or objects (like std:vector) or somehow else. But still, I'm a bit curios what is the answer here from a theoretical standpoint.
Passing arrays to functions is a bit funny in C and C++. There are no rvalues of array types, so you're actually passing a pointer.
To address a 2D array (a real one, not array of arrays), you'll need to pass 2 chunks of data:
the pointer to where it starts
how wide one row is
And these are two separate values, be it C or C++ or with VLA or without or whatnot.
Some ways to write that:
Simplest, works everywhere but needs more manual work
void foo(int width, int* arr) {
arr[x + y*width] = 5;
}
VLA, standard C99
void foo(int width, int arr[][width]) {
arr[x][y] = 5;
}
VLA w/ reversed arguments, forward parameter declaration (GNU C extension)
void foo(int width; int arr[][width], int width) {
arr[x][y]=5;
}
C++ w/ VLA (GNU C++ extension, terribly ugly)
void foo(int width, int* ptr) {
typedef int arrtype[][width];
arrtype& arr = *reinterpret_cast<arrtype*>(ptr);
arr[x][y]=5;
}
Big remark:
The [x][y] notation with a 2D array works because the array's type contains the width. No VLA = array types must be fixed at compile-time.
Hence: If you can't use VLA, then...
there's no way to handle it in C,
there's no way to handle it without a proxy class w/ overloaded operator overloading in C++.
If you can use VLA (C99 or GNU C++ extensions), then...
you're in the green in C,
you still need a mess in C++, use classes instead.
For C++, boost::multi_array is a solid choice.
A workaround
For 2D arrays, you can make two separate allocations:
a 1D array of pointers to T (A)
a 2D array of T (B)
Then set the pointers in (A) to point into respective rows of (B).
With this setup, you can just pass (A) around as a simple T** and it will behave well with [x][y] indexing.
This solution is nice for 2D, but needs more and more boilerplate for higher dimensions. It's also slower than the VLA solution because of the extra layer of indirection.
You may also run into a similar solution with a separate allocation for every B's row. In C this looks like a malloc-in-a-loop, and is analogous of C++'s vector-of-vectors. However this takes away the benefit of having the whole array in one block.
There is no clear cut way for doing this but you can use a workaround to treat a 2 dimensional array as a one dimensional array and then reconvert it to a two dimensional array inside the function.
void foo2(int n, int *arr)
{
int *ptr; // use this as a marker to go to next block
int i;
int j;
for(i = 0; i < n; i++)
{
ptr = arr + i*n; // this is the starting for arr[i] ...
for (j = 0; j < n ;j++)
{
printf(" %d ", ptr[j]); // This is same as arr[i][j]
}
}
}
void bar2()
{
int arr[10][10];
foo2(10, (int *)arr);
}
I'm trying to pass an three dimensional array to a function like this:
void example( double*** bar ) {
// Stuff
}
int main() {
double[3][2][3] foo;
// Initialize foo
example( foo );
return 0;
}
This causes the gcc to give me "Invalid pointer type". How am I supposed to be doing this? I could just make the entire argument a one-dimensional array and arrange my data to fit with that, but is there a more elegant solution to this?
edit:
In addition, I can't always specify the length of each sub-array, because they may be different sizes. e.g.:
int* foo[] = { { 3, 2, 1 }, { 2, 1 }, { 1 } };
If it helps at all, I'm trying to batch pass inputs for Neurons in a Neural Network. Each Neuron has a different number of inputs.
just use double*. A multidimensional array is stored contiguously in memory so you are quite welcome to give it your own stride. This is how bitmaps are passed on OpenGL.
A one-dimensional int array decays into an int pointer when passing it to a function. A multi-dimensional array decays into a pointer to an array of the next lowest dimension, which is
void example(double (*bar)[2][3]);
This syntax can be a bit baffling, so you might chose the equivalent syntax:
void example(double bar[][2][3]) {
// Stuff
}
int main() {
double foo[3][2][3];
example(foo);
return 0;
}
The first dimension does not have to be given, it's that part that is "decaying". (Note that the dimensions of arrays are not given on the type as in Java, but on the array name.)
This syntax works for variable-length arrays (VLAs) as well, as long as you pass the dimensions before the array:
void example(int x, int y, double (*bar)[x][y]) {
// Stuff
}
int main() {
double foo[3][2][3];
example(2, 3, foo);
return 0;
}
This feature requires C99 and is not compatible with C++.
If the array size is fixed, you can use:
void example(double bar[][2][3]) {
}
Otherwise, you can pass the size along with the array into the function:
void example(size_t x, size_t y, size_t z, double bar[x][y][z]) {
}
That can't be done in C the way you're thinking of. If you need a function that operates on variable-size multidimensional arrays, you'll either have to pass the sizes (all but one) explicitly to the function, or make a structure and pass that. I generally always make a structure when a 2D or 3D array is called for, even if they're of fixed size. I think it's just cleaner that way, since the structure documents itself.
I'm just a tad confused about initializing multidimensional arrays in C...
This works:
int foo[2][MAX] = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
But this does not:
int foo[2][MAX];
foo = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
How come?
This syntax is for initialization, but in the second case you are using it for assignment which will not work.
type varName = someValue; // this is declaration and initialization
type varName; // this is declaration
varName = someValue; // this is assignment and not initialization
That is initialization can only be done at the declaration time, else it's a normal assignment.
The { syntax is only valid when you're initializing and declaring an array at the same time.
After declaring it, you need to use the complete syntax:
foo[0][0] = 2;
Technically speaking, C only has one-dimensional arrays. You create multidemnsional arrays by making arrays of arrays. The name of an array is converted to a pointer to its first element, and only the outer array is converted to a pointer. It's a pointer to an array of MAX ints, or int(*)[MAX].
As you said, this syntax is used to initialize an array, but in your second piece of code:
int foo[2][MAX];
Here, foo is uninitialized, and then
foo = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
This is assignment, not initialization.
Multidimensional or not, arrays in C are not copyable, which means that there's no way to assign anything to the entire array using core language features after the initialization is complete.
However, it is still possible to copy arrays by using memcpy function. In combination with compound literals it allows you to do what you tried to do. You just have to use a different syntax
int foo[2][MAX];
memcpy(
foo,
(int[2][MAX]) {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
},
sizeof foo);
In C99 (or in gcc as an extension) you can make use of compound literals:
int (*foo)[MAX];
foo = (int [][MAX]) {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
But note that foo must be declared as a pointer to MAX int's (not as a 2D array)
You have misunderstood the concept of 'initialization' and 'assignment`.
For example
int a = 10; // Initialization
Initialization is nothing but declaration + assignment.
But
int a; // Declaration
a = 10; // Assignment
When you do like this-
int foo[2][MAX] = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
internally it came to know 2 rows and MAX columns. It will initialize the whole array.
But-
int foo[2][MAX];
foo = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
Here foo represent the starting address of the array. Here you are trying to assign the values to 2D array. when you are trying to assign values to array it doesn't know how many rows and how many columns are there. so it is not possible and not allowed.
When you want to assign the input to array A better solution is scan it from user/ at run time-
int foo[2][MAX],i,j;
for(i=0;i<2;i++){
for(j=0;j<max;j++)
scanf("%d",&foo[i][j]);
}
For my program I need to pass a 2D array of pointers to a function in a separate file. I've written a similarly-syntaxed file below:
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int state;
int design;
} card_t;
card_t *cardSet[5][5];
void setFirst(card_t *cards[][]) { // <- Error: Array has incomplete element type
cards[0][0]->state = 1;
}
int main() {
setFirst(cardSet); // <- Error: Type of formal parameter 1 is incomplete
return 0;
}
When I change the code to all 1D arrays it compiles fine, but for a 2D array I get the errors shown above. What is the difference between the two cases?
Thanks!
Cameron
if you pass an array to a function, you have to specify the size of the inner array, in your case, instead of void setFirst(card_t *cards[][]), you should specify void setFirst(card_t *cards[][5]).
Why do you need to specify it and not the size of the first dimension?
Since cards is an array of array of card_t pointers, if you want to get to cards[1][0], the compiler will need to know how much to add to the pointer cards - cards is declared: card_t *cards[5][4] it will need to add 4 * sizeof(*card_t) to get to cards[1][0], but if cards is declared: card_t *cards[5][5] it will need to add 5 * sizeof(*card_t) to get to cards[1][0].
As has been mentioned, to pass a 2d array to a function, you need to have every dimension but the first declared.
However, you can also just pass the pointer, as follows. Note that you should always (unless the array dimension is completely fixed and the function that operates on the array only operates within the array's dimension) pass the length of each array, too.
void setFirst(card_t ***cards, size_t n, size_t m) {
if (n > 0 && m > 0) {
cards[0][0]->state = 1;
}
}
Because referencing an array via code[0][0] is the same as *(*(code+0)+0*m), you can pass two pointers instead of array dimensions.
Only the first index is optional. You should definitely mention the second index, because a two dimensional array decays to a pointer to 1d array.
void setFirst(card_t *cards[][5]) {
// ^ Newly added
// ..
}
Also make sure that the pointers are pointing to valid memory locations. Else dereferencing leads to segmentation faults. BTW, is there any reason to have a two dimensional array with pointers. I think you are just complicating the program.
To achieve something similar to what you are trying C99 has variable length arrays. These come particularly handy in function definitions:
void setFirst(size_t n, size_t m, card_t *cards[n][m]) {
...
}
Observe that you have to have the size parameters known at the moment of the array declaration, so you'd have to put them in front.