How does passing an array to another C function work? - c

This is causing me a great deal of confusion.
If I have the following array:
int arr[6];
// I then fill indices 0-5 with ints
And I want to pass that to a function that uses the array as a parameter, what does the function header look like?
Would it be void saveArray(int *arr) or void saveArray (int arr)? And then how would I call the function? saveArray(arr) or saveArray(&arr)?
As I understand it, while that initial array is not a pointer, it effectively acts as one as it decays into a pointer to the first element. So my intuition it that I should pass it like saveArray(arr) and the header should be void saveArray(int *arr). Would that be right?
Why do I want a pointer to the initial array and not just the array itself? What does &arr even represent?

In C, parameters passed in functions can only be passed by value.
In addition to that, in C you can't pass an array as a parameter to a function. However, you can pass by value a pointer to the first cell of the array.
Thus, your function's prototype would be:
void saveArray(int *arr)
which you'd call by
saveArray(arr);

Why do I want a pointer to the initial array and not just the array
itself?
That's because you cannot pass an array to a function. An array is not a first-class object in C unlike int, float, struct etc. This means an array is not copied to the function parameter. What actually gets passed is a pointer to the first element of the array. Therefore, the function parameter should be a pointer to the array element type. Also, you have to pass the length of the array to function as well since that information cannot be had in the function from the pointer that is passed to it.
An array is a different type than a pointer. There are some cases when it decays or is implicitly converted to a pointer to its first element. Therefore, your function should have the prototype
void saveArray(int *arr, int len);
// or
void saveArray(int arr[], int len);
// in main, for example
int arr[6];
saveArray(arr, sizeof arr);
// equivalent to
saveArray(&arr[0], sizeof arr);
What does &arr even represent?
The address of operator & evaluates the address of its operand which must be an lvalue. Here arr is of type int[6], i.e., an array of 6 integers. Therefore &arr is of type int (*)[6], i.e., a pointer to an array of 6 integers. Please note that the value &arr is equal to the base address of the array but its type is not int *. It is a different type and has different pointer arithmetic. This is, in fact, one of the cases where an array does not decay into a pointer to its first element.

Yes
void saveArray(int *arr)
But for it to be useful, pass the array length too.
void saveArray(int *arr, int len)
Otherwise how will you know how long it is?
Call then like so:
saveArray(arr, 6);

The question "Would it be void saveArray(int *arr) or void saveArray (int arr)?" has already been answered. I am going to answer the question "What does &arr even represent?"
In your case, &arr has the same numerical value as &arr[0]. However, if you did something a bit different,
int* arr = malloc(sizeof(int)*6);
Then the numerical value of &arr will be different than that of &arr[0] even though you will be able to call saveArray(arr) without any difference in meaning for both cases.
In the first case, both &arr and &arr[0] are addresses on the stack.
In the second case, &arr is an address on the stack while &arr[0] is an address in the heap.
Hope that helps.

If you use this prototype:
void saveArray(int *arr)
you loose information about the array length (e.g. number of elements).
Unless your function is supposed to operate on arrays with fixed length (e.g. some functions doing 3D math calculations may just consider 3D vectors, with fixed size of 3 double elements), you should specify the array length (e.g. element count) as an additional parameter:
void saveArray(int * arr, int count);
If your function just observes the content of the input array and does not modify it, you can use const to make your code const-correct and more precise:
void saveArray(const int * arr, int count);
Sometimes size_t is used as a type to specify length/count parameters:
void saveArray(const int * arr, size_t count);
About the other option you listed in your question:
void saveArray(int arr)
That is wrong, since in this case arr is just a single integer (not an array).
Instead, in the first (correct) case of passing [const] int*, you passed the address of the first item in the array, and since the array elements are stored in contiguous memory locations, just the address of the first item and the item count define the whole array.
At the call site, you can call your function like this:
int arr[<<some size here>>];
...
saveArray(arr, <<same size as above>>);
Or if you already have a pointer (e.g. since you allocated the array using malloc()), you can just specify the pointer itself:
int* arr;
arr = malloc( numberOfElements * sizeof(int) );
...
saveArray(arr, numberOfElements);

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 *.

Differences when using ** in C

