Амперсанд в PlaceHolder сканф? - PullRequest
0 голосов
/ 07 сентября 2018

Каким будет вывод следующего кода?

#include <stdio.h>

int n;

int main() {
    scanf("&d", &n);

    switch (n) {
      case 1:
        printf("hello\n");
        break;
      case 2:
        printf("good\n");
        break;
      default:
        printf("Morning\n");
        break;
    }
    return 0;
}

Большинство людей ожидали, что будет ошибка, но при выполнении она всегда выдает Morning независимо от того, что вводится.

Ответы [ 2 ]

0 голосов
/ 07 сентября 2018

«Утро» - правильный вывод для этой программы.

Во-первых, нет никаких оснований ожидать сообщения об ошибке, поскольку программа нигде не печатает его. В частности, функции стандартной библиотеки C, такие как scanf(), не передают сообщения об ошибках в стандартные потоки. Вместо этого они возвращают информацию о состоянии через свои возвращаемые значения , а в некоторых случаях путем установки локальной переменной потока errno. Эта программа даже не проверяет возвращаемое значение scanf, поэтому нет оснований полагать, что она выдаст сообщение об ошибке из-за возникшей там проблемы.

Во-вторых, хотя строка формата, переданная в scanf, по-видимому, содержит опечатку, это все еще совершенно правильный формат. Он говорит scanf попытаться прочитать (но больше ничего не делать с) двухсимвольную последовательность «& d». Если это не следующие два символа, которые он видит, то произойдет сбой с ошибкой сопоставления, которую он укажет, вернув 0. Фактически, он также вернет 0, если это следующие два символа, потому что возвращаемое значение сообщает количество полей ввода успешно отсканированных, преобразованных и сохраненных, а формат не описывает никаких полей ввода.

Второй аргумент scanf игнорируется во всех случаях, но некоторые компиляторы выдают предупреждение (не ошибку) об этом.

Поскольку scanf не присваивает значение переменной n, оно сохраняет любое значение, которое имело до вызова. Поскольку он был объявлен в области видимости файла, он автоматически инициализируется равным нулю перед запуском программы, и он все еще имеет это значение, когда исполняемый файл достигает оператора switch. Это приводит к выполнению дела по умолчанию.

0 голосов
/ 07 сентября 2018

Выход всегда будет Morning.

scanf("&d") ожидает в качестве ввода два символа & и d, буквально. Если вы введете что-нибудь еще, вызов scanf не удастся. Однако ваш код не проверяет возвращаемое значение scanf, поэтому нет никакой разницы.

Аргумент &n для scanf игнорируется, поскольку в строке формата отсутствует «спецификация преобразования» (это вещи, начинающиеся с %). Таким образом (как сказано в стандарте C (C99, 7.19.6.2 Функция fscanf / 2)):

Если формат исчерпан, а аргументы остаются, избыток аргументы оцениваются (как всегда), но в противном случае игнорируются.

Следовательно,

scanf("&d", &n) эквивалентно scanf("&d").

Когда switch (n) проверяет n, оно все равно будет содержать значение, с которым оно было инициализировано. Явного инициализатора не существует, поэтому он установлен на 0 (потому что это глобальная переменная (в частности, потому что он имеет статическое хранилище; см. C99, 6.7.8 Initialization / 10)).

Нет ярлыка case 0:, поэтому default: запускается.

...