Код
#Руководства

Ввод данных и обработка исключений в С++: 4-я часть гайда по языку программирования

Разбираемся, как правильно использовать ввод данных, чтобы ничего не сломалось.

 vlada_maestro / shutterstock

Это четвёртая часть из серии статей «Глубокое погружение в C++». В прошлый раз мы познакомились с ветвлением и условными конструкциями. Сейчас поговорим о том, как сделать программу более полезной за счёт ввода данных и обработки исключений.

Если программа работает с изначально заданными данными, то она полезна только один раз, потому что результат будет всегда один и тот же. Гораздо эффективнее она становится, когда можно использовать разные данные:

  • числа для вычисления;
  • команды пользователя;
  • изображения;
  • аудио и видео;
  • текст и так далее.

Как получить и обработать данные через консоль? Давайте пробовать.

Команды ввода и вывода в C++

В самом начале кода каждой программы мы подключаем библиотеку iostream Input/Output Stream (поток ввода/вывода). Именно в ней находится команда cout, что позволяет выводить данные на экран консоли. В ней же есть команда cin, которая, наоборот, запрашивает пользовательский ввод.

Давайте напишем простую программу, которая спрашивает имя пользователя.

#include <iostream>

int main()
{
    std::string name;

    std::cout << "Enter your name: ";

    std::cin >> name;

//С помощью одной команды cout можно вывести несколько значений
    std::cout << "Hello, " << name << "! \n";
}

Сначала мы объявили переменную name строкового типа, а потом сказали пользователю, что именно нужно ввести, и в конце выдали сообщение «Hello, %name%!». Это выглядит так:

Важно! Старайтесь всегда сообщать пользователю, какие действия от него требуются и что происходит в программе.

Также вы можете запросить от пользователя данные других типов. Например, числовые:

int a, b, c;

std::cout << "Enter a: ";
std::cin >> a;

std::cout << "Enter b: ";
std::cin >> b;

c = a + b;

std::cout << a << " + " << b << " = " << c;

Получается простейший калькулятор:

Это работает с символами, числами с плавающей запятой и другими данными.

Проверка консольного ввода в C++

Как мы уже говорили в первой статье, компьютер может только выполнять инструкции. Когда что-то идёт не по плану, он не способен самостоятельно решить, что ему делать, поэтому выдаёт ошибку.

Допустим, нам нужно, чтобы пользователь ввёл свой возраст. Мы ожидаем число вроде 8, 15 или 21, но кто-то может ввести эти числа прописью, например «двадцать один». Для программы эти варианты будут неожиданными, потому что она уже подготовила переменную типа int строка в неё никак не влезет.

Чтобы избежать таких ошибок, любые данные от пользователей стоит принимать как строку, а потом переводить в нужный нам тип. Процесс преобразования данных из одного типа в другой называется конвертацией.

Шутка в тему от Пикабу

Конвертация данных

В C++ самый простой способ конвертировать строку в число — использовать функцию stoi () или аналогичную:

std::string ageInput;
int age;

std::cout << "How old are you: ";
std::cin >> ageInput;

//В круглых скобках функции указывается значение, которое нужно конвертировать
age = stoi(ageInput);

std::cout << "You are " << age << " years old. \n";

Вот пример корректной и некорректной конвертации:

Как видно на скриншоте, в первом случае всё прошло успешно, но в следующих случаях программа выдала ошибку. Давайте рассмотрим последнюю:

Разберём некоторые моменты подробнее:

  • Исключение (exception) — это что-то вроде ошибки, но не совсем. Разные части программы могут «выбрасывать» их при определённых условиях, чтобы сказать: что-то идёт не так; в данном случае — out of range (выход из диапазона). Это исключение было выброшено, потому что введённое число больше, чем может поместиться в переменную типа int.
  • Дамп памяти (memory dump) — это содержимое рабочей памяти одного процесса, ядра или всей операционной системы. Дамп можно посмотреть, чтобы понять, каким было состояние программы и почему она аварийно завершила работу.

Чтобы программа не закрывалась при выбрасывании исключений, их нужно обработать.

Обработка исключений в C++

Для этого нам пригодится конструкция try-catch.

Вот код программы, которая проверяет корректность введённых данных:

std::string ageInput;
int age = 0;

std::cout << "How old are you: ";
std::cin >> ageInput;

//Названия исключений можно посмотреть в сообщениях об ошибке
try
{
    age = stoi(ageInput);
}
catch(std::invalid_argument) 
{
    //Говорим, что можно вводить только числа
    std::cout << "Only numbers are allowed! \n";
}
catch(std::out_of_range)
{
    //Говорим, что число слишком большое
    std::cout << "You can't be that old! \n";
}
catch(...)
{
    //Если будет выброшено какое-то исключение, которое не обработано выше, то говорим, что возникла неизвестная ошибка
    std::cout << "Unknown error! \n";
}

if(age > 0)
{
    std::cout << "You are " << age << " years old. \n";
}
else
{
    std::cout << "Try again! \n";
}

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

Пользовательский ввод и ветвление

С помощью пользовательского ввода можно по-настоящему раскрыть возможности условных конструкций. Например, конструкция switch позволяет создать простое консольное меню.

int action = 0;

//Выводим меню
std::cout << "===Calculator++==\n1 - Addition\n2 - Subtraction\n3 - Division\n4 - Multiplication\n5 - Quadratic equation\nAction: ";

//Допускаем, что ввод будет верным
std::cin >> action;

switch(action)
{
    case 1:
   	 //Сложение
   	 break;

    case 2:
   	 //Вычитание
   	 break;

    case 3:
   	 //Деление
   	 break;

    case 4:
   	 //Умножение
   	 break;

    case 5:
   	 //Квадратные уравнения
	std::cout << 
   	 break;
}

Теперь можно прописать разные инструкции для каждого из этих действий.

Конструкция if пригодится для решения квадратных уравнений:

double a, b, c, d, x1, x2;

std::cout << "ax^2 + bx + c = 0\n";

std::cout << "a = ";
std::cin >> a;

std::cout << "b = ";
std::cin >> b;

std::cout << "c = ";
std::cin >> c;

d = (b * b) - 4 * a * c;

std::cout << "d = " << b << "^2 - 4 * " << a << " * " << c << "\n";
std::cout << "d = " << d << "\n";

if(d > 0)
{
    //Для работы функции sqrt() нужно подключить библиотеку cmath
    x1 = (-b + sqrt(d)) / (2 * a);
    x2 = (-b - sqrt(d)) / (2 * a);

    std::cout << "x1, x2 = (-" << b << " +- sqrt(" << d << ")) / (2 * " << a <<")\n";
    std::cout << "x1 = " << x1 << "\nx2 = " << x2 << "\n";
}
else if(d == 0)
{
    x1 = -(b / (2 * a));
    std::cout << "x1, x2 = -(" << b << " / (2 * " << a << ")\n";
    std::cout << "x1, x2 = " << x1 << "\n";
}
else if(d < 0)
{
    std::cout << "No roots! \n";
}

Такие программы сильно упрощают жизнь не только учёным и инженерам, но и школьникам:

Заключение

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

Проверьте свой английский. Бесплатно ➞
Нескучные задания: small talk, поиск выдуманных слов — и не только. Подробный фидбэк от преподавателя + персональный план по повышению уровня.
Пройти тест
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована