G'day all,
I know this has been discussed a lot, but I still cant find what I need. I am pretty new to C and still am getting my head around pointers, namely, pointers to multi-dimensional arrays.
I have looked at examples such as int a[2][3]; int (*p) = a when a is a 2D array, but what does the brackets do?
I am creating a program which has a 2D array as a variable and it needs to pass that array onto an external function to modify it.
My array is initilised like this:
unsigned int node[3][2]={ {PINB,PINC}, {0,0}, {0,0} };
I believe the best way to do this is through pointers but I don't know how to setup the prototype for my function that takes in the 2D array.
This is the function im passing it to and how I call it:
NodeToMIDI(node, i, pMIDIdata);
And this is its prototype: //where "node_pointer" is the 2D array arg.
void NodeToMIDI(unsigned int node_pointer, unsigned int node_select, unsigned int * MidiPacket);
Can someone please explain the syntax and logic behind how to do this. Some of the other threads I have looked at have syntax that is unknown to me. Such as int ** a for example.
Thank-you for any help!
Andrew.
You can pass the array to function naturally only if you know (at compilation-time) the size of the inner array.
The examples you saw, are probably int a[2][3]; int (*p)[3] = a. The brackets means that p is pointer to array of 3 ints, not array of 3 pointers to int. Since you can dereference pointers like arrays, you can use p as if it was an array of arrays of 3 ints (which a is).
In the same way, you can write a prototype like void myfunc(int (*arr)[3]); - If you pass a to this function, it's exactly the same thing like pass array to function that gets pointer.
There is another way to write this prototype: void myfunc(int arr[][3]); - The compiler will understand it in the same way, and some people find this writing more understandable.
The signature you are looking for is:
void NodeToMIDI(unsigned node_pointer[][2], unsigned node_select, unsigned * MidiPacket);
which you would call
NodeToMIDI(node, /*something*/, /*something else*/);
Some background information:
An array behaves a bit like a pointer. if you have char* name = {"John"}; you can access the characters with name[2] = h for example.
Also name[0] (the first element) is the same like you use the pointer name directly. The pointer name refers to the adress of the first element in the array.
So an array of on array is... a pointer to a pointer. This looks like that what you described.
int ** a;
So this is an int pointer which referes to another int pointer which refers to a specific adress.
So you can take unsigned int** arrayOfArray as a function parameter.
Then you can access the element like you know it from arrays.
arrayOfArray[0][2] = 42;
Related
EDIT: the correct syntax for declaring a function with the return type of array pointer in the example I wrote further below in my code example section should be as follows:
int (*my_function(void))[10]
{
...
}
Important note for future readers who might come across the same question: don't typecast malloc! Just don't. Thanks to user3386109 for that one. Further reading on the why.
Thanks to Andrew Henle and Eric Postpischil for their answers.
Here's a really good explanation if anyone wants to read further on the the topic.
Original thread below:
What I want to know
How to return a pointer to array in C.
Why I want to know that
Because it (is?) should be possible to do so.
For what I want it
To return multidimensional arrays from functions.
"Have you tried structs?"
Yes, but this isn't about structs. The point (no pun intended) of this thread is doing it with pointers.
Code example
My example is wrong, thus the reason I'm asking here, but here it go:
int (*)[10]my_function(void) // Should be returning a type of array pointer to 10-elements array. Sure enough it's not.
{
int (*ptr)[10] = (int (*)[10]) malloc(10 * sizeof(int));
return ptr;
}
int main(void)
{
printf("Address of ptr is: %d", my_function());
return 0;
}
As you can see, I'm not sure about how to typecast malloc to type array pointer to 10-elements array as well. If you know how, please let me know.
IMPORTANT NOTE
As far as I know, using double pointers (pointer to pointer) in this case is wrong.
Code example:
int **my_function(void); // WRONG, afaik
Rationale: this video, at 16:22.
I already tried searching online and in some books, they have examples using structs, pointer to array as function arguments, but not this.
If you have some knowledge about this topic, please reply, I'll be grateful.
Arrays can't be passed by value, unless you embed them in a structure. When you pass an array to or from a function, it decays to a pointer to the first element. So the way to return a dynamically-allocated array is as a single pointer.
int *my_function(void) {
int *ptr = malloc(10 * sizeof(int));
return ptr;
}
There's no need to specify the dimension in the type, as this will be ignored.
This is not a multi-dimensional array, it's just a 1-d array of 10 int.
The type declaration int (*ptr)[10] is for an array of 10 pointers to integers, not a pointer to an array of 10 integers.
int (*p)[10] declares a pointer to an array of 10 int.
int (*)[10] is a type that is a pointer to an array of 10 int. However, note that you do not need to cast the result of malloc in C. As a void * used as an initializer or right operand of assignment, it will be automatically converted to the target type.
int (*foo(void))[10] declares a function taking no parameters that returns a pointer to an array of 10 int.
Note that int (*foo(void))[10] can be derived from int (*p)[10] simply by replacing p with foo(void). Generally, to get any return type for a function, write a declaration for an object of that type, then replace the object name with the function name followed by its usual parameter declarations.
This question already has answers here:
Should I use char** argv or char* argv[]?
(10 answers)
Closed 8 years ago.
I've been fiddling around to see if there's any way to retain information about an array's length automatically when passed into a function (see my other question here: Why is this array size "workaround" giving me a warning?), but my question is more about a warning that gcc is giving that doesn't make sense to me.
According to this website (EDIT: I misread the website), char *p[10] declares a pointer to a 10-wide array of chars. But when I tried to pass in a pointer to an array into a function, I got this error message from the compiler:
Here is the rest of the program:
I know that when an array is passed into a function, it decays into a pointer (losing information about its length), but it seems that the declaration itself is decaying. What's going on here?
EDIT: When I replace the char *p[10] with char (*p)[10], it doesn't give the warning anymore, and more importantly, it displays the proper array length: 10. I guess my questions are 1) Why do the parentheses change things? and 2) Is this a well-known workaround or am I relying on some behavior of the compiler that isn't guaranteed? (i.e. that array length info can be passed by indirectly passing in a pointer to it?)
In fact char *p[10] is an array, of length 10, of pointers to char. You are looking for char (*p)[10]. That is a pointer to an array, of length 10, of char.
You might find http://cdecl.org/ a useful resource to help you test your understanding of declarations.
Regarding the discussion surrounding dynamic arrays, you are going to have to accept that once you allocate an array dynamically, the system provides no means for you to recover the length of the array. It is your responsibility to remember that information.
The subject of your question has been answered already but I wanted to address the heart of it, which is "can I encode the length of an array in its type?" Which is in fact what a pointer-to-array does. The real question is whether you can actually gain any brevity or safety from this. Consider that in each scope where you have a declaration of your type, the length still needs to be known a-priori. To show you what I mean let's generalize your example slightly by making 10 a compile-time constant N.
#define N 10
size_t arraylength(char (*arrayp)[N]) {
return sizeof(*arrayp);
}
int main(void) {
char array[N];
assert( arraylength(&array) == N ); //always true
}
So far so good. We didn't have to pass the length of array anywhere. But it's easy to see that anywhere the expression sizeof(*arrayp) is used, we also could have written N. And any place we declare a char(*)[ ], the bracketed length must come from somewhere.
So what if N isn't a compile time constant, and array is either a VLA or a pointer-to-array from malloc? We can still write and call arraysize, but it looks like this:
size_t arraylength(size_t N, char (*arrayp)[N]) {
return sizeof(*arrayp);
}
int main(void) {
size_t N = length_from_somewhere();
char array[N];
assert( arraylength(sizeof(array), &array) == N );
}
In defining arraysize N must still be visible before the declaration of arrayp. In either case, we can't avoid having N visible outside of the declaration of arrayp. In fact, we didn't gain anything over writing arraysize(size_t N, char* array) and passing array directly (which is a bit silly given the purpose of this function.) Both times arraylength could have equally been written return N;
Which isn't to say that array pointers are useless as parameters to functions -- in the opposite situation, when you want to enforce a length, they can provide type checking to make sure somefunc(char (*)[10]); receives a pointer to an array that is really (sans shady casting) 10 elements long, which is stronger than what a construct like [static 10] provides.
Also keep in mind that all of the length measurements above depend on the underlying type being char where length == size. For any larger type, taking the length requires the usual arithmetic e.g.
sizeof(*arrayp)/sizeof((*arrayp)[0])
In C, arrays decay to pointers to their first elements on most uses. In particular, what a function receives is always just a pointer to the first element, the size of the array is not passed with it.
Get a good text on C and read up on arrays.
I've been fiddling around to see if there's any way to retain information about an array's length automatically when passed into a function
The problem is so annoying that lots of programmers would love to have an answer. Unfortunately, this is not possible.
It seems that the declaration itself is decaying
Pointer to an array is not the same as a pointer to a pointer; that is why you are getting an error.
There is no decaying going on in your code, because you are not passing an array in your code sample: instead, you are trying to pass a pointer to an array &p. The pointer to an array of characters is not compatible to the expected type of the function, which is char**. Array size from the declaration is ignored.
You need to keep in mind two things:
1. Arrays are not pointers.
2. Array names decays to pointers (in most cases) when passed as arguments to functions.
So, when you declare
int a[10]; // a is an array of 10 ints
int *b; // b is a pointer to int
both of a and b are of different types. Former is of type int [10] while latter is of type int *.
In case of function parameter
void foo1 (int a[10]); // Actually you are not passing entire array
void foo2 (int a[]); // And that's why you can omit the first dimension.
void foo3 (int *a); // and the compiler interprets the above two third
ain all of the above function declarations is of same data type int *.
Now in your case
unsigned long arraySize(char *p[10]);
you can declare it as
unsigned long arraySize(char *p[]);
and hence
unsigned long arraySize(char **p);
All are equivalent.
char *p[10] char *p[] and char **p all are exactly equivalent but when they are declared as parameter of a function otherwise char *p[10] (an array of 10 pointers to char) and char **p (a pointer to pointer to char)are entirely of different type.
Suggested reading: C-FAQ: 6. Arrays and Pointers explains this in detailed.
Array name itself is a constant pointer. for example int arr[10]={0};
arr contains the address of arr[0]. hence arr equals&arr[0] .
when u pass the arraysize(&p) , you are actually passing a double pointer .
The correct format to pass a array pointer would be arraysize(&p[0]) or arraysizeof(p)
Note Array name is constant pointer , you cant change its value .
int arr[10];
arr++;
is invalid.
In your case you cant find a size of an array in function by passing the array name . it would return size of pointer(4 or 8 depends on your processor .
The method is to pass the size along with the array
func(array_name , array_size);
Question from a past exam paper:
"Which of the following:
int a[4][4], (*b)[4], *c[4], **d;
Could you pass into a function expecting a pointer to a pointer to an int
ie
int funct(int **);
Explain your answer."
The answer is c and d i believe?
I am just struggling to understand why the rest arn't allowed?
Any help would be appreciated.
funct expects an int ** - that is, a pointer-to-a-pointer-to-an-int. d is literally that, so no problem. c works too, since it's an array of pointers-to-int, which will therefore decay into a pointer-to-a-pointer-to-an-int when used in a function call context.
a and b won't work, since they're not compatible types. a is an array-of-arrays-of-int, and b is a a pointer-to-array-of-int. a will decay into a pointer-to-array-of-int when passed as a parameter.
in general if you pass an array to a function it is passed as pointer to first element of the array...
int a[4][4] to a function i.e. fun(a); it is passed as int (*p)[4] so fun parameter must be fun(int (*p)[])
here first element itself is an array of 4 integers
fun(a) ---> fun(int (*p)[])
int (*b)[4] is a pointer to array of 4 integers so calling fun(b) requires parameter must be fun(int (*pt)[])
fun(b) ---> fun(int (*pt)[])
int *c[4] is an array of 4 integer pointers ..so calling fun(c) requires parameter must
be pointer to first element of array. here first element is itself an int pointer..so fun(int **p)
fun(c) ---> fun(int **p)
int **d is double pointer to an int..so calling fun(d) requires parameter must be
fun(int **p)
fun(d) ---> fun(int **p)
If I can add some information on the difference between the above answers.
This - [] has higher precedence than this * when declaring an array. That combined with the assumption that arrays and pointers are always interchangeable (they are not) catches a lot of people out.
Naively one would assume that int *arr[] would be a pointer to an array because read from left to right this is a natural assumption.
However it is actually an array of integer pointers. You want a pointer to an array? Tell C so:
int (*arr)[array_size];
by setting your own precedence.
As Carl has explained only answers c and d are applicable because in the d case you already have a pointer to a pointer and in the c case the array of pointers will decay to a pointer to a pointer when passed as an argument to a function.
If you want a function that will read a and b, the signature needs to change to the following:
int funct(int (*array_name)[array_size]);
Note that in the above here you will need to specify the size of the array that the pointer will point to.
Some good answers on two dimensional arrays and pointers to pointers here and here.
gcc 4.6.2 c89
I have the following 2D array that I want to pass to a function:
char elements[MAX_NUM_ELEMENTS][MAX_STRING_LEN] = {{0}};
My function prototype is:
int get_elements(char **elements)
And I am calling the function like this:
get_elements(elements);
However, I get the following error:
expected ‘char **’ but argument is of type ‘char (*)[128]’
All arrays declay into pointers, so sure why I can't just pass the pointer.
Many thanks for any advice,
"All arrays decay into pointers" is a common misconception about C.
The first few answers in this FAQ clarify the issue.
If the object to pass to your function is defined as:
char elements[MAX_NUM_ELEMENTS][MAX_STRING_LEN];
Your function prototype should not be:
int get_elements(char **elements)
but rather:
int get_elements(char elements[][MAX_STRING_LEN])
or
int get_elements(char (*elements)[MAX_STRING_LEN])
(both forms are equivalent)
The reason for this is the type of the value of an object of type
char [MAX_NUM_ELEMENTS][MAX_STRING_LEN]
is
char (*)[MAX_STRING_LEN] (a pointer to an array of MAX_STRING_LEN chars) and not char ** (a pointer to a pointer of char).
You can cast:
get_elements((char **) elements);
char ** and char[128][128] are obviously different types.
"Two -dimensional Array and Double Pointer are not the Same"
"A two - dimensional Array is a array of pointers"
Is what I learnt/memorized while reading about array and pointer
Say elements- data has memory startin Location 100 ..
And the elements Pointer has memory at Location 50 ..
The element data gets allocated memory from 100 to 100+MAX_NUM_ELEMENTS * MAX_STRING_LEN -1..
And you need to access data from 100 ..
But you are passing element as a double pointer .. so it tries to access ( 50->100->Actual data's) Location instead of accessing ( 50-> 100)'s location ..
If you change the prototype to int get_elements( char *element[]) .. It will work ..
Your prototype looks very broken, it lacks a type name.
And you can't use a "decayed" pointer, since that would lose the information about the dimensions of the array, which are (obviously) needed in order to compute accesses properly.
The best way, in my opinion, is to pass a pointer to the first element, along with the dimensions as needed. For 2D, this would do:
int get_elements(int *elements, size_t width, size_t height);
This also requires that you decide, and adhere to, an in-memory layout for your elements, such as column-major or row-major. This affects how you compute the address for a given element.
int main(){
int right[2][3] = {
{1,4,6}, {2,7,5}
}
....
calc(right);
}
int calc(int ** right){
printf("%i", right[0][0]);
}
I calc function that calculate some numbers based on a matrix, but I dont' know why i get seg fault when I access the variable right within the calc function. does any body know the solution?
edit:
right now that is all it's doing at calc function. I have some calc stuff but it's all commented out trying to figure out how to access this variable.
Two-dimensional arrays in C don't work the way you think they do. (Don't worry, you're not alone -- this is a common misconception.)
The assumption implicit in the code is that right is an array of int * pointers, each of which points to an array of int. It could be done this way -- and, confusingly, the syntax for accessing such an array would be the same, which is probably what causes this misconception.
What C actually does is to make right an array of 12 ints, layed out contiguously in memory. An array access like this
a=right[i][j];
is effectively equivalent to this:
int *right_one_dimensional=(int *)right;
a=right[i*3 + j];
To pass your array to the calc function, you need to do this:
int calc(int *right, size_t d){
// For example
a=right[i*d + j];
}
and then call it like this:
int right[2][3] = {
{1,4,6}, {2,7,5}
};
calc(&right[0][0], 3);
Edit: For more background on this, the question linked to in Binary Worrier's comment is definitely worth looking at.
Although a one-dimensional array is automatically converted to a pointer, the same does not hold for a multi-dimensional array and multi-level pointers.
If you change the order of the calc and main functions (or if you provide a prototype for calc before main), you will get a complaint from the compiler that it can convert right to the type int**.
The reason is that right is declared as an "array of 4 arrays of 3 int". This can be automatically converted to "pointer to array of 3 int" (int (*)[3]), but that is where the conversions stop.
calc on the other hand expects a "pointer to a pointer to int", which is a completely different beast from a "pointer to array of 3 int".
There are two possible solutions:
Change calc to accept a pointer to an array (or array of arrays):
int calc(int right[][3])
Change right to be a pointer to a pointer:
int temp_array[4][3];
int* temp_array2[4] = { temp_array[0], temp_array[1], temp_array[2], temp_array[3] };
int** right = temp_array2;