c++ - ¿Puedes explicar el propósito de array+5 en este programa?
arrays pointer-arithmetic (5)
La
array
variable es como un puntero al comienzo de la memoria que contiene los datos.
La longitud de la
array
es
5
, por lo que agregar 5 al principio da la posición de uno más allá del final.
start --|
10, 20, 29, 200, 2, (out of array)
|--- +5 -----------^
La condición
it != end
comprueba si el bucle no está fuera de los límites.
Entiendo cómo funciona la mayor parte, a excepción de la segunda línea en la función
main
:
int* end = array+5;
.
¿Cómo funciona esa línea?
#inlcude <iostream>
int main()
{
int array[] = {10, 20, 29, 200, 2};
int* end = array+5;
for(int* it = array; it != end; ++it)
{
std::cout << *it << std::endl;
}
}
Se supone que solo imprime todos los elementos de la lista.
Para cualquier matriz o puntero
a
e índice
i
, la expresión
a[i]
es exactamente igual a
*(a + i)
.
Junto con la disminución de la matriz (lo que significa que, por ejemplo, la
array
es igual a
&array[0]
) significa que la
array + 5
será igual a
&array[5]
.
Por lo tanto, su ciclo está iterando desde
&array[0]
(que es lo que es igual a la
array
) a one
&array[4]
(inclusive).
El ciclo está iterando sobre los cinco elementos de la
array
, haciendo
it
apunte a cada elemento o la matriz a su vez.
Para entender
int* end = array+5;
, uno debe saber cómo se ha establecido la memoria para
int array[] = {10, 20, 29, 200, 2}
.
Han representado lo mismo a continuación para una mejor comprensión.
Las direcciones se dan en decimales y hexadecimales para realizar operaciones aritméticas fácilmente.
Address table
-----------------------------------------------------------
array ===>| 100 | 104 | 108 | 112 | 116 | 120 | -----> DECIMAL
| 0x100 | 0x104 | 0x108 | 0x10C | 0x110 | 0x114 | -----> HEXADECIMAL
-----------------------------------------------------------
| | | | |
10 20 29 200 2
''array'' will be pointing to 0x100
La declaración
int* end = array + 5;
se compila en un código que es equivalente a
int* end = (array + (sizeof(int) * 5));
Por lo tanto, se evalúa como
int* end = (0x100 + (4 * 5)) = 0x114(decimal equivalent 120);
cual es la dirección al lado del último elemento.
Así que
end
estará apuntando al penúltimo elemento.
Es importante recordar que el valor que se debe agregar o restar de la dirección base de la matriz siempre depende del tipo de datos que es
int
en su caso y se supone que el
sizeof(int)
es de
4 bytes
.
En una nota al margen, datatype arr [index];
se evalúa como
*(arr + (sizeof(datatype) * index))
.
array + 5
es equivalente a
&array[5]
.
Dado que la
array
en su código de muestra es una matriz de cinco elementos.
int array[] = {10, 20, 29, 200, 2};
la inicialización
int* end = array+5;
hace que
end
sea un puntero a uno pasado el final de la matriz, y la condición final en el bucle
for(int* it = array; it != end; ++it) { std::cout << *it << std::endl; }
significa que el bucle termina una vez
it
apunta más allá del final de la matriz (en su ejemplo, apunta a la
array[5]
).
Esto está perfectamente bien en C ++, ya que se permite calcular o comparar un puntero a uno más allá del final de una matriz con otros punteros a elementos de esa matriz.
Sin embargo, al desreferenciar dicho puntero (por ejemplo, en su ejemplo, usarlo para acceder al valor de
array[5]
) provoca un comportamiento indefinido.
En C ++ 11 y posterior, las funciones
std::begin()
y
std::end()
(del encabezado estándar
<iterator>
) si se les da un argumento de matriz, devuelven las direcciones del primer elemento y one-past-the -último elemento respectivamente.
Entonces, su código es funcionalmente equivalente, para una
array
tiene cinco elementos, a;
int *end = std::end(array);
for(int *it = std::begin(array); it != end; ++it)
{
std::cout << *it << std::endl;
}
También es equivalente al más conciso, y a menudo se prefiere ya que es menos propenso a errores;
for (const auto &element : array) // const since the loop body doesn''t change the array
{
std::cout << element << std::endl;
}
it != end;
significa que alcanzó la posición [5], que es una después de la última (4).
int* end = array + 5;
simplemente crea una variable que apunta a esa [5] posición.
Funciona, pero una versión mucho más limpia y segura es:
for(int i = 0 ; i < 5 ; i++)
{
std::cout << it[i] << std::endl;
}
Por supuesto, puede reemplazar el 5 codificado con
sizeof(array)/sizeof(int)
, o, mejor aún, usar un std :: array.
std::array arr<int,5> = {10, 20, 29, 200, 2};
for(int i = 0 ; i < arr.size() ; i++)
{
std::cout << arr[i] << std::endl;
}
o
std::array arr<int,5> = {10, 20, 29, 200, 2};
for(auto& it : arr)
{
std::cout << it << std::endl;
}
Las últimas formas son tan rápidas como la matriz sin formato simple, pero mucho más seguras.