Введите следующую программу, и вы поймете, почему:
#include <stdio.h>
int main (void) {
int val = 4096;
printf ("Enter your character: ");
scanf ("%c",&val);
printf ("integer val = %d, character val = %c\n", val, val);
return 0;
}
Компиляция этого с gcc -Wall
(все предупреждения), дает:
qq.c: In function 'main':
qq.c:6: warning: format '%c' expects type 'char *',
but argument 2 has type 'int *'
(как хорошопричина, как любая, для обеспечения того, что вы включили все предупреждения при компиляции), и его запуск дает те же результаты, что вы нашли:
Enter your character: f
integer val = 4198, character val = f
Причина 1012 * для этого способа scanf
работает в сочетании сспособ размещения переменных в памяти.
Чтобы scanf
просто получил символ и поместил его в память.Поскольку вы дали ему адрес integer , и это целое число имеет младший порядок, оно будет перезаписывать только младший байт (LSB) этого целого числа.Подумайте о том, чтобы рассматривать эту память как перекрывающуюся область, и вы поймете, почему:
+--- The address passed to scanf.
|
V
+------+
| char | <-- Treated as char.
+------+------+------+------+
| lsb | | | msb | <-- Treated as integer (assumes 32-bit).
+------+------+------+------+
Поскольку scanf
не касается этих самых правых байтов целого числа, они остаются с тем, что они держали до вызова.В моем коде я явно устанавливаю значение 4096
, но если ваше объявление неинициализировано int val;
, содержимое будет неопределенным.Фактически, когда я удаляю инициализацию, я получаю 1629542246
(0x6120D766
, и вы все еще можете видеть LSB, установленный в 0x66
или f
).
Это просто означает, что мое целое число выглядело такдо того, как вызов scanf
:
+------+
| ?? |
+------+------+------+------+
| ?? | d7 | 20 | 61 |
+------+------+------+------+
и вызов scanf
изменили только бит ??
.