1.11 – Разработка первой программы на C++

Добавлено 9 апреля 2021 в 17:26

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

Умножение на 2

Во-первых, давайте создадим программу, которая просит пользователя ввести целое число, ждет, когда он введет целое число, а затем сообщает ему, чему будет равно это число, умноженное два. Программа должна выдать следующий результат (предположим, я ввел 4 в качестве входных данных):

Enter an integer: 4
Double that number is: 8

Как справиться с этой задачей? Пошагово.

Лучшая практика


Программисты-новички часто пытаются написать всю программу сразу, а затем теряются, когда она выдает много ошибок. Лучшая стратегия – добавлять по одному элементу за раз, проверять его компиляцию и тестировать. Затем, когда вы убедитесь, что один элемент работает, переходите к следующему фрагменту.

Мы используем эту стратегию и здесь. По мере прохождения каждого шага набирайте (не копируйте/вставляйте) каждую программу в своей IDE, компилируйте и запускайте ее.

Сначала создайте новый консольный проект.

Теперь давайте начнем с основного каркаса. Мы знаем, что нам понадобится функция main() (поскольку она должна быть во всех программах на C++), поэтому, если ваша среда IDE не создала эту функцию пустой при создании нового проекта, давайте создадим ее сами:

int main()
{
	return 0;
}

Мы знаем, что нам нужно будет выводить текст в консоль и получать текст с клавиатуры пользователя, поэтому нам нужно включить iostream для доступа к std::cout и std::cin.

#include <iostream>
 
int main()
{
	return 0;
}

Теперь давайте сообщим пользователю, что нам нужно ввести целое число:

#include <iostream>
 
int main()
{
	std::cout << "Enter an integer: ";
 
	return 0;
}

На этом этапе ваша программа должна выдать такой результат:

Enter an integer:

а затем завершиться.

Далее мы собираемся получить от пользователя входные данные. Для этого мы будем использовать std::cin и operator>>. Но нам также необходимо определить переменную для хранения этого входного значения, чтобы использовать его в дальнейшем.

#include <iostream>
 
int main()
{
	std::cout << "Enter an integer: ";
 
	int num{ 0 };    // определяем переменную num как целочисленную переменную
	std::cin << num; // получаем целочисленное значение с клавиатуры пользователя
 
	return 0;
}

Пора скомпилировать наши изменения… и…

Ой! Вот что автор получил в Visual Studio 2017:

1>------ Build started: Project: Double, Configuration: Release Win32 ------
1>Double.cpp
1>c:\vcprojects\double\double.cpp(8): error C2678: binary '<<': no operator found which takes a left-hand operand of type 'std::istream' (or there is no acceptable conversion)
1>c:\vcprojects\double\double.cpp: note: could be 'built-in C++ operator<<(bool, int)'
1>c:\vcprojects\double\double.cpp: note: while trying to match the argument list '(std::istream, int)'
1>Done building project "Double.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Мы столкнулись с ошибкой компиляции!

Во-первых, поскольку программа компилировалась до того, как мы сделали это последнее обновление, и не компилируется сейчас, ошибка должна быть в только что добавленном коде (строки 7 и 8). Это значительно сокращает объем кода, который мы должны проверить, чтобы найти ошибку. Строка 7 довольно проста (просто определение переменной), поэтому здесь ошибки, вероятно, нет. Под подозрением остается строка 8.

Во-вторых, это сообщение об ошибке нелегко прочитать. Но давайте выделим некоторые ключевые элементы: компилятор сообщает нам, что он обнаружил ошибку в строке 8. Это означает, что фактическая ошибка, вероятно, находится в строке 8 или, возможно, в предыдущей строке, что подтверждает нашу предыдущую оценку. Затем компилятор сообщает вам, что не смог найти оператор '<<' с левым операндом типа std::istream (который является типом std::cin). Другими словами, operator<< не знает, что делать с std::cin, поэтому ошибка должна быть либо в использовании std::cin, либо в использовании operator<<.

Теперь видите ошибку? Если нет, посмотрите еще.

Вот программа, содержащая исправленный код:

#include <iostream>
 
int main()
{
	std::cout << "Enter an integer: ";
 
	int num{ 0 };
	std::cin >> num; // std::cin использует оператор >>, а не оператор <<!
 
	return 0;
}

Теперь программа компилируется, и мы можем ее протестировать. Программа будет ждать, пока вы введете число, поэтому давайте введем 4. Результат должен выглядеть следующим образом:

Enter an integer: 4

Почти готово! Последний шаг – удвоить число.

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

