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.
Related
i have some fix arrays defined that i need to write with a common function:
uint8 myArray_A[3][5];
uint8 myArray_B[3][5];
void doThings(uint8 * in)
{
*in[0][0] = someValue_0
*in[0][1] = someValue_1
}
This function i will call in another function and give the needed Array to it:
void main(void)
{
doThings(myArray_A);
}
Is this the way to do it? Will it work?
Your function takes a pointer to an integer, that is the location of a single integer in your memory space.
It means that as you pass the pointer to your array (that is the address of the 1st element in your array - &myArray_A[0][0]) you lose the structural information that was contained in the definition of myArray_A - the size of the array.
This can, however, be fixed by specifying the array parameters in the function declaration.
This can be either done by defining your array type with typedef int[3][5] my_array_t or by specifying the array size in the parameter void doThings(uint8[3][] in)
Bonus: #define your array sizes so that you can update the size in only a single location and have the change propagate across your code.
do this instead.
uint8 myArray_A[3][5];
uint8 myArray_B[3][5];
void doThings(uint8 in[][5])
{
in[0][0] = someValue_0
in[0][1] = someValue_1
}
If the size of the dimensions varies, then you would need to pass that in somehow, and do your own matrix arithmetic, which is frankly machine-dependent so not a good idea:
void doThings(uint8 * in, int dim1, int dim2)
{
in[0*dim2+0] = someValue_0
in[0*dim2+1] = someValue_1
}
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.
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 have an array/pointer related problem.
I created an int array myArray of size 3. Using a function I want to fill this array.
So I'm calling this function giving her the adress &myArray of the array.
Is the syntax correct for the function declaration`? I'm handing over the pointer to the array, so the function can fill the array elements one by one.
But somehow my array is not filled with the correct values.
In Java I could just give an array to a method and have an array returned.
Any help is appreciated! Thanks!
#include <stdio.h>
int myArray[3];
void getSmth(int *anArray[]);
int main(void)
{
getSmth(&myArray);
}
void getSmth(int *anArray[])
{
for(i=0...)
{
*anArray[i] = tmpVal[i];
}
}
Remove one level of indirection:
#include <stdio.h>
int myArray[3];
void getSmth(int anArray[]);
int main(void)
{
getSmth(myArray);
}
void getSmth(int anArray[])
{
for(i=0...)
{
anArray[i] = tmpVal[i];
}
}
Also, as others have suggested, it would be a good idea to pass the size of the array into getSmth().
No, the syntax is not correct. You have an extra *, making the argument into an array of pointers.
In general, it's better to use:
void getSmth(int *array, size_t length);
since then the function can work on data from more sources, and the length becomes available which is very handy for iterating over the data as you seem to want to be doing.
You'd then call it like so:
int main(void)
{
int a[12], b[53];
getSmth(a, sizeof a / sizeof a[0]);
getSmth(b, sizeof b / sizeof b[0]);
}
Note the use of sizeof to compute (at compile-time) the number of elements. This is better than repeating the numbers from the definitions of the variables.
Right now, your function accepts an int *anArray[] parameter, which is an array of pointers to int. Remove the unneccessary * and your function signature should look simply like this:
void getSmth(int anArray[]); // array of int
or
void getSmth(int *anArray); // pointer to first array element of type int
You should use either int anArray[] or int *anArray (which is effectively the same, because array decays to pointer). You should also make sure that the function knows how big your array is either by agreement or passing it as a parameter for it can not use sizeof for the purpose.
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;
...