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

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.

Related

What is difference in int* p and (int*) p in C

I couldn't understand use of (int*) p in following program for pointer to an array
#include<stdio.h>
void main()
{
int s[4][2];
int (*p)[2];
int i,j,*pint;
for(i=0;i<=3;i++)
{
p=&s[i];
pint=(int*)p; /*here*/
printf("\n");
for(j=0;j<=1;j++)
printf("%d",*(pint+j));
}
}
can i use *p instead of (int*) p here. thanks in advance
In your code,
pint=(int*)p;
p is of type int (*)[2], i.e., pointer to an array of 2 ints, and pint is a int *. They are not compatible types, so you need the cast.
If you have an array declaration like this
int s[4][2];
then these three pointers have the same value
int ( *p1 )[4][2] = &s;
int ( *p2 )[2] = &s[0];
int *p3 = &s[0][0];
because all the pointers point to the initial address of the extent of memory allocated for the array.
However the pointers have different types because they point to objects of different types.
The first pointer points to the array in whole as a single object.
the second pointer points to an array element that in turn has the array type int[2].
And the third array point to a scalar object of the type int.
So you may not assign directly one pointer to another because they are incompatible though as it was mentioned they have the same value (address).
You need to cast one pointer type to another pointer type explicitly.
This assignment in the original program
p=&s[i];
assigns the address of each element (array of the type int[2]) to the pointer. In fact it is the address of the first element of the array that is it is equal to &s[i][0]. However the first expression and the last expression have different pointer types.
So you need to use casting in this assignment
pint=(int*)p;
Now using the pointer arithmetic in this expression
*(pint+j)
you can traverse all scalar elements of the array initially pointed to by the pointer p.
Pay attention to that this declaration of main
void main()
is nit a standard declaration.
You should declare the function main like
int main( void )

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.

Can I safely cast a &char[] to char**?

Having the following code:
char data[2048];
And a function declared like this:
int f(char** data);
Can I safely call it like this:
f((char**)&data);
If I just use &data, the compiler issue the following warning:
warning C4047: 'function' : 'char **' differs in levels of indirection from 'char (*)[2048]'
No, you cannot.
data is an array. &data is a pointer to an array. It is not a pointer to a pointer. Despite the fact that data decays to a pointer in multiple contexts, it is not itself a pointer - taking the address gives you the address of the array.
If you want a pointer to a pointer to the array, you might try something like this:
char *pdata = data; // data decays to a pointer here
// (a pointer to the first element of the array)
f(&pdata); // Now &pdata is of type char ** (pointer to a pointer).
though, of course, what you actually need will depend on what your usecase is.
A pointer-to-pointer is not an array, nor is it a pointer to an array, nor should it be used to point at an array. Except for the special case where it can be used to point at the first item of an array of pointers, which is not the case here.
A function int f(char** data); cannot accept a char data[2048]; array as parameter. Either the array type needs to be changed, or the function needs to be rewritten.
Correct function alternatives would be:
int f (char* data);
int f (char data[2048]); // completely equivalent to char* data
int f (char (*data)[2048]); // array pointer, would require to pass the address of the array
As stated in this more detailed example:
While an array name may decay into a pointer, the address of the array does not decay into a pointer to a pointer. And why should it? What sense does it make to treat an array so?
Pointers to pointers are sometimes passed to modify the pointers (simple pointer arguments don't work here because C passes by value, which would only allow to modify what's pointed, not the pointer itself). Here's some imaginary code (won't compile):
void test(int** p)
{
*p = malloc ... /* retarget '*p' */
}
int main()
{
int arr[] = {30, 450, 14, 5};
int* ptr;
/* Fine!
** test will retarget ptr, and its new value
** will appear after this call.
*/
test(&ptr);
/* Makes no sense!
** You cannot retarget 'arr', since it's a
** constant label created by the compiler.
*/
test(&arr);
return 0;
}
You can do something like that.
char data[2048];
char *a=&data[0];
char **b=&a;
f(b);

How does passing an array to another C function work?

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);

Passing address of array as a function parameter

Recently, I was debugging one of my programs and found a mistake that I've constantly make, but it was not shown as a warning during compilation, so I've just assume everything was in place and was OK. I a bit confused on what's happening in the code below:
void foo(char b[2]);
char a[2] = {1, 2};
foo(a); // I always assumed that this would pass the entire array to be
// duplicate in stack, guess I was wrong all this while
// Instead the address of the array was passed
void foo(char b[2])
{
// Value of b[0], b[1]?
// Does this mean : 1) b[0] == &a[0]?
// or 2) b[0] == &a[0+2]?
// Compiler didn't complain, so I assume this is a valid syntax
}
When you pass an array as a parameter to a function it decays into a pointer, this is defined in the C standard in 6.7.1:
On entry to the function the value of each argument expression shall be converted to the type
of its corresponding parameter, as if by assignment to the parameter. Array expressions and
function designators as arguments are converted to pointers before the call. A declaration of a
parameter as “array of type” shall be adjusted to “pointer to type,”
This essentially means that in your function declaration it's equivalent to use
void foo(char b[2]); or
void foo(char b[]); or
void foo(char *b)
`
It is valid syntax, and yes, when passing an array the memory address of the first element is copied, but when you dereference the address, you are modifying the original array.
This is the same as the following:
// The array "char b[2]" "decays" to a pointer "char *b"
void foo(char *b)
{
// b[0] == a[0]
// also, b == a (two addresses, both the same)
}
You can read up on how arrays and pointers in C behave very similarly (but not exactly the same). Arrays decay to pointers if they're function arguments (but not anywhere else). The real gotcha here is that on a 64-bit system, sizeof(b) == 8 and sizeof(a) == 2, which is somewhat surprising unless you know about arrays decaying into pointers.
When you declare an array as a function parameter, it is treated as if it were a pointer. Your foo is completely identical to
void foo(char *b)
{
...
}
Arrays decay to pointers. In other words, in some uses (e.g. sizeof(a)) a is an array, but in others where a pointer is expected, the name a means the address of a[0].
b[0] = &a[0] if you do foo(a) as the argument.
If you pass foo((a+1)) then b[0] = &a[1] (you shouldn't do that though since b[1] would be undefined) and so on.
I should make a correction: the address of the array is not passed - it's the address of the array's first element. The simplest way of putting it is:
In C, the value of an array is a pointer to its first element.
If you work with arrays of arrays, you need to supply information about the sizes of arrays after the first dereference:
// either the following or: void foo(char param[][30][20])
void foo(char (*param)[30][20])
{
// ...
}
int main(void)
{
// bar is an array of 10 arrays of 30 arrays of 20 chars.
// its value's TYPE is 'pointer to an array of 30 arrays of 20 chars,
// which is what foo above requires.
char bar[10][30][20];
foo(bar);
}

Resources