C++ для начинающих. Ввод только чисел

Одним из вопросов, возникающих у новичков при попытках защитить программу от неправильного ввода данных, оказывается вопрос ввода только чисел. Во многих первых учебных задачах требуется ввод именно числовых значений. Над решением такой задачи можно поломать голову. Защита своей программы от потенциальных проблем — одна из обязательных истин любого программиста. Ведь если вы напишете программу, которая будет или работать странно, или раз через раз выдавать ошибки — мало какому пользователю понравится.
Одним из наиболее употребляемых способов обязательного ввода чисел может оказаться вот такой:

В некоторых случаях такой защиты от дурака достаточно.
Для решения этой задачи можно использовать ввод строки с последующим преобразованием строки в числовое значение. Строку удобно проверять на присутствие нехарактерных числам символов:

Этот способ лучше первого тем, что если ввести в число несколько, например, точек: 598.66.66 — то это будет считаться ошибкой, а в первом способе будет считаться, что было введено 598.66

Недостаток этого способа — это то, что приходится делать преобразования, а любые преобразования влияют на время работы программы. И ещё один недостаток — это не очень хорошая степень логичности. Это немного ненормально, что для того, чтобы ввести число, мы сначала вводим строку.

  • Для преобразования строки к числу в С используют или функцию atof (для дробного представления), или функцию atoi (для представления строки как целого число).
Теперь посмотрим на наиболее распространённые варианты решений. Тому, кто хочет побольше узнать, имеет смысл почитать описываемое ниже.
Напишем простую программу, вычисляющую среднее арифметическое. Предположим, вы работаете в страховой компании и ваша страховая компания оплачивает страховку в случае кораблекрушения, покрывая некоторую часть расходов убытка клиента из-за кораблекрушения. Согласно вашему договору с клиентом, вы оплачиваете половину стоимости груза. Вот нам и нужно посчитать, сколько мы будем платить. Для облегчения (в пользу сейчас обучающегося) предположим, что у корабля есть санкции, ограничивающие количество перевозимого товара, отчего корабль не имеет права перевозить больше 5 наименований груза. Но не будем ограничиваться стоимостью. Поскольку нас интересует только цена и известно, что есть максимум 5 предметов торговли, а надо рассчитать среднюю стоимость — то приступим к написанию программы.
По условию сложившейся задачи вы должны самостоятельно прикидывать, что потребуется для решения. В данном случае нам понадобится массив из 5 элементов, в ячейки которого мы будем записывать цену каждого предмета торговли потерпевшего крушения судна.

Если собрать программу из показанного кода, то чтобы не вводить все значения, можно ввести любое не число и тогда ввод прекратится. Также ввод будет прекращён, если ввести весь максимум значений.
Несмотря на кажущееся удобство есть в этом примере небольшой подводный камень. Если вводить в arr_cost[i] не число, то цикл конечно прекращается, но прекращается не только цикл: отключается вообще ввод в cin. Пример листинга #4 показывает попытку развития программы, где нагляден эффект отключения, обычно непонятный простым новичкам:

Поскольку ввод из-за попытки внедрения cin неожидаемого cin-ом типа отключился, то и попытки тщетны. Чтобы заново включить ввод, нужно будет добавить немного кода (см строки 37-):

В зависимости от типа запиываемого значения может быть небольшое различие, но в целом если тип символьный, то нужно учитывать символ нажатого Enter, эта строчка закомментирована, а если числовой, то просто нужно забрать из буфера введённый символ, останется переключить cin в рабочее состояние, для чего использовалось cin.clear().
Теперь поговорим о самом коде, о цикле while и что это в нём за cin >> arr_cost[i].

arr_cost[i] — это просто очередная ячейка массива, индекс которой i, её можно использовать как обычную переменную, тип которой соответствует типу заявленному массиву.
(cin >> arr_cost[i]) — это уже более сложно, но тем не менее объяснимо. Сама по себе такая запись обозначает прочитать что-то с клавиатуры и запомнить прочитанное значение в arr_cost[i], но кроме непосредственно чтения, для нас существует возможность узнать произошёл ли ввод удачно или что-то пошло не так.

  • Если cin используется как часть проверочного условия, он преобразуется в тип bool. Преобразованное значение равно true, если ввод прошел успешно, и false — в противном случае.
Почему ввод прекращается, если введено некорректное значение? Это происходит потому что для логических выражений || и && порядок анализа всегда слева-направо, а если левая часть выполняет/нарушает условие (в зависимости от того, что именно нужно), то правая просто не выполняется. Т. е. компилятор просто не проверяет ненужный для проверки хвост.

Поскольку когда мы выходим на граничащее значение массива и наращиваем i, 5 < 5 == false — цикл завершается, а cin просто хвостовая ненужность.
В том случае, если надо ввести все, например, значения, то нужной подойти к программе немного не так, как было в произошедшем сейчас разборе. Предположим, что программа обнаружила неправильный ввод пользователя. Она должна выполнить три действия:

  • Сбросить состояние cin для принятия нового ввода
  • Освободиться от некорректного ввода
  • Предложить пользователю повторить ввод
Обратите внимание:

  • Программа должна сбросить cin перед тем, как отклонять неверный ввод.
Пример:

10 комментариев на «“C++ для начинающих. Ввод только чисел”»

  1. Иван Иванов:

    Гарантировать ввод числа (например, float) можно ещё так:

    Автор сайта отвечает
    Разница между кодом показанным в статье и кодом, показанным вами, в том, что код из статьи просто не даст вводить то, что к части числа не относится. Ваш код позволит вводить число с частью не относящейся к построению числа отбрасывая все, что за этой частью.

    Точнее если ввести 5ааа5ааа
    ваш код сохранит в переменную 5
    код из сайта сохранит в переменную 55

    тут подкорректирован для mingw

  2. fENGO:

    я ввожу плюс или минус,а возращает не false, a true

    • Да, это проверка, которая определяет + или — принадлежат к знаку числа или являются частью строки:
      +788 — число
      -55 — число
      55-99 — не число

      • fENGO:

        ЭТО БУДЕТ ПЕРЕПОЛНЕНИЕ СТЕКА?

  3. fENGO:

    я ввожу плюс или минус,а возращает не false, a true

  4. fENGO:

    Не понимаю это обьясните,пожалуйсто

    • if (strcchr(Строка, Искомый_Символ) == NULL) return false;
      Функция strchr возвращает указазатель, если символа в строке найдено не было, то возвращается нулевой указатель. Если символа не нашлось (т. е. функция вернула нулевой указатель), то отдаём false

  5. fENGO:

    ЭТО БУДЕТ ПЕРЕПОЛНЕНИЕ СТЕКА?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Поиск

 
     

Случайная книга в электронном формате

https://www.litres.ru/aleksandr-shen/programmirovanie-teoremy-i-zadachi-11647808/?lfrom=15589587

Последние комментарии

Яндекс.Метрика