Есть (по крайней мере) 3 способа сделать это. Пойдем от худшего к лучшему.

Плохое решение

#include <iostream>
 
// худшая версия
int main()
{
	std::cout << "Enter an integer: ";
 
	int num{ 0 };
	std::cin >> num;
 
	num = num * 2; // удваиваем значение num, а затем присваиваем это значение обратно num
 
	std::cout << "Double that number is: " << num << '\n';
 
	return 0;
}

В этом решении мы используем выражение для умножения num на 2, а затем присваиваем это значение обратно num. С этого момента num будет содержать наше удвоенное число.

Почему это плохое решение:

  • Перед оператором присваивания num содержит введенные пользователем данные. После присваивания оно содержит другое значение. Это сбивает с толку.
  • Мы перезаписали входные данные пользователя, присвоив новое значение входной переменной, поэтому, если мы захотим расширить нашу программу, чтобы сделать что-то еще с этим входным значением позже (например, утроить входное значение пользователя), но оно уже будет потеряно.

Почти хорошее решение

#include <iostream>
 
// менее плохая версия
int main()
{
	std::cout << "Enter an integer: ";
 
	int num{ 0 };
	std::cin >> num;
 
    // определяем новую переменную и инициализируем ее с num * 2
	int doublenum{ num * 2 }; 
    // затем печатаем значение этой переменной
	std::cout << "Double that number is: " << doublenum << '\n';
 
	return 0;
}

Это решение довольно просто читать и понимать, и оно решает обе проблемы, возникающие при наихудшем решении.

Основным недостатком здесь является то, что мы определяем новую переменную (что добавляет сложности) для хранения значения, которое мы используем только один раз. Мы можем добиться большего.

Предпочтительное решение

#include <iostream>
 
// предпочтительная версия
int main()
{
	std::cout << "Enter an integer: ";
 
	int num{ 0 };
	std::cin >> num;
 
    // используем выражение для умножения num * 2 в точке, где мы собираемся его напечатать
	std::cout << "Double that number is: " <<  num * 2 << '\n';
 
	return 0;
}

Это предпочтительное решение из всех. Когда выполняется std::cout, вычисляется выражение num * 2, и результатом будет удвоенное значение num. Это значение будет напечатано. Само значение в num не будет изменено, поэтому мы можем использовать его позже, если захотим.

Эта версия является нашим эталонным решением.

Примечание автора


Первая и основная цель программирования – заставить вашу программу работать. Программа, которая не работает, бесполезна, независимо от того, насколько хорошо она написана.

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

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

Конечным результатом является то, что наши первоначальные решения часто недостаточно хорошо структурированы, надежны (устойчивы к ошибкам), читабельны или кратки. Итак, как только ваша программа заработает, ваша работа на самом деле не закончена (если только программа не является одноразовой). Следующим шагом будет очистка вашего кода. Это включает в себя такие вещи, как удаление (или закомментирование) временного/отладочного кода, добавление комментариев, обработка случаев ошибок, форматирование кода и обеспечение соблюдения передовых практик. И даже тогда ваша программа может быть не такой простой, как могла бы быть – возможно, есть избыточная логика, которую можно объединить, или несколько операторов, которые тоже можно объединить, или переменные, которые не нужны, или тысяча других мелочей, которые можно было бы упростить. Слишком часто начинающие программисты сосредотачиваются на оптимизации для повышения производительности, тогда как им следует оптимизировать для удобства обслуживания.

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

Всё это на самом деле для того, чтобы сказать: не расстраивайтесь, если/когда ваши решения не выходят чудесно оптимизированными прямо из вашего мозга. Это нормально. Совершенство в программировании – это итеративный процесс (требующий многократных проходов).

Примечание автора


Еще одна вещь: вы можете подумать: «В C++ так много правил и концепций. Как мне всё это запомнить? ».

Короткий ответ: Никак. Использование того, что вы знаете в C++, – одна треть, оставшиеся две трети – это поиск, как сделать всё остальное.

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

Небольшой тест

Вопрос 1

Измените решение, показанное выше, на «лучшее решение» так, чтобы его вывод был следующим (при условии, что пользователь ввел 4):

Enter an integer: 4
Double 4 is: 8
Triple 4 is: 12

#include <iostream>
 
int main()
{
	std::cout << "Enter an integer: ";
 
	int num{ 0 };
	std::cin >> num;
 
	std::cout << "Double " << num << " is: " << num * 2 << '\n';
	std::cout << "Triple " << num << " is: " << num * 3 << '\n';
 
	return 0;
}

Теги

C++ / CppДля начинающихОбучениеПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.