Pointer to array as function parameter - c

I wrote a function which takes a pointer to an array to initialize its values:
#define FIXED_SIZE 256
int Foo(int *pArray[FIXED_SIZE])
{
/*...*/
}
//Call:
int array[FIXED_SIZE];
Foo(&array);
And it doesn't compile:
error C2664: 'Foo' : cannot convert parameter 1 from 'int (*__w64 )[256]' to 'int *[]'
However, I hacked this together:
typedef int FixedArray[FIXED_SIZE];
int Foo(FixedArray *pArray)
{
/*...*/
}
//Call:
FixedArray array;
Foo(&array);
And it works. What am I missing in the first definition? I thought the two would be equivalent...

int Foo(int *pArray[FIXED_SIZE])
{
/*...*/
}
In the first case, pArray is an array of pointers, not a pointer to an array.
You need parentheses to use a pointer to an array:
int Foo(int (*pArray)[FIXED_SIZE])
You get this for free with the typedef (since it's already a type, the * has a different meaning). Put differently, the typedef sort of comes with its own parentheses.
Note: experience shows that in 99% of the cases where someone uses a pointer to an array, they could and should actually just use a pointer to the first element.

One simple thing is to remember the clockwise-spiral rule which can be found at
http://c-faq.com/decl/spiral.anderson.html
That would evaluate the first one to be an array of pointers . The second is pointer to array of fixed size.

An array decays to a pointer. So, it works in the second case. While in the first case, the function parameter is an array of pointers but not a pointer to integer pointing to the first element in the sequence.

Related

Ways to represent function with multi-dimensional array parameters

I'm currently learning function that work with multi-dimensional array in C.
Let's say I have
short myArray[10][30].
I have declared following function prototype to work with myArray.
void first(int n, short ar[][30]);
void second(int n, short ar[30]);
void third(int n, short (*ar)[30]);
My understanding is that the ar parameter in both first and third function are equivalent. short ar[][30] in first function is equivalent to the short (*ar)[30] in third function because they are both pointer to array of 30 short.
The ar in second function is different because in short ar[30], ar is a pointer to short, not a pointer to array of 30 short.
Is my understanding correct?
Yes your understanding is correct. 1 and 3 are equivalent. And 2 is also right (But not for passing 2d array - it is correct for passing 1D array). But will clarify a bit the second case.
And the second one that 30 inside of third brackets are not considered by the compiler. You can omit it still the compiler won't complain. Actually here you have passed an 1D array of short that decayed into pointer to the first element (First element being short it is short*). So the second one you can also write as short *ar.
void second(int n, short ar[]);
void second(int n, short* ar );
These two works and they are equivalent in this context. The second one is for passing 1D array something like
second(n, myArray[5]);
The thing is, most of the time array decays into pointer (exception is sizeof operator or Alignof etc). Passing an array to a function is a case where the array decays.
Also you are passing int arrays so it is wrong to write short.(int and short may have same size but it is guaranteed that size of int would be larger than or equal to the size of short). If you used short and then wrote int in the declaration that would have worked.
Edit: The second one is not for passing 2d array. Let's be clear on that. You can't pass 2d array to a function with the prototype declared as the second one. For pointers there are 2 things to consider - it's type and it's value. If you tried to pass a 2d array to the same function that would be illegal. 2d array decays into int (*)[30] which is not in anyway same as int * or int[].
1 and 3 are indeed the same, as would be
void fourth(int n, short ar[10][30]);
because when you pass an array as function parameter, it decays to a pointer to its first parameter, so the compiler sees 1 and 4 as 3.
That explains why this would also be correct:
void fifth(int n, short arr[15][30]);
As it decays to a pointer, the declared size of the first dimension is not used. You are supposed to give the actual size in another way.
But this one is different:
void second(int n, short ar[30]);
and your compiler should raise a warning there because the expected paramater is a pointer to short, when you pass a pointer to an array of 30 short. Of course the pointers will have same value (same address), and common compilers will give expected results, but aliasing a pointer to array and a pointer to element is not allowed by the standard. So please avoid it.
With such a declaration, second should be called as
cr = second(n, arr[0]);
because arr[0] is a short array and will correctly decay to a short *.

difference between &array[0] and &array when passed to a C function

Is there a difference between &array[0] and &array when passed to a C Function. This array is a void* array which currently takes integer as data.
Added the test code
#include <iostream>
#include <conio.h>
using namespace std;
int read_buffer[10] = {0,0,0,0,0,0,0,0,0,0};
int write_buffer[10] = {0,1,2,3,4,5,6,7,8,9};
void WriteBlock(void* SrcPtr)
{
//WriteBlock will use SrcPtr and store the data to a common memory block which ReadBlock will access.
}
void ReadBlock(void* DstPtr)
{
//ReadBlock function will fetch data from readBuffer and put the data back into the *DstPtr.
}
void main()
{
WriteBlock((int*)&write_buffer);
//Is there a difference between these two below calls.
ReadBlock(&read_buffer[0]);
ReadBlock(&read_buffer);
}
Yes, there's a big difference, and it depends on context.
Consider this:-
char arrayA[10];
char *arrayB;
&arrayA[0] and &arrayB[0] both have type char *.
But &arrayA has type char (*)[10] while &arrayB has type char ** - the address of the pointer.
For arrayA, these point to the same address - but for arrayB, they do not! There's a common C misconception that "pointers and arrays are the same". This is a great example of where they are absoluelty not,
See this : http://ideone.com/OcbuXZ
Assuming array is declared
void *array[N];
then the expressions &array[0] and &array will yield the same value (the address of the first element of the array is the same as the address of the array itself), but will have different types.
Expression Type
---------- ----
&array void *(*)[10] -- pointer to 10-element array of `void *`
&array[0] void ** -- pointer to pointer to void
Your function prototype will need to match up with whichever expression you pass. If you call the function as
func(&array);
then the function prototype needs to be
void func(void *(*arrp)[10]) {...}
If you call the function as
func(&array[0]);
then the function prototype needs to be
void func(void **arrp) {...}
although in that case you should pass the size of the array as a separate parameter.
Now, assuming array is declared
void **array = malloc(sizeof *array * N);
then the expressions &array and &array[0] will yield different values and different types.
Expression Type
---------- ----
&array void ***
&array[0] void **
&array will give you the address of the array variable itself, which is different from the address of the heap memory that's been allocated for the array. Again, your function prototype will need to match up with the type of the expression you use.
If array is really an array, then
&array[0] is the pointer to element 0 of array[]
&array is the pointer to the entire array[]
So, these two expressions are of different types. And that's the main difference that may cause your code to fail to compile if you pass the wrong one of the two.
At the low level, however, the two pointers are going to hold the same address.
Yes there is a big different
&array[0]==>void**
AND
&array==>void***
This won't compile, you are using a void * and try to get the first element of it. But what size does it have? The compiler doesn't know. Using int * may compile, if you are not trying something like this:
int main (void) {
int *arr = malloc( 10 );
arr = &arr[0]; // this is ok
arr = &arr; // wrong data type
}
&array returns an int **, &array[0] returns int *. These are different data types.

How to point to an array

I am writing a shader for OpenGL and I need to be able to pass in an array of data. I need to be able to pass by reference because I cannot copy the whole array. I know that you cannot define a pointer to an array of structs with Vertices *v[100]; because this will create an array of pointers.
I think you can pass the memory location of the first element in the c array with bindArrayFunction(&v); but then how should I use it? Would I increase the pointer by the size of the struct to get every vertex?
Any help or comments would be appreciated.
In C and C++, an array is never passed by value.
When an array type appears in a function declaration (as in void f(int a[])), the type is implicitly converted to the corresponding pointer type (as in void f(int* a)).
When you use the name of an array in most expressions, it is implicitly converted to a pointer to its first element. So, given int v[100], when you call f(v), a pointer to the initial element of v is passed. (There are several exceptions to the implicit conversion, most notably when the array is the operand of the sizeof or unary & operator).
Pointer arithmetic is always done in terms of the size of the pointed-to element. So, given v + 1, the array v is implicitly converted to a pointer to its initial element (equivalent to &v[0]) and is incremented by sizeof(int) bytes, to point to v[1].
Just reference it as though it were an array.
void bindArrayFunction(Vertices *v, int size) {
for (int i = 0; i < size; ++i) {
process(v[i]);
}
}
In most situation, an array decays to a pointer to its first element. So if you have a function:
void foo(int *p)
{
printf("%d\n", p[2]);
}
then these two calls are identical:
int array[10];
foo(array);
foo(&array[0]);
In both case, a single pointer is passed to the function, allowing the function to access the entire array.

passing a 2D array to a function

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.

Passing in array to a function

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;

Resources