which definition is better? - c

#include<stdio.h>
int main(int argc , char *argv[])
{
int array[2][2] = {{1,100},{1000,10000}};
int *pointer = array;
int *ppointer = &array;
int *pppointer = array[0];
int *ppppointer = &array[0];
printf("%d\n",*pointer);
printf("%d\n",*ppointer);
printf("%d\n",*pppointer);
printf("%d\n",*ppppointer);
return 0;
}
Four pointers are point to the first element of array.
which definition shown above is better?
And I don't known why the same value to array and &array?

The only reason all for of your definitions compile is that your C compiler is too permitting when it comes to pointer type conversions. If you use some switches that make it more pedantic in this regard, it should immediately tell you that only the third initialization is valid, while the rest are erroneous.
In most contexts (with a few exceptions) when array of type T[N] is used in an expression, it "decays" (gets implicitly converted) to pointer type T * - a pointer that points to its first element. In other words, in such contexts for any array A, the A expression is equivalent to &A[0]. The only contexts where array type decay does not occur are unary & operator, sizeof operator and string literal used as an initializer for a char array.
In your example array is a value of int [2][2] type. When used on the right-hand side of initialization it decays to pointer type int (*)[2]. For this reason this is invalid
int *pointer = array;
The right-hand side is int (*)[2], while the left-hand side is int *. These are different pointer types. You can't initialize one with the other.
The
int *ppppointer = &array[0];
is exactly equivalent to the previous one: the right-hand side produces a value of int (*)[2] type. It is invalid for the very same reason.
The &array expression produces a pointer of int (*)[2][2] type. Again, for this reason
int *ppointer = &array;
is invalid.
The only valid initialization yo have in your example is
int *pppointer = array[0];
array[0] is an expression of int [2] type, which decays to int * type - the same type that you have on the left-hand side.
In other words there's no question of which one "better" here. Only one of your initialization is valid, others are illegal. The valid initialization can also be written as
int *pppointer = &array[0][0];
for the reasons I described above. Now, which right-hand side is "better" (array[0] or &array[0][0]) is a matter of your personal preference.
In order to make your other initializations valid, the pointers should be declared as follows
int (*pointer)[2] = array;
int (*ppointer)[2][2] = &array;
int (*ppppointer)[2] = &array[0];
but such pointers will have different semantics from an int * pointer. And you apparently need int * specifically.

Only the third actually does the right thing. All other three are invalid C++ and cause warnings in my C compiler. It is often preferable to write C that is also valid C++, because on some platforms the C++ compiler is the also recommended compiler for C also (MSVC). This also makes it easier to include C code in a C++ project without significant build-system fiddling.
Why does your compiler complain about about 1, 2 and 4? Neither of the expressions on the right hand side have the right type to be converted to int*.
array has type int[2][2] it can be converted to int(*)[2], not int*
&array is a pointer to an int[2][2]
array[x] has actually type int*
&array[x] has type int**

int *pointer = array; //Incorrect
int *ppointer = &array; //Incorrect
int *pppointer = array[0]; //Correct
int *ppppointer = &array[0]; //Incorrect
That's the short version.
Now for the reasons.
The first pointer is incorrect, because you're assigning 'array' (which is a pointer without any further specification)...but not one of int, but one of int *[]
The second pointer is incorrect, since you'd be assigning the address of the pointer...essentially the address of the variable, which holds the pointer to the data.
The third one is correct, because you get a pointer to an int array, regardless of size.
The fourth one is incorrect, since you're copying the address of the first array.
That makes it an int **, and not a int *.
Sorry for the many edits...I must be tired.

Short answer:
$ cat decls.c
int main(void)
{
int array[2][2] = {{1,100},{1000,10000}};
int *pointer = array;
int *ppointer = &array;
int *pppointer = array[0];
int *ppppointer = &array[0];
}
$ clang decls.c -Wall -o decls
decls.c:4:7: warning: incompatible pointer types initializing 'int *' with an
expression of type 'int [2][2]' [-Wincompatible-pointer-types]
int *pointer = array;
^ ~~~~~
decls.c:5:7: warning: incompatible pointer types initializing 'int *' with an
expression of type 'int (*)[2][2]' [-Wincompatible-pointer-types]
int *ppointer = &array;
^ ~~~~~~
decls.c:7:7: warning: incompatible pointer types initializing 'int *' with an
expression of type 'int (*)[2]' [-Wincompatible-pointer-types]
int *ppppointer = &array[0];
^ ~~~~~~~~~
So only the third declaration is correct.
Slightly long answer: when you declare something in C, you declare it using an expression which, when evaluated, gives you the type at the left.
So, if you have a char name[][], then it means that when you have name[2][3], you get a char. This works the other way around: let A = name[3]; how can you can get a char out of A? By doing A[2], so A is a char *.
This is why only the third declaration is correct: because the declaring expression at the left and the expression at the right both have the same type.

