Полученные знания всегда нужно применять на практике, поэтому мы сначала повторим теорию, а затем перейдем к практике.
Теория
Целочисленные типы данных используются для хранения целых чисел. Не забывайте о проблемах деления и переполнения с ними. Используйте целочисленные типы с фиксированным размером.
Типы данных с плавающей точкой используются для хранения вещественных чисел. Не забывайте о проблемах с точностью, ошибках округления и неточном сравнении чисел.
Логический тип данных содержит 2 значения: true
и false
.
Символьный тип данных содержит целые числа, которые могут интерпретироваться в символы, соответствующие стандарту ASCII. Будьте осторожны при использовании фактических чисел и цифр, которые используются для представления символов. Также помните о проблемах переполнения.
Используйте спецификатор const для объявления символьных констант вместо использования директив #define. Это безопаснее.
Задание №1
Почему символьные константы лучше литеральных (магических чисел)? Почему использование const
лучше использования директив #define?
Ответ №1
Использование литеральных констант (магических чисел) не только усложняет программу, но и затрудняет внесение в нее изменений. Символьные константы лучше, так как они дают понимание того, зачем и почему они используются, а также, если вам еще понадобится внести изменения — достаточно будет внести правки только в объявлении константы, а не искать их по всему коду. Значения констант, объявленных с помощью директивы #define, не отображаются в отладчике, вероятность возникновения конфликта имен у таких констант выше.
Задание №2
Выберите подходящий тип данных для переменных в каждой из следующих ситуаций. Будьте как можно более конкретными. Если ответом является целочисленный тип данных, то используйте соответствующий тип с фиксированным размером (например, int16_t). Если переменная должна быть константной, то так и отвечайте.
Возраст пользователя.
Нравится ли определенный цвет пользователю?
Число Пи.
Количество страниц в учебнике.
Цена акций в долларах (дробь присутствует).
Сколько раз вы моргнули за всю свою жизнь? (Примечание: Ответ исчисляется в миллионах)
Пользователь выбирает опцию с помощью ввода определенной буквы.
Ответ №2
int8_t не сможет хранить возраст человека, старше 127. Несмотря на то, что таких случаев в мире единицы (если есть вообще), в будущем это может быть вполне возможным. Так что int16_t здесь подойдет лучше.
bool.
const double.
Так как большинство книг имеют больше 255 страниц, но меньше чем 32767, то int16_t — здесь наилучший вариант.
float.
int32_t.
char.
Задание №3
Напишите следующую программу. Сначала пользователю предлагается ввести 2 числа типа с плавающей точкой (используйте тип double). Затем предлагается ввести один из следующих математических символов: +
, -
, *
или /
. Программа выполняет выбранную пользователем математическую операцию между двумя числами, а затем выводит результат на экран. Если пользователь ввел некорректный символ, то программа ничего не должна выводить. Например:
Enter a double value: 7
Enter a double value: 5
Enter one of the following: +, -, *, or /: *
7 * 5 = 35
Подсказка: Вы можете использовать ветвление if для того, чтобы распознать, ввел ли пользователь определенный математический символ (например, +
) или нет. Детально об этом читайте в материалах урока №34.
Ответ №3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
#include <iostream> double getDouble() { std::cout << "Enter a double value: "; double x; std::cin >> x; return x; } char getOperator() { std::cout << "Enter one of the following: +, -, *, or / "; char op; std::cin >> op; return op; } void printResult(double x, char op, double y) { if (op == '+') std::cout << x << " + " << y << " = " << x + y << '\n'; else if (op == '-') std::cout << x << " - " << y << " = " << x - y << '\n'; else if (op == '*') std::cout << x << " * " << y << " = " << x * y << '\n'; else if (op == '/') std::cout << x << " / " << y << " = " << x / y << '\n'; } int main() { double x = getDouble(); double y = getDouble(); char op = getOperator(); printResult(x, op, y); return 0; } |
Задание №4
Это уже немного сложнее. Напишите небольшую программу-симулятор падения мячика с башни. Сначала пользователю предлагается ввести высоту башни в метрах. Не забывайте о гравитации (9,8м/с2
) и о том, что у мячика нет начальной скорости (его держат в руках). Программа должна выводить расстояние от земли, на котором находится мячик после 0, 1, 2, 3, 4 и 5 секунд падения. Минимальная высота составляет 0 метров (ниже мячику падать нельзя).
В вашей программе должен быть заголовочный файл constants.h с пространством имен myConstants
. В myConstants
определите константу для хранения значения силы тяжести на Земле (9.8
). В качестве напоминания смотрите урок №37.
Напишите функцию для вычисления высоты мячика через х
секунд падения. Используйте следующую формулу: высота мячика над землей = константа_гравитации * x_секунд2/2.
Пример результата выполнения программы:
Enter the initial height of the tower in meters: 100
At 0 seconds, the ball is at height: 100 meters
At 1 seconds, the ball is at height: 95.1 meters
At 2 seconds, the ball is at height: 80.4 meters
At 3 seconds, the ball is at height: 55.9 meters
At 4 seconds, the ball is at height: 21.6 meters
At 5 seconds, the ball is on the ground.
Примечания:
В зависимости от начальной высоты, мячик может и не достичь земли в течение 5 секунд — это нормально. Мы усовершенствуем эту программу, когда будем рассматривать циклы.
Символ ^
не является экспонентом в языке C++. В формуле вместо него используйте знак умножения *
.
Ответ №4
Файл constants.h:
1 2 3 4 5 6 7 8 |
#ifndef CONSTANTS_H #define CONSTANTS_H namespace myConstants { const double gravity(9.8); } #endif |
Файл main.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#include <iostream> #include "constants.h" // Получаем начальную высоту от пользователя и возвращаем её double getInitialHeight() { std::cout << "Enter the initial height of the tower in meters: "; double initialHeight; std::cin >> initialHeight; return initialHeight; } // Возвращаем расстояние от земли после "..." секунд падения double calculateHeight(double initialHeight, int seconds) { // Используем формулу: [ s = u * t + (a * t^2) / 2 ], где u(начальная скорость) = 0 double distanceFallen = (myConstants::gravity * seconds * seconds) / 2; double currentHeight = initialHeight - distanceFallen; return currentHeight; } // Выводим высоту, на которой находится мячик после каждой секунды падения void printHeight(double height, int seconds) { if (height > 0.0) std::cout << "At " << seconds << " seconds, the ball is at height: " << height << " meters\n"; else std::cout << "At " << seconds << " seconds, the ball is on the ground.\n"; } void calculateAndPrintHeight(double initialHeight, int seconds) { double height = calculateHeight(initialHeight, seconds); printHeight(height, seconds); } int main() { const double initialHeight = getInitialHeight(); calculateAndPrintHeight(initialHeight, 0); calculateAndPrintHeight(initialHeight, 1); calculateAndPrintHeight(initialHeight, 2); calculateAndPrintHeight(initialHeight, 3); calculateAndPrintHeight(initialHeight, 4); calculateAndPrintHeight(initialHeight, 5); return 0; } |
Обратите внимание, функция calculateHeight() не выводит высоту на экран (помните о «правиле одного задания»). Мы используем отдельную функцию для вывода.
В задании №3 захотелось поэкспрементировать с делением long double
после вот такого кода получил следующий результат:
Enter a double value:
14.958
Enter a second double value argument:
97.1122331423
Choose arithmetic operation by printing one of the following: +, -, *, or /:
/
14.958/97.1122331422999999981 = 0.154027968629676346378
Конечно же, у меня был «нормальный» путь — создать отдельную переменную для результата деления. И надеяться на компилятор, потому как индекс ld/LD/lD/Ld будет негде поставить — инициализация такой переменной зависит от ввода пользователя…
когда же я поменял setprecision на 22, то получил следующее:
14.957999999999999999993/97.112233142299999998082 = 0.15402796862967634637762
Что же произошло? Если всё правильно понял, то для выражений в cout у нас дефолтная точность double — 16 значащих цифр. И эта точность ‘как-то’ распределяется на два аргумента делимое/делитель.
У первого 5 верных цифр, у второго 11(первый случай, точность 21). Всё нормально. НО уже во втором случае получается точность 4 + 11 = 15. Или всё-таки пятую цифру первого аргумента нужно считать, а я совсем не понимаю правил округления? Почему компилятор gcc взбесился именно от setprecision(22), а при setprecision(21) — точность long double — выдал вполне обычный, понятный результат?
Благодарю, если кто-то заморочится с поиском истины, хотя это и не так важно. ))
Юра, спасибо тебе за этот чудесный сайт!!!
Служу сейчас в ЗСУ и в свободное время решил попробовать овладеть новыми знаниями (у меня образование медицинское).
Дошел до Итогового теста 2-й главы и понял, что не смогу написать 4-е задание без заглядывания в ответы.
Начал все заново с первого урока.
Просил чат GPT дать дополнительные задачки по каждой теме.
В итоге написал 4-е задание без подсказок и, не веря в работоспособность сего творения, нажал на на пуск)
Как же я радовался, когда все получилось! Программа рабочая, но дай, пожалуйста, обратную связь, что я сделал не удачно?
Слава Украине!
constants.h
main.cpp
Привет! По коду — бросается в глаза функция result(), которая перегружена «однотипным» кодом. Можно подумать, как избавиться от многочисленных if.
То, что не всё дается сразу и легко — это нормально, таков процесс обучения не только в программировании, но и в других сферах. Слишком зацикливаться на подобных задачках не стоит, но и пропускать тоже не желательно.
P.S. А вообще в программировании всегда есть много разных вариантов решения проблемы: одни — удачны, но сложны, другие — простые, но громоздкие, третьи — и сложны и громоздкие и т.д. Задача хорошего программиста состоит в том, чтобы подобрать наиболее удачное из существующих решение конкретной проблемы, учитывая обстоятельства ситуации. Это нелегко 🙂
Это отлично, я тоже начал осваивать С++, будучи экономистом. Много if . Использовать лучше либо switch, либо через цикл (ещё лучше, так как он красиво после каждой итерации тебе выведет остаток после каждой секунды)
Слава Украине
Спасибо за поддержку)
Но ведь switch и циклы рассматриваются в 5 й главе и я до них не дошел? Или я где-то что-то пропустил?
Первое задание сделал с помощью добавления функции на получение времени. Костыль с «i<time +1″(цикл на 1 раз меньше выполняется из-за итератора) можно было через while пофиксить, но так тоже работает.
Вот моё решение
main.cpp
constants.h
Добрый вечер! Вот мой код 🙂 все никак не научу себя применять функции, кроме как функции ввода)
Здравствуйте! Вот моё решение, все ответы совпали, как в примере. Подскажите пожалуйста, чем плох моё решение?
Привет, посмотрел решение автора по заданию 4 и… Ничегошеньки не понял, очень мудреное, сложно читать и понять. Я сделал чуть полегче (по деревенски) и нарушил одно негласное правило. Но все же работает)
Пытался сделать на If, но что то пошло не так. Код не сильно читабельный (У меня была цель — выполнить поставленную задачу со всеми проверками и тд.). Возможно код не оптимизирован, но зато работает (на любую высоту (в пределах double)). 🙂
main.cpp
constants.h
Обновленный код (почищен, мелкие fix's). В принципе на этом все, всем удачи 🙂
очень интересные названия функций))
Добрый день!
Спасибо авторам за такой замечательный ресурс!
У меня есть вопросы по упр. 4:
1. Почему в функции double calculateHeight в аргументе мы прописываем double initialHeight, int seconds.
а в самой функции появляются переменные distanceFallen и currentHeight. Почему их не надо прописывать в имени функции, а initialHeight и seconds нужно прописать.
2. Почему в main нам потребовалось объявить константой initialHeight?
3. Почему в main в вызове функции calculateAndPrintHeight у нас указан аргумент initialHeight, но он разный, хотя мы его объявили константой. Почему нельзя использовать значение currentHeight (хотя, прописал в функции void calculateAndPrintHeight(double currentHeight, int seconds), и затем double height = calculateHeight(currentHeight, seconds); и все равно работает программа (вот как выглядит функция после изменения:
)
Спасибо за ответы.
initialHeight находится в разных областях видимости, и что бы знать что значение значит подписал одинаково, в моем варианте они разные, чтоб не возникало путаницы..
Ваш вариант может и рабочий, но возникает вопрос для не опытного откуда это взялось, а так по функциям читается получше, если разные названия а не как у автора одинаковые, долго мучался разбирался пока все понял
Как же я ломал голову по поводу передачи расстояния из функции с потерей остатка от деления. Оказалось что тип данных функции всего то нужно было превратить в тип double 😀
main.cpp
constants.h
Задание №4. Решения других пользователей мне по какой-то причине кажутся очень сложными, пока разбирался в их коде заболела голова. Сам набросал такой код, кажется, что он куда проще и читабельнее.
Интересно кончено, но только один вопрос: а зачем вообще нужно было добавлять bool boba, если можно в if вписать (bH > 0), что по сути тоже самое? Тот же вопрос к глобальной переменной check, которая по сути нужна ни для чего. Ведь в функции gMetr мы получаем значение, которое затем присваиваем переменной g и посылаем в функцию calcHeight, после чего, зачем-то, делаем это значение глобальным, при том что используется оно в единственной функции, в которой это значение уже и так есть
Извините, пожалуйста, если я выскажу что — то несущественное. Я изучала программирование самостоятельно и для моих научных задач мне хватало навыков, или я осваивала новые. Но мне хотелось некоторого фундаментального взгляда на программирование…. Вот для этого я читаю и использую этот курс….. Что меня напрягает, может не верно, извините…. Но метр, верста, секунда — это не физические величины, а единицы измерения….. Получается, что в Вашей программе Вы ищете единицу измерения….. Извините, я бы не написала, если бы не увидела этого во множестве программ…… Если не трудно, ответьте, в чем я ошибаюсь….
А такой вопрос, обязательно всё расфасовывать по функциям? Просто мне кажется, что на данном этапе изучения гораздо читабельней код, как пример мой, ниже. Я понимаю, что для одного дела одна функция, но создавая подобную сеть для столь малой программы, мне кажется, код излишне запутывается. Прошу высказать альтернативную точку зрения
Я, как любитель модульных программ (как моды для игр), люблю использование функций из-за одной важной детали: эти функции можно модифицировать и\или использовать в других программах. К тому же возможность проверить каждую функцию отдельно от кода бывает полезной (и я уже не говорю про возможность сворачивать функции, в которых ты уверен, в 1 строку (в VisualStudio)).
Но в целом — да, для небольших программ можно и без функций
Я сделал четвертое задание так, чтобы можно было проверить любую высоту башни без использования циклов.
main.cpp:
myConst.h:
Сколько раз вы моргнули за всю свою жизнь? (Примечание: Ответ исчисляется в миллионах)
int32_t, зачем нам отрицательная часть) лучше заменить на uint32_t
«Использовать тип unsigned (вместо signed) для получения еще одного бита для представления положительных целых чисел, почти никогда не является хорошей идеей» — Бьёрн Страуструп
https://ravesli.com/urok-32-fiksirovannyj-razmer-integers-spor-naschet-unsigned/#toc-5
Добрый день, мой вариант
третье задание
Неверно. Вернее, программа все равно выводит правильный ответ, но в начале строчки есть пробел. Это оттого, что else будет исполняться всегда, за исключением последнего случая(/). Чтобы программа правильно работала, все if-ы кроме первого нужно заменить на else if.
Задание №4
Основной код:
constants.h
При усовершенствовании программы пришлось разнести расчет данных и вывод их на экран по разным функциям) Наглядно видна разница.
Спасибо Вам большое, Юрий! Этим урокам просто нет равных.
Третье задание. Для каждой задачи свой файл.
input.cpp
input.h
calculate.cpp
calculate.h
output.cpp
output.h
main.cpp
Третье задание:
Файл main.cpp:
Файл inNumber.cpp:
Файл cimbol.cpp:
Файл head.h:
Четвертое задание:
Файл main/cpp:
Файл constanta.h:
Третье задание, нормально?
4 задание
Что скажете?
4-е задание:
FallingBall.h:
BallFallConstants.h:
FallingBall.cpp:
Source.cpp:
3-е задание:
Очень забавляют люди, которые используют для решения четвертой задачи циклы. Тут ведь соль задачи, как я понимаю, именно в том, чтобы решить её только с помощью имеющихся средств, то есть только с тем, что уже было пройдено ранее.
У меня вышел такой вот код, к сожалению, отрицательную высоту все равно показывает, не понимаю, почему так(
constants.h
main.cpp
Уже не актуально но всё же .Проверка в 16 строке не имеет смысла ,bW всегда будет положительная потому что умножение и деление не может сделать число отрицательным .Нужно проверять разницу начальной высоты и расчётной .У вас расчётная высота всегда возвращается и если она больше начальной то возникает минус .Например начальная высота 5 а расчёт вернул 10; 5-10=-5
Всегда актуально, спасибо большое)
Сделал такой код.
constants.h
program.h
main.cpp
Калькулятор
Не понимаю, почему после 3 секунды у меня начинаются отрицательные числа
1) Y в этой программе — не скорость, а значение текущей высоты.
2) Условие в блоке if проверяется 1 раз при выполнении строчки, если в момент срабатывания if условие выполняется — вложенный цикл оттарабанит до конца, потому что внутри цикла ничто не может его прервать (не влияет на счетчик i). Вместо использованной конструкции if + for достаточно одного цикла while, где условием будет высота больше 0, а в теле будет, собственно, эта высота изменяться. Ну или же засунуть if на проверку высоты в тело цикла for (с последующим break), рабочий вариант, но более громоздкий.
3. Зачем вывод функции через инициализацию double h? Исходя из того, как написана функция, достаточно типа void и все.
Вышло как-то так
myConstants.h
main.cpp