问题
In C99, why is it that declaring a variable p
as pointer to array needs to be cast before it is passed as a parameter to a function with array type argument, but declaring a variable p
as void pointer then casting it to a pointer to array can be passed as pointer to array to the same function?
#include <stdio.h>
int arreglo(int locArr[])
{
locArr[0]=1;
printf("el arreglo es : %i\n",locArr[0]);
return 0;
}
int main()
{
/* Declare a pointer p to array */
int (*p)[];
int manArr[10];
p=&manArr; /* assign the adress of manArr as case below */
/* Here passing pointer p is not allowed as expected,
since our function has int* as argument */
/* so I need to do a casting */
arreglo((int*)p);
}
/* **But in this other main function**: */
int main()
{
/* Declare a void pointer */
void *p=NULL;
/* Do a casting from p to void to p to array */
p=(int (*)[])p;
int manArr[10];
p=&manArr; /* assing the adress of the array manArr as in above case */
/* Now given the pointer to array as parameter to function WORKS¡¡,
why?. As before the function expects int* as argument not
a pointer to an array */
arreglo(p);
}
回答1:
Here is a straight-forward adaptation of your code, combining the two variants of main()
into one by using variables p
and q
:
#include <stdio.h>
static int counter = 0;
static int arreglo(int locArr[])
{
locArr[0] = ++counter;
printf("el arreglo es: %i\n", locArr[0]);
return 0;
}
int main(void)
{
int manArr[10];
int (*p)[] = &manArr;
/* Here passing pointer p is not allowed as expected, since
** the function has int* as argument so I need to cast it...
*/
arreglo((int*)p);
printf("manArr[0] = %d\n", manArr[0]);
/* Or, since p is a pointer to an array, *p is the array,
** which can be passed directly without a cast.
*/
arreglo(*p);
printf("manArr[0] = %d\n", manArr[0]);
void *q = NULL;
/* This is a no-op */
q = (int (*)[])q; /* Cast from q to void to q to array */
q = &manArr; /* assign the address of the array manArr as above */
/* Now given the pointer to array as parameter to function WORKS¡¡
** Why?. As before the function expects int* as argument not
** a pointer to an array
*/
arreglo(q);
printf("manArr[0] = %d\n", manArr[0]);
/* Convert the void * back to a pointer to array, then dereference it */
arreglo(*(int (*)[])q);
printf("manArr[0] = %d\n", manArr[0]);
return 0;
}
The reason you could not pass p
to arreglo()
without a cast was that the type 'pointer to array of int
' is not the same as 'pointer to int
', and the parameter to the function is equivalent to a 'pointer to int
'. Your cast bludgeoned the compiler into agreeing with you, and you get away with it because even though the type of p
is incorrect, its value (byte address) is the same as the address of the start element of the array which the function expects. As noted in the comments, since you have a pointer to an array and the function expects an array, you can pass *p
without any cast being necessary.
The void *
version (ab)uses the fact that a void *
can be converted to any other pointer to object type without a cast in C (C++ would require a cast). The compiler is not able to warn you because you're using void *
. Again, you get away with it because the byte address of &manArr
is the same as the byte address of &manArr[0]
, even though the type is different. Note that the explicit cast (back to pointer to array) and then dereferencing works.
Be cautious with void *
; it loses type information. It can be a boon; it can also hide major problems.
Normally, you don't use pointers to arrays at all — they exist in the 'esoterica' section of the C pantheon of types. You'd normally write code such as:
#include <stdio.h>
static int counter = 0;
static int arreglo(int locArr[])
{
locArr[0] = ++counter;
printf("el arreglo es: %i\n", locArr[0]);
return 0;
}
int main(void)
{
int manArr[10];
int *p = manArr;
arreglo(p);
printf("manArr[0] = %d\n", manArr[0]);
return 0;
}
Which is much simpler to understand.
回答2:
While an array-of-int and a pointer-to-int are equivalent, a pointer-to-array(-of-int) is an extra level of indirection.
Here's your program with some comments and corrections.
#include<stdio.h>
int arreglo(int locArr[])
{
locArr[0]=1;
printf("el arreglo es : %i\n",locArr[0]);
return 0;
}
int main()
{
/* Declare a pointer p to array */
//int (*p)[]; //NO!
/* Declare a pointer p to int */
int *p;
int manArr[10];
//p=&manArr; /* assign the adress of manArr as case below */ //NO!
p=manArr;
/* Here passing pointer p is not allowed as expected,
since our function has int* as argument */ // Because `int*` and `int (*)[]` are different
/* so I need to do a casting */ //NO!
//arreglo((int*)p);
arreglo(p);
}
/* **But in this other main function**: */
int main()
{
/* Declare a void pointer */
void *p=NULL;
/* Do a casting from p to void to p to array */
//p=(int (*)[])p; //NO! This does absolutely nothing at all.
int manArr[10];
//p=&manArr; /* passing the adress of the array manArr as in above case */
p=manArr;
/* Now given the pointer to array as parameter to function WORKS¡¡,
why?. As before the function expects int* as argument not
a pointer to an array */
// A void* bypasses all type-checking, since it can be implicitly converted to any type
arreglo(p); //This would still compile if p="potato", because a void* converts to any type.
}
So, let's start over from the beginning.
int i = 0; // a simple int variable
int a[3] = { 1, 2, 3 }; // an array of ints
int *p = a; // a pointer to int can be used the same as an array of int
p[0] = 4; // so now a[0] = 4, too
int i int a[3]
|----| |----|----|----|
| 0 | | 4 | 2 | 3 |
|----| |----|----|----|
^
int *p |
|----| |
| --|-----
|----|
A pointer-to-array, is totally different because it points to the whole array, not just a single int which may or may not be part of an array.
int b[3] = { 5, 6, 7 };
int (*bp)[3] = &b; // bp points to the whole array b
-------------
V |
int b[3] | int (*bp)[3]
|----|----|----| | |----|
| 5 | 6 | 7 | --|-- |
|----|----|----| |----|
bp[0][0] = 8; // it now takes 2 dereferences to get to the int
-------------
V |
int b[3] | int (*bp)[3]
|----|----|----| | |----|
| 8 | 6 | 7 | --|-- |
|----|----|----| |----|
回答3:
This is an attempt to answer the question, after a long thought..:) Please correct me if I am wrong.
The following line p=(int (*)[])p;
has no effect on type of p
. p
is still of type void *
(so your casting is redundant) and since void *
is compatible with any data pointer type so the function call is fine.
As for the first main()
function you have figured it write.
Look here(good read to avoid confusion).
EDIT:
In short: You are trying to chage the type of the lhs
of expression. This is never the aim of typecasting.
In detail:
Converting an expression of a given type into another type is known as type-casting
.
So, let us analyse the line p=(int (*)[])p;
Consider the rhs
of the expression: (int (*)[])p
. It is a pointer to arrays of integer pointers
(as expected). But you want it to be assigned to void *
(operator =
). Now the compiler does not complain because void *
admits pointer of any type. So pointer to arrays of integer pointers
is again type-cast to void *
(implicitly).
Try: p=(*whatever type you like*)p
; and the compiler will not complain.(Do not expect it to run..:))
来源:https://stackoverflow.com/questions/17438175/why-does-a-pointer-to-array-need-to-be-cast-before-being-passed-as-parameter-to