especificadores - scanf %d
¿Qué sucederá si ''&'' no se incluye en una declaración ''scanf''? (5)
No pude entender por qué el programa colapsaría? ¿Alguien podría explicarme la razón? Cualquier ayuda apreciada.
Quizás un poco más aplicado:
int i = 123;
scanf ("%d", &i);
Con el primer comando, asigna memoria para un valor entero y escribe 123 en este bloque de memoria.
Para este ejemplo, digamos que este bloque de memoria tiene la dirección
0x0000ffff
.
Con el segundo comando, lee su entrada y scanf escribe la entrada en el bloque de memoria
0x0000ffff
, porque no está accediendo (desreferenciando) el valor de esta variable
i
pero es su dirección.
Si usa el comando
scanf ("%d", i);
en su lugar, está escribiendo la entrada en la
dirección de
memoria
123
(porque ese es el valor almacenado dentro de esta variable).
Obviamente, eso puede salir terriblemente mal y causar un accidente.
Fui a una entrevista en la que me hicieron la pregunta:
¿Qué opinas sobre lo siguiente?
int i; scanf ("%d", i); printf ("i: %d/n", i);
Yo respondí:
- El programa se compilará con éxito.
- Imprimirá el número incorrectamente pero se ejecutará hasta el final sin fallar
La respuesta que hice fue incorrecta. Yo estaba abrumado.
Después de eso me despidieron:
El programa se bloqueará en algunos casos y provocará un volcado del núcleo.
No pude entender por qué el programa colapsaría? ¿Alguien podría explicarme la razón? Cualquier ayuda apreciada.
Cuando se define una variable, el compilador asigna memoria para esa variable.
int i; // The compiler will allocate sizeof(int) bytes for i
i
definido anteriormente no está inicializado y tiene un valor indeterminado.
Para escribir datos en esa ubicación de memoria asignada para
i
, debe especificar la dirección de la variable.
La declaración
scanf("%d", &i);
el usuario escribirá datos
int
en la ubicación de memoria asignada para
i
.
Si
&
no se coloca antes de
i
,
scanf
intentará escribir los datos de entrada en la ubicación de memoria
i
lugar de
&i
.
Dado que contiene un valor indeterminado, hay algunas posibilidades de que pueda contener un valor equivalente al valor de una dirección de memoria o puede contener un valor que está fuera del rango de la dirección de memoria.
En cualquier caso, el programa puede comportarse de manera errática y conducirá a un comportamiento indefinido. En ese caso, cualquier cosa podría pasar.
Pasó datos que tienen el tipo incorrecto (se espera
int*
, pero se pasa
int
) a
scanf()
.
Esto conducirá a
un comportamiento indefinido
.
Cualquier cosa puede suceder por un comportamiento indefinido. El programa puede bloquearse y no bloquearse.
En un entorno típico, supongo que el programa se bloqueará cuando alguna "dirección" que apunte a una ubicación en la que el sistema operativo no pueda escribir se pase a
scanf()
, y al escribir allí el sistema operativo terminará el programa de aplicación, y se observará como un bloqueo.
Porque invoca un comportamiento indefinido.
La familia de funciones
scanf()
espera un puntero a un entero cuando se encuentra el especificador
"%d"
.
Está pasando un número entero que puede interpretarse como la dirección de algún número entero, pero no lo es.
Esto no tiene un comportamiento definido en el estándar.
De hecho, se compilará (
sin embargo, emitirá alguna advertencia
), pero ciertamente funcionará de manera inesperada.
En el código tal como está, hay otro problema más.
La variable
i
nunca se inicializa, por lo que tendrá un valor indeterminado, otra razón más para el
comportamiento indefinido
.
Tenga en cuenta que el estándar no dice nada sobre lo que sucede cuando pasa un tipo dado cuando se esperaba otro tipo, es simplemente un comportamiento indefinido, sin importar qué tipos intercambie. Pero esta situación particular se debe considerar especialmente porque los punteros se pueden convertir en enteros, aunque el comportamiento solo se define si se vuelve a convertir en un puntero y si el tipo de entero es capaz de almacenar el valor correctamente. Es por eso que se compila, pero seguramente no funciona correctamente.
Una cosa que las otras respuestas aún no han mencionado es que en algunas plataformas,
sizeof (int) != sizeof (int*)
.
Si los argumentos se pasan de cierta manera *,
scanf
podría engullir parte de otra variable o de la dirección de retorno.
Cambiar la dirección de retorno podría conducir a una vulnerabilidad de seguridad.
* No soy un experto en lenguaje ensamblador, así que tómalo con un poco de sal.