Что произойдет, если '&' не будет введен в 'scanf' в C?
Я отправился на собеседование, в котором меня задали вопрос:
Что вы думаете о следующем?
int i;
scanf ("%d", i);
printf ("i: %d\n", i);
Я ответил:
- Программа будет успешно скомпилирована.
- Он напечатает номер неправильно, но он будет работать до конца
без сбоев
Ответ, который я сделал, был неправильным. Я был ошеломлен.
После этого они уволили меня:
В некоторых случаях программа выйдет из строя и приведет к дампу ядра.
Я не мог понять, почему программа потерпит крах? Может ли кто-нибудь объяснить мне причину. Любая помощь была оценена.
Ответы
Ответ 1
Когда переменная определена, компилятор выделяет память для этой переменной.
int i; // The compiler will allocate sizeof(int) bytes for i
i
, определенный выше, не инициализирован и имеет неопределенное значение.
Чтобы записать данные в эту ячейку памяти, выделенную для i
, вам необходимо указать адрес переменной. Утверждение
scanf("%d", &i);
будет записывать данные int
пользователем в ячейку памяти, выделенную для i
.
Если &
не помещается перед i
, тогда scanf
попытается записать входные данные в ячейку памяти i
вместо &i
. Поскольку i
содержит неопределенное значение, существуют некоторые возможности, которые могут содержать значение, эквивалентное значению адреса памяти, или оно может содержать значение, выходящее за пределы адреса памяти.
В любом случае программа может вести себя беспорядочно и приведет к поведению undefined. В этом случае все может случиться.
Ответ 2
Beacuse вызывает поведение undefined. Семейство функций scanf()
ожидает указатель на целое число, когда найден спецификатор "%d"
. Вы передаете целое число, которое можно интерпретировать как адрес некоторого целого числа, но это не так. Это не имеет определенного поведения в стандарте. Он действительно скомпилируется (однако, будет выдано какое-то предупреждение), но это, безусловно, будет работать неожиданным образом.
В коде как есть, есть еще одна проблема. Переменная i
никогда не инициализируется, поэтому она будет иметь неопределенное значение, а еще одна причина для undefined Поведение.
Обратите внимание, что стандарт ничего не говорит о том, что происходит, когда вы передаете данный тип, когда ожидался какой-то другой тип, это просто поведение undefined, независимо от того, какие типы вы меняете. Но эта конкретная ситуация подпадает под особое внимание, поскольку указатели могут быть преобразованы в целые числа, хотя поведение определяется только в том случае, если вы конвертируете обратно в указатель и если целочисленный тип способен правильно хранить значение. Вот почему он компилируется, но он, безусловно, работает неправильно.
Ответ 3
Вы передали данные с неправильным типом (ожидается int*
, но int
) до scanf()
. Это приведет к поведению undefined.
Все что может случиться для поведения undefined. Программа может вылететь из строя и может не сработать.
В типичной среде я предполагаю, что программа выйдет из строя, когда какой-то "адрес", указывающий на место, которое не разрешено записывать в операционную систему, передается в scanf()
, и запись на него будет иметь OS завершает прикладную программу, и это будет наблюдаться как сбой.
Ответ 4
Одна вещь, о которой другие ответы еще не упоминались, заключается в том, что на некоторых платформах sizeof (int) != sizeof (int*)
. Если аргументы переданы определенным образом *, scanf
может сожрать часть другой переменной или адрес возврата. Изменение адреса возврата может привести к уязвимости безопасности.
* Я не специалист по ассемблеру, поэтому возьмите это с солью.
Ответ 5
Я не мог понять, почему программа потерпит крах? Может ли кто-нибудь объяснить мне причину. Любая помощь была оценена.
Возможно, еще немного применено:
int i = 123;
scanf ("%d", &i);
С помощью первой команды вы выделяете память для одного целочисленного значения и записываете 123 в этот блок памяти. В этом примере предположим, что этот блок памяти имеет адрес 0x0000ffff
. С помощью второй команды вы читаете свой ввод, а scanf записывает вход в блок памяти 0x0000ffff
- потому что вы не получаете доступ (разыменовываете) значение этой переменной i
, а адресуете.
Если вы используете команду scanf ("%d", i);
, вместо этого вы записываете ввод в память адрес 123
(потому что это значение хранится внутри этой переменной). Очевидно, что это может пойти ужасно неправильно и вызвать крушение.