None of them are correct (third one will not give error but I don't think it will be the value the poster want).
It should be:
int ** pointer1 = array;
int ** pointer2 = &array; //This one is wrong
int ** pointer3 = array[0]; //This one is not correct in this case
int * ppointer3 = array[0];
int ** pointer4 = &array[0];
int * pointer5 = &array[0][0];
I prefer the first one and last one.
If it is a 1-dimensional array, I would prefer the first one, because it shows the fact that array is basically pointer. If it is a multi-dimensional array, I would use the last one (because it only needs dereference once to get the value, but be careful about the index: for example if you want to get 1000, you will need to use pointer5[2] instead of pointer5[1][1]

They are all equivalent.
&array is the address of the array, which start at the same position as its first element and therefor &array = &array[0]
array is an array but in some case, it can decay into a pointer to its first element, that is why array = &array = &array[0]
As for
int *pppointer = array[0];
my first impression is that this should be wrong. may be someone else can explain.
Update: My guess is that array is considered as a pointer by the compiler here giving:
int *pppointer = (&array)[0] = array[0]

So, you have an array within an array. So the variable "array" is actually a pointer to another pointer.
So if you say:
int *pointer = array;
You've got a type mismatch. *pointer is a pointer to an int, but array is a pointer to another pointer.
When you say:
int *ppointer = &array;
You've still got a type mismatch. &array gives us the address of the pointer to a pointer, which we could only assign to a pointer to a pointer to a pointer.
When you say:
int *pppointer = array[0];
This is correct. Square brackets dereference the array variable. So array[0] actually refers to a pointer to an int, which matches up with *pppointer's type.
When you say:
int *ppppointer = &array[0];
So, we're kind of back to where we started here. array[0] is a pointer to an int, so &array[0] is the address of a pointer to an int, which we could only assign to a pointer to a pointer to an int.
So in the end, the third one is the only one that is actually valid. However, I personally think a better way to accomplish this would be:
int *pointer = *array;

Related

Incompatible pointer type pointer to array and double pointer to array

So i am new to programming and i have this program that i have to write, it has an array of integers and i have to pass it to a function with a pointer and then with a double pointer.
After i wrote the code i had this error that i couldn't find a solution to. The error is :
initialization of 'int **' from incompatible pointer type 'int *'
[-Wincompatible-pointer-type]
The code that i wrote is this:
int main(){
int i;
int arr[]={3,-15,19,0,-984};
int *p=arr;
funzione(p,sizeof(arr)/sizeof(arr[0])); //The first function
for(i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) //print of the single pointer (p)
printf("%d\n",p[i]);
int **g=p; //the error results to be coming from p in this row
for(i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) //print of the double pointer (g)
printf("%d\n",g[i]);
funzione2(g,sizeof(arr)/sizeof(arr[0])); //The second function
return 0;
}
My question is how can i remove this error.
The variable p has the type int * while the initialized variable g has the type int **.
int **g=p; //the error results to be
These pointer types are not compatible and there is no implicit conversion from one pointer type to another.
You need to write
int **g = &p;
for(i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) //print of the double pointer (g)
printf("%d\n",( *g )[i]);
Pay attention to that the for loop can look the same way if you will declare the pointer g also the following way
int ( *g )[5] = &arr;
for(i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) //print of the double pointer (g)
printf("%d\n",( *g )[i]);
Also the expression sizeof(arr)/sizeof(arr[0]) has the unsigned integer type size_t. So it would be better to declare the variable i also as having the unsigned type size_t instead of the signed type int.
size_t i;
Though it is even much better to declare the variable i in the minimal scope where it is used as for example
for( size_t i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) //print of the double pointer (g)
printf("%d\n",( *g )[i]);
And this called function
funzione2(g,sizeof(arr)/sizeof(arr[0])); //The first function
is not the first function as it is written in the comment.:)
Note: This is not a rigorous answer but it is enough for you to continue and solve your compiler issue.
See, p has type int* while g is of type int**. They are incompatible as the error clearly states.
p is a pointer to int while g is a point to a pointer to int.
If you do int **g=&p; the compiler will stop complaining because the types now match.
The & operator takes the address of its argument (think of it like getting a pointer out of a variable). If you apply & to a pointer than you are taking a pointer out p which is a pointer already and this is how you end up with a pointer to pointer.
I suggest you to get a good C book and study pointers properly.

Does "int (*)[]" decay into "int **" in a function parameter?

I posted this question on programmers.stackexchange earlier today. I have always assumed that int (*)[] does not decay into int ** in function parameters but I got multiple responses to my question that suggested that it does.
I have used int (*)[] heavily in my function parameters but now I have become really confused.
When I compile this function using gcc -std=c99 -pedantic -Wall
void function(int (*a)[])
{
sizeof(*a);
}
I get this error message:
c99 -Wall -pedantic -c main.c -o main.o
main.c: In function ‘function’:
main.c:3:11: error: invalid application of ‘sizeof’ to incomplete type ‘int[]’
make: *** [main.o] Error 1
Which suggests that *a has the type int [] and not int *.
Can someone explain if things like int (*)[] decays into int ** in function parameters and give me some reference (from the standard documents perhaps) that proves why it is so.
Only array types converted to pointer to its first element when passed to a function. a is of type pointer to an array of int, i.e, it is of pointer type and therefore no conversion.
For the prototype
void foo(int a[][10]);
compiler interpret it as
void foo(int (*a)[10]);
that's because a[] is of array type. int a[][10] will never be converted to int **a. That said, the second para in that answer is wrong and misleading.
As a function parameter, int *a[] is equivalent to int ** this is because a is of array type .
int (*)[] is a pointer to an array of int.
In your example, *a can decay to int*. But sizeof(*a) doesn't do decaying; it is essentially sizeof(int[]) which is not valid.
a can not decay at all (it's a pointer).
N1256 §6.7.5.3/p7-8
7 A declaration of a parameter as ‘‘array of type’’ shall be
adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword
static also appears within the [ and ] of the array type
derivation, then for each call to the function, the value of the
corresponding actual argument shall provide access to the first
element of an array with at least as many elements as specified by the
size expression.
8 A declaration of a parameter as ‘‘function returning type’’ shall
be adjusted to ‘‘pointer to function returning type’’, as in
6.3.2.1.
int (*)[] is "pointer to array of int". Is it "array of type"? No, it's a pointer. Is it "function returning type"? No, it's a pointer. Therefore it does not get adjusted.
In the case of int (*a)[], sizeof *a does not work for one reason: there is no element count for the array. Without an element count, the size cannot be calculated.
As a consequence of this, any pointer arithmetic on a will not work because it is defined in terms of the size of an object. Since the size is indeterminate for the array, you cannot use pointer arithmetic on the pointer itself. Array notation is defined in terms of pointer arithmetic, so sizeof a[0][0] (or any expression involving a[n] won't work whereas sizeof (*a)[0] will.
This effectively means you can do very little with the pointer. The only things allowed are:
dereferencing the pointer using the unary * operator
passing the pointer to another function (the type of the function parameter must be an array of arrays or a pointer to an array)
getting the size of the pointer (and alignment or type, if your compiler supports either or both of them)
assigning the pointer to a compatible type
If your compiler supports variable-length arrays (VLAs), and you know the size, you could work around the issue by simply adding a line at the start of the function body as in
void
foo (int (*a0)[], size_t m, size_t n)
{
int (*a)[n] = a0;
...
}
Without VLAs, you must resort to some other measure.
It is worth noting that dynamic allocation isn't a factor with int (*)[]. An array of arrays decays to a pointer to an array (like we have here), so they are interchangeable when passing them to a function (sizeof and any _Alignof or typeof keywords are operators, not functions). This means that the array pointed to must be statically allocated: once an array decays to a pointer, no more decay occurs, so you can't say a pointer to an array (int (*)[]) is the same as a pointer to a pointer (int **). Otherwise your compiler would happily let you pass int [3][3] to a function that accepts int ** instead of wanting a parameter of the form int (*)[], int (*)[n], int [][n], or int [m][n].
Consequently, even if your compiler doesn't support VLAs, you can use the fact that a statically allocated array has all of its elements grouped together:
void foo (int (*a0)[], size_t m, size_t n)
{
int *a = *a0;
size_t i, j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
// Do something with `a[i * n + j]`, which is `a0[i][j]`.
}
}
...
}
A dynamically allocated one-dimensional array that is used as a two-dimensional array has the same properties, so this still works. It is only when the second dimension is dynamically allocated, meaning a loop like for (i = 0; i < m; i++) a[i] = malloc (n * sizeof *a[i]); to allocate each sub-array individually, that this principle not work. This is because you have an array of pointers (int *[], or int ** after array decay), which point to the first element of an array at another location in memory, rather than an array of arrays, which keeps all of the items together.
So:
no, int (*p)[] and int **q cannot be used in the same way. p is a pointer to an array, which means all items are grouped together starting the address stored in p. q is a pointer to a pointer, which means the items may be scattered at different addresses that are stored in q[0], q[1], ..., q[m - 1].
sizeof *p doesn't work because p points to an array with an unknown number of elements. The compiler cannot calculate the size of each element, so operations on p itself are very limited.

C pointer to pointer

Does
int **p
and
int *p[1]
mean the same thing? as both can be passed to functions allowing the change the pointer object, also both can be accessed via p[0], *p ?
Update, thanks for your help, tough Memory management seems different. does the access mechanism remain the same
*eg: p[0] becomes *(p+0) & *p (both pointing to something)
Thanks
Not quite.
int **p;
declares a pointer p, which will be used to point at objects of type int *, ie, pointers to int. It doesn't allocate any storage, or point p at anything in particular yet.
int *p[1];
declares an array p of one pointer to int: p's type can decay to int ** when it's passed around, but unlike the first statement, p here has an initial value and some storage is set aside.
Re. the edited question on access syntax: yes, *p == p[0] == *(p+0) for all pointers and arrays.
Re. the comment asking about sizeof: it deals properly with arrays where it can see the declaration, so it gives the total storage size.
void foo()
{
int **ptr;
int *array[10];
sizeof(ptr); // just the size of the pointer
sizeof(array); // 10 * sizeof(int *)
// popular idiom for getting count of elements in array:
sizeof(array)/sizeof(array[0]);
}
// this would always discard the array size,
// because the argument always decays to a pointer
size_t my_sizeof(int *p) { return sizeof(p); }
To simplify things, you could factor out one level of pointers since it's not relevant to the question.
The question then becomes: what's the difference between T* t and T t[1], where T is some type.
There are several differences, but the most obvious one has to do with memory management: the latter allocates memory for a single value of type T, whereas the the former does not (but it does allocate memory for the pointer).
They are not the same thing, although in many cases they can appear to behave the same way.
To make the discussion below flow better, I'm going to take the liberty of renaming your variables:
int **pp; // pointer to pointer
int *ap[1]; // array of pointer
If an expression of type "N-element array of T" appears in most contexts, it will be converted to an expression of type "pointer to T" whose value is the address of the first element in the array (the exceptions to this rule are when the array expression is an operand of either the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration).
So, suppose you write something like
foo(ap);
The expression ap has type "1-element array of pointer to int", but by the rule above it will be converted to an expression of type "pointer to pointer to int"; thus, the function foo will receive an argument of type int **, not int *[1].
On the other side of the equation, subscripting is defined in terms of pointer arithmetic: E1[E2] is defined as *(E1 + E2) where one of the expressions is a pointer value and the other is an integral value. Thus you can use a subscript operator on pp as though it were an array. This is why we can treat dynamically-allocated buffers as though they were regular arrays:
pp = malloc(sizeof *pp * N); // allocate N pointers to int (type of *pp == int *)
if (pp)
{
size_t i;
for (i = 0; i < N; i++)
pp[i] = ...; // set pp[i] to point to some int value
}
Now for some major differences. First of all, array expressions may not be the target of an assignment; for example, you can't write something like
ap = some_new_pointer_value();
As mentioned above, array expressions will not be converted to pointer types if they are the operands of either the sizeof or unary & operators. Thus, sizeof ap tells you the number of bytes required to store a 1-element array of type int *, not a pointer to a pointer to int. Similarly, the expression &ap has type int *(*)[1] (pointer to 1-element array of pointer to int), rather than int *** (which would be the case for &pp).
No, they are not the same.
int **p is a pointer to a pointer to int.
int *p[1] is an array (of length 1) of pointers to int.
They are not same:
int **p
Is a pointer which points to another pointer whose type is int *
while,
int *p[1];
Is an array of size 1 to the type int *
They are different.
int **p
means a pointer to a pointer to an int.
int *p[1]
means an array containing one element, with that element being a pointer to an int.
The second form can be treated the same as the first in some situations, e.g. by passing it to a function.

How to understand the pointer star * in C?

I'm struggling with the pointer sign *, I find it very confusing in how it's used in both declarations and expressions.
For example:
int *i; // i is a pointer to an int
But what is the logic behind the syntax? What does the * just before the i mean? Let's take the following example. Please correct me where I'm wrong:
char **s;
char *(*s); // added parentheses to highlight precedence
And this is where I lose track. The *s between the parantheses means: s is a pointer? But a pointer to what? And what does the * outside the parentheses mean: a pointer to what s is pointing?
So the meaning of this is: The pointer pointing to what s is pointing is a pointer to a char?
I'm at a loss. Is the * sign interpreted differently in declarations and expressions? If so, how is it interpreted differently? Where am I going wrong?
Take it this way:
int *i means the value to which i points is an integer.
char **p means that p is a pointer which is itself a pointer to a char.
int i; //i is an int.
int *i; //i is a pointer to an int
int **i;//i is a pointer to a pointer to an int.
Is the * sign interpreted differently in declarations and expressions?
Yes. They're completely different. in a declaration * is used to declare pointers. In an expression unary * is used to dereference a pointer (or as the binary multiplication operator)
Some examples:
int i = 10; //i is an int, it has allocated storage to store an int.
int *k; // k is an uninitialized pointer to an int.
//It does not store an int, but a pointer to one.
k = &i; // make k point to i. We take the address of i and store it in k
int j = *k; //here we dereference the k pointer to get at the int value it points
//to. As it points to i, *k will get the value 10 and store it in j
The rule of declaration in c is, you declare it the way you use it.
char *p means you need *p to get the char,
char **p means you need **p to get the char.
Declarations in C are expression-centric, meaning that the form of the declaration should match the form of the expression in executable code.
For example, suppose we have a pointer to an integer named p. We want to access the integer value pointed to by p, so we dereference the pointer, like so:
x = *p;
The type of the expression *p is int; therefore, the declaration of p takes the form
int *p;
In this declaration, int is the type specifier, and *p is the declarator. The declarator introduces the name of the object being declared (p), along with additional type information not provided by the type specifier. In this case, the additional type information is that p is a pointer type. The declaration can be read as either "p is of type pointer to int" or "p is a pointer to type int". I prefer to use the second form, others prefer the first.
It's an accident of C and C++ syntax that you can write that declaration as either int *p; or int* p;. In both cases, it's parsed as int (*p); -- in other words, the * is always associated with the variable name, not the type specifier.
Now suppose we have an array of pointers to int, and we want to access the value pointed to by the i'th element of the array. We subscript into the array and dereference the result, like so:
x = *ap[i]; // parsed as *(ap[i]), since subscript has higher precedence
// than dereference.
Again, the type of the expression *ap[i] is int, so the declaration of ap is
int *ap[N];
where the declarator *ap[N] signifies that ap is an array of pointers to int.
And just to drive the point home, now suppose we have a pointer to a pointer to int and want to access that value. Again, we deference the pointer, then we dereference that result to get at the integer value:
x = **pp; // *pp deferences pp, then **pp dereferences the result of *pp
Since the type of the expression **pp is int, the declaration is
int **pp;
The declarator **pp indicates that pp is a pointer to another pointer to an int.
Double indirection shows up a lot, typically when you want to modify a pointer value you're passing to a function, such as:
void openAndInit(FILE **p)
{
*p = fopen("AFile.txt", "r");
// do other stuff
}
int main(void)
{
FILE *f = NULL;
...
openAndInit(&f);
...
}
In this case, we want the function to update the value of f; in order to do that, we must pass a pointer to f. Since f is already a pointer type (FILE *), that means we are passing a pointer to a FILE *, hence the declaration of p as FILE **p. Remember that the expression *p in openAndInit refers to the same object that the expression f in main does.
In both declarations and expressions, both [] and () have higher precedence than unary *. For example, *ap[i] is interpreted as *(ap[i]); the expression ap[i] is a pointer type, and the * dereferences that pointer. Thus ap is an array of pointers. If you want to declare a pointer to an array, you must explicitly group the * with the array name, like so:
int (*pa)[N]; // pa is a pointer to an N-element array of int
and when you want to access a value in the array, you must deference pa before applying the subscript:
x = (*pa)[i];
Similarly with functions:
int *f(); // f is a function that returns a pointer to int
...
x = *f(); // we must dereference the result of f() to get the int value
int (*f)(); // f is a pointer to a function that returns an int
...
x = (*f)(); // we must dereference f and execute the result to get the int value
My favorite method to parse complicated declarators is the clockwise-spiral rule.
Basically you start from the identifier and follow a clockwise spiral. See the link to learn exactly how it's used.
Two things the article doesn't mention:
1- You should separate the type specifier (int, char, etc.) from the declarator, parse the declarator and then add the type specifier.
2- If you encounter square brackets which denote an array, make sure you read the following square brackets (if there are any) as well.
int * i means i is a pointer to int (read backwards, read * as pointer).
char **p and char *(*p) both mean a pointer to a pointer to char.
Here's some other examples
int* a[3] // a is an array of 3 pointers to int
int (*a)[3] //a is a pointer to an array of 3 ints
You have the answer in your questions.
Indeed a double star is used to indicate pointer to pointer.
The * in declaration means that the variable is a pointer to some other variable / constant. meaning it can hold the address of variable of the type. for example: char *c; means that c can hold the address to some char, while int *b means b can hold the address of some int, the type of the reference is important, since in pointers arithmetic, pointer + 1 is actually pointer + (1 * sizeof(*pointer)).
The * in expression means "the value stored in the address" so if c is a pointer to some char, then *c is the specific char.
char *(*s); meaning that s is a pointer to a pointer to char, so s doesn't hold the address of a char, but the address of variable that hold the address of a char.
here is a bit of information
variable pointer
declaring &a p
reading/ a *p
processing
Declaring &a means it points to *i. After all it is a pointer to *int. An integer is to point *i. But if consider j = *k is the pointer to the pointer this, means &k will be the value of k and k will have pointer to *int.

Why can't I assign an array to pointer directly in C?

I have the following program. However, I can't understand why I have to pass the address of the array. When they are both pointing to the same address. Which is the address of the first element of the array of int's.
I get a warning when I try and do this "assignment from incompatible pointer type":
ptr = var;
Complete source code:
void print_values(int (*ptr)[5])
{
size_t i = 0;
for(i = 0; i < 5; i++) {
printf("%d: [ %d ]\n", i, (*ptr)[i]);
}
}
int main(void)
{
/* declare a pointer to an array integers */
int (*ptr)[5] = NULL;
/* array of integers */
int var[] = {1, 2, 3, 4, 5};
/* assign the address of where the array is pointing to (first element) */
ptr = &var;
/* Both are pointing to the exact same address */
printf("var [ %p ]\n",(void*)var);
printf("&var [ %p ]\n", (void*)&var);
print_values(ptr);
return 0;
}
I compile the code with gcc 4.4.4 c89 -Wall -Wextra -O0
It's purely a type issue.
In most expression contexts the name of an array (such as var) decays to a pointer to the initial element of the array, not a pointer to the array. [Note that this doesn't imply that var is a pointer - it very much is not a pointer - it just behaves like a pointer to the first element of the array in most expressions.]
This means that in an expression var normally decays to a pointer to an int, not a pointer to an array of int.
As the operand of the address-of operator (&) is one context where this decay rule doesn't apply (the other one being as operand of the sizeof operator). In this case the type of &var is derived directly from the type of var so the type is pointer to array of 5 int.
Yes, the pointers have the same address value (the address of an arrays first element is the address of the array itself), but they have different types (int* vs int(*)[5]) so aren't compatible in the assignment.
ISO/IEC 9899:1999 6.3.2.1/4:
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression of type "pointer to type" that points to the initial element of the array object and is not an lvalue. ...
var itself is a (*int) pointing to the first element in your array. Pointers and arrays in C extremely similar. Change int (*ptr)[5] = NULL; to int* ptr = NULL; and ptr = &var; to ptr = var;
C is a strongly typed language. When a function expects a parameter of type int *, you have to pass an argument of type int *. Not double *, not char *, but int *. Even if the actual numerical address in those double * or char * is "the same" as the one you want to pass, it still doesn't change anything - you still have to pass an int *. The language prohibits you from passing the value of wrong type.
This is exactly what happens in your case. The function takes a parameter of type int (*)[5]. That means that you have to pass the argument of that type. Passing an int * instead is not allowed. Whether the address is the same makes no difference.
From what I can tell you are assigning an array pointer (var) to a pointer that points to an array pointer ((*ptr)[5]), so that's why you get that warning.
Instead, try using
int *ptr = NULL;

Resources