backwards c++ c pointers

c++ - xbox 360 backwards compatibility list



¿Por qué es arr y & arr lo mismo? (6)

Ellos no son los mismos.

Una explicación un poco más estricta:

arr es un lvalor de tipo int [3] . Un intento de usar arr en algunas expresiones como cout << arr resultará en una conversión de valor a valor que, como no hay valores de tipo de matriz, lo convertirá en un valor de tipo int * y con el valor igual a &arr[0] . Esto es lo que puede mostrar.

&arr es un valor de tipo int (*)[3] , que apunta al objeto de matriz en sí. No hay magia aquí :-) Este puntero apunta a la misma dirección que &arr[0] porque el objeto de matriz y su primer miembro comienzan exactamente en el mismo lugar en la memoria. Por eso tienes el mismo resultado al imprimirlos.

Una forma fácil de confirmar que son diferentes es comparando *(arr) y *(&arr) : el primero es un valor de tipo int y el segundo es un valor de tipo int[3] .

He estado programando c / c ++ durante muchos años, pero el descubrimiento accidental de hoy me hizo sentir un poco curioso ... ¿Por qué ambas salidas producen el mismo resultado en el siguiente código? ( arr es, por supuesto, la dirección de arr[0] , es decir, un puntero a arr[0] . Habría esperado que &arr fuera la dirección de ese puntero, pero tiene el mismo valor que arr )

int arr[3]; cout << arr << endl; cout << &arr << endl;

Observación: esta pregunta se cerró, pero ahora se abre de nuevo. (Gracias ?)

Sé que &arr[0] y arr evalúa el mismo número, ¡pero esa no es mi pregunta! La pregunta es por qué &arr y arr evalúa al mismo número. Si arr es un literal (no se almacena ningún software), entonces el compilador debe quejarse y decir que arr no es un lvalue. Si la dirección del arr está almacenada en algún lugar, entonces &arr debería darme la dirección de esa ubicación. (Pero este no es el caso)

si escribo

const int * arr2 = arr;

luego arr2[i]==arr[i] para cualquier entero i , pero &arr2 != arr .


La dirección es la misma pero ambas expresiones son diferentes. Simplemente comienzan en la misma ubicación de memoria. Los tipos de ambas expresiones son diferentes.

El valor de arr es de tipo int * y el valor de &arr es de tipo int (*)[3] .

& es el operador de dirección y la dirección de un objeto es un puntero a ese objeto. El puntero a un objeto de tipo int [3] es de tipo int (*)[3]


Los dos tienen el mismo valor pero tipos diferentes.

Cuando se usa solo (no el operando de & o sizeof ), arr evalúa a un puntero para mantener int la dirección de la primera int en la matriz. &arr evalúa a un puntero a la matriz de tres int s, manteniendo la dirección de la matriz. Dado que la primera int en la matriz debe estar al principio de la matriz, esas direcciones deben ser iguales.

La diferencia entre los dos se hace evidente si haces algunos cálculos con los resultados:

arr+1 será igual a arr + sizeof(int) .

((&arr) + 1) será igual a arr + sizeof(arr) == arr + sizeof(int) * 3

Edición: En cuanto a cómo / por qué sucede esto, la respuesta es bastante simple: porque el estándar lo dice. En particular, dice (§6.3.2.1 / 3):

Excepto cuando es el operando del operador sizeof o el operador unario &, o si se utiliza un literal de cadena para inicializar una matriz, una expresión que tiene el tipo "matriz de tipo" se convierte en una expresión con el puntero de tipo a " escriba '''' que apunta al elemento inicial del objeto de matriz y no es un valor l.

[nota: esta cita en particular es del estándar C99, pero creo que hay un lenguaje equivalente en todas las versiones de los estándares C y C ++].

En el primer caso ( arr por sí mismo), arr no se usa como el operando de sizeof, unary &, etc., por lo que se convierte (no se promueve) al tipo "puntero a tipo" (en este caso, "puntero a int ").

En el segundo caso ( &arr ), el nombre obviamente se está utilizando como el operando de unary & operator, para que la conversión no tenga lugar.


Los punteros y las matrices a menudo se pueden tratar de manera idéntica, pero hay diferencias. Un puntero tiene una ubicación de memoria, por lo que puede tomar la dirección de un puntero. Pero una matriz no tiene nada que apunte a ella, en tiempo de ejecución. Así que tomar la dirección de una matriz es, para el compilador, definida sintácticamente como la dirección del primer elemento. Lo que tiene sentido, leer esa frase en voz alta.


No son lo mismo. Simplemente están en la misma ubicación de memoria. Por ejemplo, puede escribir arr+2 para obtener la dirección de arr[2] , pero no (&arr)+2 para hacer lo mismo.

Además, sizeof arr y sizeof &arr son diferentes.


#include <cassert> struct foo { int x; int y; }; int main() { foo f; void* a = &f.x; void* b = &f; assert(a == b); }

Por la misma razón, las dos direcciones a y b anteriores son iguales . La dirección de un objeto es la misma que la dirección de su primer miembro (sin embargo, sus tipos son diferentes).

arr _______^_______ / / | [0] [1] [2] | --------------------+-----+-----+-----+-------------------------- some memory | | | | more memory --------------------+-----+-----+-----+-------------------------- ^ | the pointers point here

Como puede ver en este diagrama, el primer elemento de la matriz se encuentra en la misma dirección que la propia matriz.