I started learning C recently, and I'm having a problem understanding pointer syntax, for example when I write the following line:
int ** arr = NULL;
How can I know if:
arr is a pointer to a pointer of an integer
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
Isn't it all the same with int ** ?
Another question for the same problem:
If I have a function that receives char ** s as a parameter, I want to refer to it as a pointer to an array of strings, meaning a pointer to an array of pointers to an array of chars, but is it also a pointer to a pointer to a char?
Isn't it all the same with int **?
You've just discovered what may be considered a flaw in the type system. Every option you specified can be true. It's essentially derived from a flat view of a programs memory, where a single address can be used to reference various logical memory layouts.
The way C programmers have been dealing with this since C's inception, is by putting a convention in place. Such as demanding size parameter(s) for functions that accept such pointers, and documenting their assumptions about the memory layout. Or demanding that arrays be terminated with a special value, thus allowing "jagged" buffers of pointers to buffers.
I feel a certain amount of clarification is in order. As you'd see when consulting the other very good answers here, arrays are most definitely not pointers. They do however decay into ones in enough contexts to warrant a decades long error in teaching about them (but I digress).
What I originally wrote refers to code as follows:
void func(int **p_buff)
{
}
//...
int a = 0, *pa = &a;
func(&pa);
//...
int a[3][10];
int *a_pts[3] = { a[0], a[1], a[2] };
func(a_pts);
//...
int **a = malloc(10 * sizeof *a);
for(int i = 0; i < 10; ++i)
a[i] = malloc(i * sizeof *a[i]);
func(a);
Assume func and each code snippet is compiled in a separate translation unit. Each example (barring any typos by me) is valid C. The arrays will decay into a "pointer-to-a-pointer" when passed as arguments. How is the definition of func to know what exactly it was passed from the type of its parameter alone!? The answer is that it cannot. The static type of p_buff is int**, but it still allows func to indirectly access (parts of) objects with vastly different effective types.
The declaration int **arr says: "declare arr as a pointer to a pointer to an integer". It (if valid) points to a single pointer that points (if valid) to a single integer object. As it is possible to use pointer arithmetic with either level of indirection (i.e. *arr is the same as arr[0] and **arr is the same as arr[0][0]) , the object can be used for accessing any of the 3 from your question (that is, for second, access an array of pointers to integers, and for third, access an array of pointers to first elements of integer arrays), provided that the pointers point to the first elements of the arrays...
Yet, arr is still declared as a pointer to a single pointer to a single integer object. It is also possible to declare a pointer to an array of defined dimensions. Here a is declared as a pointer to 10-element array of pointers to arrays of 10 integers:
cdecl> declare a as pointer to array 10 of pointer to array 10 of int;
int (*(*a)[10])[10]
In practice array pointers are most used for passing in multidimensional arrays of constant dimensions into functions, and for passing in variable-length arrays. The syntax to declare a variable as a pointer to an array is seldom seen, as whenever they're passed into a function, it is somewhat easier to use parameters of type "array of undefined size" instead, so instead of declaring
void func(int (*a)[10]);
one could use
void func(int a[][10])
to pass in a a multidimensional array of arrays of 10 integers. Alternatively, a typedef can be used to lessen the headache.
How can I know if :
arr is a pointer to a pointer of an integer
It is always a pointer to pointer to integer.
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
It can never be that. A pointer to an array of pointers to integers would be declared like this:
int* (*arr)[n]
It sounds as if you have been tricked to use int** by poor teachers/books/tutorials. It is almost always incorrect practice, as explained here and here and (
with detailed explanation about array pointers) here.
EDIT
Finally got around to writing a detailed post explaining what arrays are, what look-up tables are, why the latter are bad and what you should use instead: Correctly allocating multi-dimensional arrays.
Having solely the declaration of the variable, you cannot distinguish the three cases. One can still discuss if one should not use something like int *x[10] to express an array of 10 pointers to ints or something else; but int **x can - due to pointer arithmetics, be used in the three different ways, each way assuming a different memory layout with the (good) chance to make the wrong assumption.
Consider the following example, where an int ** is used in three different ways, i.e. p2p2i_v1 as a pointer to a pointer to a (single) int, p2p2i_v2 as a pointer to an array of pointers to int, and p2p2i_v3 as a pointer to a pointer to an array of ints. Note that you cannot distinguish these three meanings solely by the type, which is int** for all three. But with different initialisations, accessing each of them in the wrong way yields something unpredictable, except accessing the very first elements:
int i1=1,i2=2,i3=3,i4=4;
int *p2i = &i1;
int **p2p2i_v1 = &p2i; // pointer to a pointer to a single int
int *arrayOfp2i[4] = { &i1, &i2, &i3, &i4 };
int **p2p2i_v2 = arrayOfp2i; // pointer to an array of pointers to int
int arrayOfI[4] = { 5,6,7,8 };
int *p2arrayOfi = arrayOfI;
int **p2p2i_v3 = &p2arrayOfi; // pointer to a pointer to an array of ints
// assuming a pointer to a pointer to a single int:
int derefi1_v1 = *p2p2i_v1[0]; // correct; yields 1
int derefi1_v2 = *p2p2i_v2[0]; // correct; yields 1
int derefi1_v3 = *p2p2i_v3[0]; // correct; yields 5
// assuming a pointer to an array of pointers to int's
int derefi1_v1_at1 = *p2p2i_v1[1]; // incorrect, yields ? or seg fault
int derefi1_v2_at1 = *p2p2i_v2[1]; // correct; yields 2
int derefi1_v3_at1 = *p2p2i_v3[1]; // incorrect, yields ? or seg fault
// assuming a pointer to an array of pointers to an array of int's
int derefarray_at1_v1 = (*p2p2i_v1)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v2 = (*p2p2i_v2)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v3 = (*p2p2i_v3)[1]; // correct; yields 6;
How can I know if :
arr is a pointer to a pointer of an integer
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
You cannot. It can be any of those. What it ends up being depends on how you allocate / use it.
So if you write code using these, document what you're doing with them, pass size parameters to the functions using them, and generally be sure about what you allocated before using it.
Pointers do not keep the information whether they point to a single object or an object that is an element of an array. Moreover for the pointer arithmetic single objects are considered like arrays consisting from one element.
Consider these declarations
int a;
int a1[1];
int a2[10];
int *p;
p = &a;
//...
p = a1;
//...
p = a2;
In this example the pointer p deals with addresses. It does not know whether the address it stores points to a single object like a or to the first element of the array a1 that has only one element or to the first element of the array a2 that has ten elements.
The type of
int ** arr;
only have one valid interpretation. It is:
arr is a pointer to a pointer to an integer
If you have no more information than the declaration above, that is all you can know about it, i.e. if arr is probably initialized, it points to another pointer, which - if probably initialized - points to an integer.
Assuming proper initialization, the only guaranteed valid way to use it is:
**arr = 42;
int a = **arr;
However, C allows you to use it in multiple ways.
• arr can be used as a pointer to a pointer to an integer (i.e. the basic case)
int a = **arr;
• arr can be used as a pointer to a pointer to an an array of integer
int a = (*arr)[4];
• arr can be used as a pointer to an array of pointers to integers
int a = *(arr[4]);
• arr can be used as a pointer to an array of pointers to arrays of integers
int a = arr[4][4];
In the last three cases it may look as if you have an array. However, the type is not an array. The type is always just a pointer to a pointer to an integer - the dereferencing is pointer arithmetic. It is nothing like a 2D array.
To know which is valid for the program at hand, you need to look at the code initializing arr.
Update
For the updated part of the question:
If you have:
void foo(char** x) { .... };
the only thing that you know for sure is that **x will give a char and *x will give you a char pointer (in both cases proper initialization of x is assumed).
If you want to use x in another way, e.g. x[2] to get the third char pointer, it requires that the caller has initialized x so that it points to a memory area that has at least 3 consecutive char pointers. This can be described as a contract for calling foo.
C syntax is logical. As an asterisk before the identifier in the declaration means pointer to the type of the variable, two asterisks mean pointer to a pointer to the type of the variable.
In this case arr is a pointer to a pointer to integer.
There are several usages of double pointers. For instance you could represent a matrix with a pointer to a vector of pointers. Each pointer in this vector points to the row of the matrix itself.
One can also create a two dimensional array using it,like this
int **arr=(int**)malloc(row*(sizeof(int*)));
for(i=0;i<row;i++) {
*(arr+i)=(int*)malloc(sizeof(int)*col); //You can use this also. Meaning of both is same. //
arr[i]=(int*)malloc(sizeof(int)*col); }
There is one trick when using pointers, read it from right hand side to the left hand side:
int** arr = NULL;
What do you get: arr, *, *, int, so array is a pointer to a pointer to an integer.
And int **arr; is the same as int** arr;.
int ** arr = NULL;
It's tell the compiler, arr is a double pointer of an integer and assigned NULL value.
There are already good answers here, but I want to mention my "goto" site for complicated declarations: http://cdecl.org/
Visit the site, paste your declaration and it will translate it to English.
For int ** arr;, it says declare arr as pointer to pointer to int.
The site also shows examples. Test yourself on them, then hover your cursor to see the answer.
(double (^)(int , long long ))foo
cast foo into block(int, long long) returning double
int (*(*foo)(void ))[3]
declare foo as pointer to function (void) returning pointer to array 3 of int
It will also translate English into C declarations, which is prety neat - if you get the description correct.

