resueltos - funciones en c++
Valores pasados del puntero válido a la cadena C-Style (4)
C ++ le permite hacer un puntero a ca[0]
través de una ca[4]
pasada ca[4]
, inclusive. Sin embargo, puede desreferenciar (es decir, aplicar operador *
) a punteros solo a ca[0]
a ca[4]
; el puntero que apunta a un pasado ca[4]
está fuera de los límites. Lo que sucede tan pronto como desreferencia el puntero es un comportamiento indefinido . El programa puede producir cualquier información, o incluso bloquearse.
Lo que sucede en la realidad es más simple: un puntero es solo una dirección en la memoria, por lo que desreferenciando continúa entregando números a su programa. En algún punto, la dirección contiene un byte cero. Esto es cuando tu programa se detiene.
Su matriz está asignada en la memoria automática. La mayoría de los compiladores usan CPU stack para ello. El contenido de los bytes 5..20 muy probablemente incluye cp
y count
, porque los compiladores tienden a juntar variables locales. Probablemente haya algo de espacio intermedio, porque el puntero y el int
se suelen alinear en direcciones divisibles por 4. Naturalmente, no puede contar con que eso ocurra, porque otros compiladores lo harán de forma diferente.
Actualmente estoy trabajando en mi camino a través de "C ++ Primer". En una, el ejercicio pregunta:
¿Qué hace el siguiente programa?
const char ca[] = { ''h'', ''e'', ''l'', ''l'', ''o'' };
const char *cp = ca;
while (*cp)
{
cout << *cp << endl;
cp++;
}
Estoy bastante contento de haber comprendido que * cp continuará siendo verdadero más allá del último carácter de la matriz ca [] porque no hay carácter nulo como último elemento de la matriz.
Es más por mi propia curiosidad sobre qué hace que el ciclo while se vuelva falso. Parece que siempre muestra 19 caracteres en mi computadora. 0-4 son la cadena de hola, 5-11 son siempre iguales, y 12-19 cambian con cada ejecución.
#include <iostream>
using namespace std;
int main( )
{
const char ca[ ] = { ''h'', ''e'', ''l'', ''l'', ''o''/*, ''/0''*/ };
const char *cp = ca;
int count = 0;
while ( *cp )
{
// {counter} {object-pointed-to} {number-equivalent}
cout << count << "/t" << *cp << "/t" << (int)*cp << endl;
count++;
cp++;
}
return 0;
}
La pregunta: ¿Qué causa que el ciclo while se vuelva inválido? ¿Por qué 5-11 es siempre el mismo personaje?
Dado que para el idioma, lo que sucede al acceder a una matriz fuera de sus límites no está definido, si quiere entender qué sucede, debe comprender cómo funciona su "plataforma".
Para la mayoría de los compiladores, su memoria probablemente se presenta así:
|H|e|l|l|o|XXX|____cp___|__count__|
XXX son "bytes de relleno" necesarios para alinearse a 8. Los compiladores -en la versión de depuración- normalmente llenan estos bytes con valores fijos distintos de 0 solo para tener una iteración fuera de límite que no se detiene (para que pueda descubrirla)
cp es un puntero a la "H" que se incrementa uno por uno. Su valor es normalmente el mapa de direcciones de la pila de su proceso en su proceso.
Esta dirección generalmente tiene un prefijo fijo y un valor de compensación que crece a medida que profundiza en las llamadas anidadas.
Como un puntero es (probablemente) de 8 bytes de longitud (con los últimos cuatro bytes colocados antes del primero, debido a los endianes bajos de los procesadores x86) lo que obtienes es una iteración que se imprime:
- Los cinco personajes "Hola"
- Los tres personajes de relleno (admitiendo el yare de alguna manera imprimible)
- El desplazamiento de
cp
desde el comienzo de la pila (siempre el mismo, ya que main está siempre en el mismo lugar con respecto al programa en sí) - Parte del prefijo del proceso (esto cambia en cada invocación)
Este prefijo puede incluir un "0" en cierto punto en adelante, terminando así el ciclo.
Tenga en cuenta que -sin embargo, esta explicación puede tener sentido- no puede confiar de ninguna manera para que el código de producción se compile para una plataforma diferente, incluso puede ser por compiladores diferentes, ya que la forma en que administran las variables también puede ser diferente.
Lo importante es saber que está experimentando un Undefined behavior
. Entonces, sea lo que sea que vea ahora, puede ser diferente cuando usa un compilador diferente o diferentes opciones de compilación.
La razón más explicable para los valores "constantes" en 5-11 es que estás leyendo una parte de la pila, que simplemente tiene el mismo valor cada vez.
Para principiantes:
Esto: almacena una matriz de caracteres (una cadena modificable) que incluye el terminador nulo /0
:
const char ca[] = "hello";
Esto no incluye el terminador nulo. Inicializa la matriz desde su lista de inicializadores
const char ca[] = { ''h'', ''e'', ''l'', ''l'', ''o'' };
Funciona de la misma manera que lo harás:
const int ib[] = {2, 5, 7, 9};
Tiene sentido aquí, porque el compilador no debe agregar cosas adicionales a su matriz.
const char ca[] = { ''h'', ''e'', ''l'', ''l'', ''o'' };
const char *cp = ca;
while (*cp){
cout << *cp << endl;
cp++;
}
Bueno, tiene un comportamiento Indefinido en su código porque eliminará la referencia más allá de su matriz ya que no hay ningún terminador nulo /0
en su matriz.
¿Qué causa que while-loop se vuelva inválido?
Entonces, lo que sucede después de imprimir el último carácter en su matriz es que su programa sigue leyendo e imprimiendo desde una ubicación de memoria indefinida (desconocida) hasta que llega al punto donde se encontró 0
y se sale del ciclo.
¿Por qué 5-11 es siempre el mismo personaje?
En cuanto a por qué tenían el mismo aspecto: las variables de la pila se ordenan de forma lineal como desea el compilador; la memoria también está acolchada ; de nuevo, la memoria se reutiliza , por lo tanto, lee de la dirección de las cosas, con la que no tiene ninguna relación legal.
Nota al pie: su programa puede llamar a otras funciones antes de int main()
. (no es asunto tuyo, lo que llama). Estas funciones inicializan variables estáticas que incluyen cosas como std::cout