En el siguiente bit de código, los valores de puntero y las direcciones de puntero difieren según lo esperado.
¡Pero los valores de matriz y las direcciones no!
¿Cómo puede ser esto?
Salida
my_array = 0022FF00
&my_array = 0022FF00
pointer_to_array = 0022FF00
&pointer_to_array = 0022FEFC
#include <stdio.h>
int main()
{
char my_array[100] = "some cool string";
printf("my_array = %p\n", my_array);
printf("&my_array = %p\n", &my_array);
char *pointer_to_array = my_array;
printf("pointer_to_array = %p\n", pointer_to_array);
printf("&pointer_to_array = %p\n", &pointer_to_array);
printf("Press ENTER to continue...\n");
getchar();
return 0;
}
sizeof(&array)
devuelve?Respuestas:
El nombre de una matriz generalmente evalúa a la dirección del primer elemento de la matriz, de modo
array
y&array
tener el mismo valor (pero diferentes tipos, de modoarray+1
y&array+1
será no ser igual si la matriz es más de 1 elemento de largo).Hay dos excepciones a esto: cuando el nombre de la matriz es un operando
sizeof
o unario&
(dirección de), el nombre se refiere al objeto de la matriz en sí. Por lo tanto,sizeof array
le da el tamaño en bytes de toda la matriz, no el tamaño de un puntero.Para una matriz definida como
T array[size]
, tendrá tipoT *
. Cuando / si lo incrementa, llega al siguiente elemento en la matriz.&array
evalúa a la misma dirección, pero dada la misma definición, crea un puntero del tipoT(*)[size]
, es decir, es un puntero a una matriz, no a un solo elemento. Si incrementa este puntero, agregará el tamaño de toda la matriz, no el tamaño de un solo elemento. Por ejemplo, con un código como este:Podemos esperar que el segundo puntero sea 16 mayor que el primero (porque es una matriz de 16 caracteres). Como% p generalmente convierte los punteros en hexadecimal, podría verse así:
fuente
&array
es un puntero al primer elemento de la matriz, donde searray
refiere a toda la matriz. La diferencia fundamental también se puede observar al compararsizeof(array)
, asizeof(&array)
. Sin embargo, tenga en cuenta que si pasaarray
como argumento a una función, solo&array
se pasa de hecho. No puede pasar una matriz por valor a menos que esté encapsulada dentro de astruct
.&array[0]
se pasa de manera efectiva , lo&array
que no sería un puntero a la matriz. Puede ser una trampa, pero creo que es importante dejar en claro; los compiladores avisarán si la función tiene un prototipo que coincida con el tipo de puntero pasado.int *p = array; int **pp = &p;
.Esto se debe a que el nombre de la matriz (
my_array
) es diferente de un puntero a una matriz. Es un alias de la dirección de una matriz, y su dirección se define como la dirección de la matriz misma.Sin embargo, el puntero es una variable C normal en la pila. Por lo tanto, puede tomar su dirección y obtener un valor diferente de la dirección que contiene en su interior.
Escribí sobre este tema aquí , por favor, eche un vistazo.
fuente
register
) sea cual sea su duración de almacenamiento: estática, dinámica o automática.my_array
sí mismo está en la pila, porquemy_array
es toda la matriz.my_array
, cuando no es el sujeto de los operadores&
osizeof
, se evalúa en un puntero a su primer elemento (es decir&my_array[0]
), pero enmy_array
sí mismo no es ese puntero (my_array
sigue siendo la matriz). Ese puntero es solo un valor efímero (por ejemploint a;
, dado , es comoa + 1
) - conceptualmente al menos se "calcula según sea necesario". El verdadero "valor" demy_array
es el contenido de toda la matriz; es solo que precisar este valor en C es como tratar de atrapar la niebla en un frasco.En C, cuando utiliza el nombre de una matriz en una expresión (incluido el paso a una función), a menos que sea el operando del
&
operador address-of ( ) o elsizeof
operador, se desintegra en un puntero a su primer elemento.Es decir, en la mayoría de los contextos
array
es equivalente&array[0]
tanto en tipo como en valor.En su ejemplo,
my_array
tiene un tipochar[100]
que decae a achar*
cuando lo pasa a printf.&my_array
tiene tipochar (*)[100]
(puntero a la matriz de 100char
). Como es el operando&
, este es uno de los casos quemy_array
no decae inmediatamente a un puntero a su primer elemento.El puntero a la matriz tiene el mismo valor de dirección que un puntero al primer elemento de la matriz, ya que un objeto de matriz es solo una secuencia contigua de sus elementos, pero un puntero a una matriz tiene un tipo diferente a un puntero a un elemento de Esa matriz. Esto es importante cuando haces aritmética de puntero en los dos tipos de puntero.
pointer_to_array
tiene tipochar *
, inicializado para apuntar al primer elemento de la matriz, ya que eso es lo quemy_array
decae en la expresión inicializadora, y&pointer_to_array
tiene tipochar **
(puntero a puntero a achar
).De estos:
my_array
(después de decaer achar*
),&my_array
ypointer_to_array
todos apuntan directamente a la matriz o al primer elemento de la matriz y, por lo tanto, tienen el mismo valor de dirección.fuente
El motivo
my_array
y el&my_array
resultado de la misma dirección se pueden entender fácilmente cuando observa el diseño de memoria de una matriz.Digamos que tiene una matriz de 10 caracteres (en lugar de los 100 en su código).
La memoria para se
my_array
parece a algo como:En C / C ++, una matriz decae al puntero al primer elemento en una expresión como
Si examina dónde se encuentra el primer elemento de la matriz, verá que su dirección es la misma que la dirección de la matriz:
fuente
En el lenguaje de programación B, que fue el predecesor inmediato de C, los punteros y los enteros eran libremente intercambiables. El sistema se comportaría como si toda la memoria fuera una matriz gigante. Cada nombre de variable tenía asociada una dirección global o relativa a la pila, para cada nombre de variable lo único que el compilador tenía que hacer un seguimiento era si era una variable global o local, y su dirección relativa a la primera global o local. variable.
Dada una declaración global como
i;
[no había necesidad de especificar un tipo, ya que todo era un entero / puntero] sería procesado por el compilador como:address_of_i = next_global++; memory[address_of_i] = 0;
y una declaración comoi++
serían procesados como:memory[address_of_i] = memory[address_of_i]+1;
.Una declaración como
arr[10];
se procesará comoaddress_of_arr = next_global; memory[next_global] = next_global; next_global += 10;
. Tenga en cuenta que tan pronto como se procesó esa declaración, el compilador podría olvidarse inmediatamente dearr
ser una matriz . Una declaración comoarr[i]=6;
se procesará comomemory[memory[address_of_a] + memory[address_of_i]] = 6;
. Al compilador no le importaría siarr
representara una matriz yi
un número entero, o viceversa. De hecho, no le importaría si ambos fueran matrices o ambos enteros; generaría perfectamente el código tal como se describe, sin tener en cuenta si el comportamiento resultante probablemente sería útil.Uno de los objetivos del lenguaje de programación C era ser ampliamente compatible con B. En B, el nombre de una matriz [llamada "vector" en la terminología de B] identificaba una variable que contenía un puntero que inicialmente se asignó para apuntar a al primer elemento de una asignación del tamaño dado, de modo que si ese nombre apareciera en la lista de argumentos para una función, la función recibiría un puntero al vector. A pesar de que C agregó tipos de matriz "reales", cuyo nombre se asoció rígidamente con la dirección de la asignación en lugar de una variable de puntero que apunte inicialmente a la asignación, hacer que las matrices se descompongan en punteros hizo que el código declarara que una matriz de tipo C se comporta de manera idéntica al código B que declaró un vector y luego nunca modificó la variable que contiene su dirección.
fuente
En realidad
&myarray
ymyarray
ambas son la dirección base.Si quieres ver la diferencia en lugar de usar
utilizar
fuente