What happens when I call a function with an array name as an argument? [duplicate]

This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 9 years ago.
I am reading the TCPL by K&R, when I read something about array and pointer, I write this small code below:
#include <stdio.h>
int sum(int a[])
{
int t = 0;
int length = sizeof(a) / sizeof(a[0]) ;
// printf("%d\n",length);
for(int i = 0; i != length; ++i)
{
t += a[i];
}
return t;
}
int main()
{
int b[5] = {1, 2, 3, 4, 5};
printf("%d\n",sum(b));
return 0;
}
The output answer is 1 NOT 15, then I debug this code by adding printf("%d\n",length); the output length is 1 NOT 5.
The TCPL tells that a array name converts to pointer when the array name used as argument, but the output answer is wrong, so I wonder that:
What happend when call a funcion with array name used as argument?
The array a[] used parameter in sum(int a[]) has storage or not?
I see two styles when calling a array : fun(int a[]); fun(b) and fun(int *a);fun(b),what the difference?
Thx very much :-)
You cannot call a function and pass a whole array; if you use an array name as a function argument, it is implicitly rewritten as ("decays to") a pointer to its first element. It is equivalent to writing
int sum(int *a) { ... }
Thus, within the function, sizeof array, does NOT give you the size of the array, only the size of a pointer to its first element.
So how do you know how many elements there are in the array? You need to pass this number explicitly to functions (or define a macro with the number of elements and use it where needed).
Your third question gets to the heart of the matter: there is no difference between those two as far as the compiler is concerned. Everything about how the argument is passed is the same.
Therefore, in response to your second question, the a parameter doesn't have storage for the underlying array, nor are the members of that array copied. The only storage allocated is for an int * pointer, and that pointer is stored in a. (That somewhat answers your first question as well.)
So, in your function:
int length = sizeof(a) / sizeof(a[0]) ;
is equivalent to
int length = sizeof(int *) / sizeof(int);
which returns 1 on systems where pointers and ints are the same size. If you run this on 64-bit Linux, you will get 2 instead, since pointers are 64 bits and ints are 32 bits.
Calling sizeof on an array declared as follows
int a[5];
will return the size of the array how you currently think it will (ie the full size in bytes of the array - in this case 20 bytes on my machine). When you pass an array like this to a function, the array will decay to a pointer to its first element. Thus when you call sizeof on your function argument you are actually calling it on a pointer type. Had you declared your function to take an int * argument, the error would be more obvious as the type of the variable that you call sizeof is explicit.
There is no problem with your call, and there is no difference between fun(int a[]) and fun(int *a) (expect that it is more obvious to the reader that you expect an array and not any pointer). Bot arguments are a pointer to an int.
Your problem here is how you try to determine the length of the array. As the square brackets are empty, there is no way for the compiler to know how long the array behind a is. You can for example provide the length of the array as a second argument. Note: When calling the function, sizeof(b) will provide the correct length, because the compiler knows its length.
The sizeof() operator can not be used for getting a dynamically allocated array length.
Here you can find examples of the sizeof() using.
When you try to do sizeof(array_ptr) it is actually gives you size of the pointer.
Thus, you have to pass array length as parameter of the function

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.

Resources