Основы С++

Оглавление

1. Простой учебник С++ для начинающих

2. Для кого С++

3. Настройка рабочего окружения C++

3.1 Компилятор C++ в Linux

3.2 Компилятор C++ в Windows

3.3 IDE с поддержкой C++ для Linux и Windows

3.4 Нечитаемые символы (кракозябры) программ на C++ в Windows

4. Компиляция и выполнение программы C++

5. Структура программы на C++

5.1 Точки с запятой и блоки в C++

5.2 Идентификаторы C++

5.3 Пробелы в C++

5.4 Комментарии в C++

6. Строки в C++

6.1 Строки символов в стиле C

6.2 Класс string в C++

6.2.1 Пример использования функции replace

6.2.2 Пример использования функции substr

6.2.3 Пример использования функции swap

6.3 Сравнение char со строкой в C++

7. Справочная информация по функциям C++

8. Основы ввода/вывода C++

8.1 Заголовочные файлы библиотеки ввода/вывода

8.2 Стандартный поток вывода (cout)

8.3 Стандартный входной поток (cin)

8.4 Стандартный поток вывода ошибок (cerr)

8.5 Стандартный поток журнала (clog)

8.6 Как ввести в cin строки с пробелами в С++

8.7 Примеры программа ввода данных — анкета

9. Типы переменных C++

9.1 Определение переменной в C++

9.2 Объявление переменных в C++

9.3 Тип переменной string?

9.4 Lvalues и Rvalues

9.5 Зарезервированные слова C++ (ключевые слова C++)

10. Операторы в C++

10.1 Арифметические Операторы

10.2 Операторы отношений

10.3 Логические Операторы

10.4 Битовые операторы

10.5 Операторы присваивания

10.6 Разные операторы

10.7 Приоритет операторов в C++

11. Математические операции C++

11.1 Диапазоны и точность чисел в C++

11.2 Почему в C++ для double в числе только 5 цифр после запятой

11.3 Математические функции в C++

11.4 Случайные числа в C++

12. Инструкции принятия решений в C++ (if, if…else, switch)

12.1 Инструкция if в C++

12.2 Инструкция if…else в C++

12.3 Инструкция if…else if…else

12.4 Инструкция switch в C++

12.5 Вложенные инструкции if в C++

12.6 Вложенные инструкции switch в C++

12.7 Условный оператор ? :

12.8 Примеры программ на C++ для решения школьных задач (нахождение площади треугольника)

13. Типы циклов C++

13.1 Цикл while в C++

13.2 Цикл for в C++

13.3 Цикл do…while в C++

13.4 Вложенный циклы C++

14. Чтение стандартного ввода в C++

15. Конвертирование из одного типа данных в другой в C++

15.1 Как конвертировать char в string

15.2 Как преобразовать число в строку

15.3 Как преобразовать строку в число

15.4 Преобразование различных типов чисел

15.5 Преобразование последовательность символов в целочисленное значение или значение с плавающей точкой

15.6 Преобразование целого числа или значение с плавающей запятой в строку

16. Доступ к аргументам командной строки в C++

16.1 Пример консольного калькулятора на C++

17. Функции C++

18. Время и дата в C++

19. Файлы и потоки

20. Опции компилятора Опции g++

21. Вызов системных программ в C++

22. Структуры данных

23. Классы и объекты

24. Наследование

25. Перезагрузка

26. Обработка исключений

27. Пространства имён

28. Доступ к переменным окружения из программы C++

29.

30.

……….

……….

……….

 


Простой учебник С++ для начинающих

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

Для данных Основ С++ был выбран другой подход — в начале максимум кода и теория необходимая только для объяснения новых концепций в рассматриваемом коде; а далее, конечно, и сама теория.

Чтобы получить положительный эффект от данных Основ языка программирования С++, вам нужно разбираться в каждом фрагменте кода, компилировать и модифицировать его в соответствии с вашими идеями, иначе результат будет такой же, как и от большинства других книг по С++.

Для кого С++

C++ рассматривается как язык среднего уровня, так как он включает в себя комбинацию высокоуровневых и низкоуровневых языковых функций.

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

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

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

Настройка рабочего окружения C++

Компилятор C++ в Linux

Если вы используете Linux или UNIX, то весьма вероятно, что пакет GCC с компилятором уже установлен в вашей системе, тем не менее, вы можете проверить это командой:

g++ -v

Если у вас установлен пакет GCC, то будет выведено что-то вроде следующего:

Если компилятор C++ отсутствует, то вы сможете установить его из стандартных репозиториев.

В Debian, Kali Linux, Linux Mint, Ubuntu и их производных для этого выполните команду:

sudo apt install gcc

В Arch Linux, BlackArch и их производных выполните команду:

sudo pacman -S gcc

Компилятор C++ в Windows

Рассмотрим разные способы установки GCC в Windows.

IDE с компилятором C++

Имеется несколько способов установить компилятор C++ в Windows, но самым простым является использование интегрированной среды разработки с встроенным компилятором C++. Пример такой IDE это Code::Blocks — рекомендуется начать с неё. Подробности об установке и использовании Code::Blocks даны ниже.

Компилятор C++ в Cygwin

Cygwin — это отличное начало для знакомства с командной строкой Linux, подробнее смотрите в теме «Как начать знакомство с командами Linux: Cygwin».

Преимущество Cygwin не только в наличии разнообразных компиляторов C++, но и в том, что вы сможете полноценно запускать скомпилированные программы так, как будто бы вы находитесь в Linux!

Для добавления компилятора C++ при установке или обновлении Cygwin выберите для установки пакет «gcc-g++»:

Пример компиляции и запуска:

g++ profile.cpp
./a.exe

Обратите внимание на скриншот — как и Linux, терминал Cygwin по умолчанию использует кодировку UTF-8. В IDE Code::Blocks, которая рекомендована чуть выше, есть проблемы с кириллицей.

Компилятор C++ в MinGW

MinGW — это сокращение от "Minimalist GNU for Windows", является минималистичной средой разработки для нативных приложений Microsoft Windows.

Знакомство с MinGW даст вам много возможностей как разработчику, здесь же мы рассмотрим только один аспект — как установить компилятор C++ в Windows

Чтобы установить MinGW, перейдите на страницу загрузки MinGW. Разверните содержимое «MinGW Installation Manager (mingw-get)» и найдите и скачайте файл mingw-get-setup.exe:

Запустите установщик. В этом окне можно ничего не менять:

Дождитесь загрузки компонентов:

Установите метапакет «mingw32-gcc-g++-bin», при желании, вы можете установить другие метапакеты (наборы пакетов) или отдельные пакеты под ваши потребности:

Выберите пункт меню «Installation» → «Apply Changes»:

Дождитесь завершения скачивания и установки выбранных компонентов:

С помощью следующей команды вы можете проверить, что g++ доступен для использования:

C:\MinGW\bin\g++ -v

Чтобы каждый раз не указывать полный путь до g++, вы можете добавить в переменную окружения Windows путь « C:\MinGW\bin\».

IDE с поддержкой C++ для Linux и Windows

Code::Blocks — это IDE, интегрированная среда разработки, то есть редактор с подсветкой синтаксиса C++ кода и с другими функциями.

Code::Blocks является кроссплатформенный, работает на Linux и на Windows. Для Windows можно скачать Code::Blocks с интегрированным компилятором исходного кода C++.

Установка Code::Blocks в Windows

Перейдите на официальный сайт http://codeblocks.org/downloads/binaries и выберите версию codeblocks-*mingw-setup.exe:

Запустите скаченный установщик, оставьте выбранными все элементы:

Выберите компилятор и нажмите кнопку «Set as default»:

Установка Code::Blocks в Debian, Kali Linux, Linux Mint, Ubuntu и их производные:

sudo apt install codeblocks

Установка Code::Blocks в Arch Linux, BlackArch и их производные:

sudo pacman -S codeblocks

Как создать проект C++ в Code::Blocks

При запуске Code::Blocks спросит, настроить ли ассоциацию с файлами .cpp:

Нажмите кнопку «New file»:

Выберите «Project»:

Выберите «Console application»:

Нажмите «Next», также можете поставить галочку «Skip this page next time» (пропустить это окно в следующий раз):

Выберите язык C++:

Выберите имя проекта и папку, в которой будет создана подпапка с файлами проекта:

Здесь можно выбрать другой компилятор, а также папки для сохранения файлов отладки и релиза (это менять необязательно):

В панели инструментов «Менеджер проектов» найдите файл main.cpp и откройте его для редактирования исходного кода:

Отредактируйте код:

Для компиляции и запуска нажмите кнопку «Build and run» или клавишу F9:

Если компиляция завершится без ошибок, то приложение будет запущено в консоли.

Нечитаемые символы (кракозябры) программ на C++ в Windows

По умолчанию командная строка Windows не использует UTF-8, поэтому буквы отличные от английских будут отображаться как кракозябры:

Вы можете использовать Cygwin для решения этой проблемы или настроить терминал на использование UTF-8.

Компиляция и выполнение программы C++

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

Взглянем на простой код, который напечатает слова Hello World.

В любом текстовом редакторе создайте файл hello.cpp и скопируйте в него:

#include <iostream>
using namespace std;

// main() здесь начинается выполнение программы.
int main() {
	cout << "Hello World"; // печатает Hello World
	return 0;
}

Откройте командную строку и перейдите в каталог, где вы сохранили файл.

Введите

g++ hello.cpp

и нажмите Enter, чтобы скомпилировать ваш код. Если в вашем коде нет ошибок, командная строка переместит вас на следующую строку и сгенерирует исполняемый файл a.out.

Теперь введите

./a.out

для запуска вашей программы.

Вы сможете увидеть «Hello World», напечатанный на окне.

Структура программы на C++

Давайте посмотрим на различные части вышеупомянутой программы.

Язык C++ имеет множество стандартных библиотек, из которых мы можем использовать функции в наших программах. Чтобы получить доступ к этим функциям, нужно подключить библиотеку, которая её содержит. Это делается в заголовках. В данном случае заголовком является первая строка #include <iostream>. Как можно догадаться из названия iostream — Input/Output Stream, мы задействуем функции ввода и вывода. В данном случае нам это нужно для использования стандартного вывода в программе.

Пространства имён (namespace) группируют и отделяют различные функции. Для доступа к функции cout (выводит строку в стандартный вывод), нужно указать пространство имён, в котором она находится (std) а затем через два двоеточия саму функцию: std::cout. Строка using namespace std; позволяет обращаться к функциям без указания каждый раз пространства имён, в которой они находятся. То есть строку using namespace std; можно пропустить, но тогда наша программа должна выглядеть следующим образом:

#include <iostream>

// main() здесь начинается выполнение программы.
int main() {
	std::cout << "Hello World"; // печатает Hello World
	return 0;
}

Следующая строка «// main() здесь начинается выполнение программы.» это однострочный комментарий, доступный в C++. Однострочные комментарии начинаются с // и заканчиваются в конце строки.

Строка int main() является главной функцией, с которой начинается выполнение программы. Содержимое этой функции помещено в фигурные скобки. Обратите внимание, что вызов главной функции не требуется, она запускается автоматически при старте программы.

Следующая строка «cout << "Hello World";» заставляет сообщение «Hello World» отображаться на экране.

Следующая строка «return 0;» завершает функцию main() и заставляет её возвращать значение 0 вызывающему процессу.

Точки с запятой и блоки в C++

В C++ точка с запятой является разделителем операторов. То есть каждое отдельное утверждение должно заканчиваться точкой с запятой. Это указывает на конец одного логического объекта.

Например, ниже приведены три разных выражения:

x = y;
y = y + 1;
add(x, y);

Блок — это набор логически связанных операторов, которые заключены в открывающую и закрывающую скобки. Например:

{
   cout << "Hello World"; // печатает Hello World
   return 0;
}

C++ не распознает конец строки как терминатор. По этой причине не имеет значения, где вы помещаете оператор в строку. Например:

x = y;
y = y + 1;
add(x, y);

это то же самое, что и

x = y; y = y + 1; add(x, y);

Идентификаторы C++

Идентификатор C++ - это имя, используемое для идентификации переменной, функции, класса, модуля или любого другого пользовательского элемента. Идентификатор начинается с буквы от A до Z или от a до z или подчёркивания (_), за которым следуют ноль или более букв, подчёркиваний и цифр (от 0 до 9).

C++ не допускает использование знаков препинания, таких как @, $ и% в идентификаторах. C++ является регистрозависимым языком программирования. Таким образом, Manpower и manpower — это два разных идентификатора в C++.

Вот несколько примеров допустимых идентификаторов:

mial       zara    abc   move_name  a_123	MiAl
myname50   _temp   j     a23b9      retVal	HackWare

Пробелы в C++

Строка, содержащая только пробел, возможно, с комментарием, называется пустой строкой, и компилятор C++ полностью игнорирует её.

Пробел (белый пробел) — это термин, используемый в C++ для описания пробелов, вкладок, символов новой строки и комментариев. Пробелы отделяют одну часть оператора от другой и позволяют компилятору определить, где заканчивается один элемент в выражении, например int, и начинается следующий элемент.

Выражение:

int age;

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

Выражение 2:

fruit = apples + oranges;   // Получаем общее количество фруктов

В приведённом выше выражении 2 не обязательно вводить пробельные символы между fruit и = или между = и apples, хотя вы можете добавить пробелы, если хотите, чтобы строки кода были удобочитаемыми.

Комментарии в C++

Программные комментарии — это пояснительные выражения, которые вы можете включить в код C++. Эти комментарии помогут всем, кто читает исходный код. Все языки программирования допускают комментарии в той или иной форме.

C++ поддерживает однострочные и многострочные комментарии. Все символы, расположенные внутри любого комментария, игнорируются компилятором C++.

Комментарии в C++ начинаются с /* и заканчиваются на */. Например:

/* Это комментарий */

/* Комментарии C++ также могут
   * занимать несколько строк
*/

Комментарии также могут начинаться на //, они распространяют действие до конца строки. Например:

#include <iostream>
using namespace std;

main() {
	cout << "Hello World"; // печатает Hello World
   
	return 0;
}

Когда приведённый выше код скомпилирован, он игнорирует // печатает Hello World, и конечный исполняемый файл выдаст следующий результат:

Hello World

В комментариях /* и */ символы // не имеют особого значения. Внутри // комментария /* и */ не имеют особого значения. Таким образом, вы можете «вкладывать» один вид комментария в другой вид. Например:

/* Печать Hello World закомментирована:

cout << "Hello World"; // печатает Hello World

*/

Строки в C++

C++ обеспечивает следующие два типа строковых представлений:

  • Строки символов в стиле C
  • Класс string представленный со стандартным C++.

Строки символов в стиле C

Строка символов в стиле C возникла в языке C и продолжает поддерживаться в C++. Эта строка на самом деле является одномерным массивом символов, который заканчивается нулевым символом '\0'. Таким образом, строка с нулевым символом в конце содержит символы, которые составляют строку, за которой следует ноль.

Следующее объявление и инициализация создают строку, состоящую из слова «Hello». Чтобы содержать нулевой символ в конце массива, размер массива символов, содержащего строку, на один больше, чем количество символов в слове «Hello».

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

Если вы следуете правилу инициализации массива, вы можете написать приведённое выше утверждение следующим образом:

char greeting[] = "Hello";

Следующее представление памяти определённой выше строки в C/C++:

На самом деле, вы не помещаете нулевой символ в конец строковой константы. Компилятор C++ автоматически помещает '\0' в конец строки, когда инициализирует массив. Давайте попробуем напечатать вышеупомянутую строку:

#include <iostream>

using namespace std;

int main () {

	// любую переменную необходимо объявить указав её тип. 
	// В данном случае тип переменной char
	// Об объявлении переменных и их типов будет рассказано далее
	char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

	cout << "Приветственное сообщение: ";
	cout << greeting << endl;

	return 0;
}

Скомпилированный и выполненный код даст следующий результат:

Приветственное сообщение: Hello

C++ поддерживает широкий спектр функций, которые обрабатывают строки с нулевым символом в конце:

Функция Цель
strcpy(s1, s2);

Копирует строку s2 в строку s1.

strcat(s1, s2);

Добавляет строку s2 к концу строки s1.

strlen(s1);

Возвращает длину строки s1.

strcmp(s1, s2);

Возвращае 0 если s1 и s2 одинаковы; меньше, чем 0 если s1<s2; больше, чем 0 если s1>s2.

strchr(s1, ch);

Возвращает указатель на первое вхождение символа ch в строке s1.

strstr(s1, s2);

Возвращает указатель на первое вхождение строки s2 в строке s1.

Следующий пример использует несколько из вышеупомянутых функций:

#include <iostream>
#include <cstring>

using namespace std;

int main () {

	// объявление и инициализация переменных типов char и int
	char str1[10] = "Hello";
	char str2[10] = "World";
	char str3[10];
	int  len ;

	// копируем str1 в str3
	strcpy( str3, str1);
	cout << "strcpy( str3, str1) : " << str3 << endl;

	// объединяем str1 и str2
	strcat( str1, str2);
	cout << "strcat( str1, str2): " << str1 << endl;

	// итоговая длина str1 после объединения
	len = strlen(str1);
	cout << "strlen(str1) : " << len << endl;

	return 0;
}

Результат выполнения кода:

strcpy( str3, str1) : Hello
strcat( str1, str2): HelloWorld
strlen(str1) : 10

В самом коде обратите внимание, что с cout можно выводить несколько строк за один раз, например:

cout << "strlen(str1) : " << len << endl;

endl — означает конец строки (для перехода вывода к новой строке) — подробнее об endl и других функциях стандартного вывода будет чуть дальше.

Также обратите внимание на новый заголовок #include <cstring>, как можно догадаться, он необходим для использования функций строковых символов в стиле C.

Класс string в C++

Стандартная библиотека C++ предоставляет тип класса string, который поддерживает все операции, упомянутые выше, и, кроме того, гораздо больше функциональности. Давайте проверим следующий пример:

#include <iostream>
#include <string>

using namespace std;

int main () {

	// объявление переменных типов string и int
	string str1 = "Hello";
	string str2 = "World";
	string str3;
	int  len ;

	// Копируем str1 в str3
	str3 = str1;
	cout << "str3 : " << str3 << endl;

	// объединяем str1 и str2
	str3 = str1 + str2;
	cout << "str1 + str2 : " << str3 << endl;

	// итоговая длина str3 после объединения
	len = str3.size();
	cout << "str3.size() :  " << len << endl;

	return 0;
}

Результат работы скомпилированной программы:

str3 : Hello
str1 + str2 : HelloWorld
str3.size() :  10

В исходном коде программы обратите внимание на новый заголовок #include <string>, он нужен для работы с классом string.

Из справочной информации о классе string: https://en.cppreference.com/w/cpp/string/basic_string

оператор =

присваивает значения строке
(функция публичного члена)

assign

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

Элементы доступа

at

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

оператор []

доступ к указанному символу
(функция публичного члена)

front

(C++11)

доступ к первому символу
(функция публичного члена)

back

(C++11)

доступ к последнемму символу
(функция публичного члена)

data

возвращает указатель на первый символ строки
(функция публичного члена)

c_str

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

Вместимость

empty

проверяет, является ли строка пустой
(функция публичного члена)

size

length

возвращает количество символов
(функция публичного члена)

max_size

возвращает максимальное количество символов
(функция публичного члена)

reserve

резервирует хранилище
(функция публичного члена)

capacity

возвращает количество символов, которое может храниться в выделенном хранилище
(функция публичного члена)

Операции

clear

очищает содержимое
(функция публичного члена)

insert

вставляет символы
(функция публичного члена)

erase

удаляет символы
(функция публичного члена)

push_back

добавляет символ к концу
(функция публичного члена)

pop_back

(C++11)

удаляет последний символ
(функция публичного члена)

append

добавляет символы в конец
(функция публичного члена)

operator+=

добавляет символы в конец
(функция публичного члена)

compare

сравнивает две строки
(функция публичного члена)

starts_with

(C++20)

проверяет, начинается ли строка с данного префикса
(функция публичного члена)

ends_with

(C++20)

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

replace

заменяет указанную часть строки
(функция публичного члена)

substr

возвращает подстроку
(функция публичного члена)

copy

копирует символы
(функция публичного члена)

resize

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

swap

меняет содержимое двух строк между собой
(функция публичного члена)

Поиск

find

найти символы в строке
(функция публичного члена)

rfind

найти последнее вхождение подстроки
(функция публичного члена)

find_first_of

найти первое вхождение символов
(функция публичного члена)

find_first_not_of

найти первое отсутствие символов
(функция публичного члена)

find_last_of

найти последнее вхождение символов
(функция публичного члена)

find_last_not_of

найти последнее отсутствие символов
(функция публичного члена)

npos

[static]

специальное значение. Точное значение зависит от контекста
(константа открытого статического члена)

Функции, не являющиеся членами

оператор +

объединяет две строки или строку и символ
(шаблон функции)

оператор ==

оператор <=> (C++20)

лексикографически сравнивает две строки
(шаблон функции)
Input/output

оператор <<

оператор >>

выполняет потоковый ввод и вывод для строк
(шаблон функции)

getline

читать данные из потока ввода-вывода в строку
(шаблон функции)

Числовые преобразования

stoi

stol

stoll

преобразует строку в целое число со знаком
(функция)

stoul

stoull

преобразует строку в целое число без знака
(функция)

stof

stod

stold

преобразует строку в значение с плавающей запятой
(функция)

to_string

преобразует целое число или значение с плавающей запятой в строку
(функция)

to_wstring

преобразует целочисленное значение или значение с плавающей точкой в wstring
(функция)

Пример использования функции replace

Заменяет часть строки, обозначенную [pos, pos + count) или [first, last), новой строкой.

#include <iostream>
#include <string>

using namespace std;

int main()
{
	string str("The quick brown fox jumps over the lazy dog.");

	str.replace(10, 5, "red"); // начиная с 10 символа заменяется 5 символов на "red"

	str.replace(str.begin(), str.begin() + 3, 1, 'A'); // начиная с начала строки до +3 символов заменяется на один символ 'A'

	cout << str << '\n';
}

Вывод:

A quick red fox jumps over the lazy dog.

Обратите внимание, как используются функции — после объекта, над которым мы хотим сделать действие (в данном случае это строка), ставится точка, затем пишется название функции и круглые скобки. Если вы уже знакомы с объектно-ориентированным программированием, то вы уже должны быть знакомы с таким синтаксисом.

Пример использования функции substr

Возвращает подстроку [pos, pos+count). Если запрошенная подстрока выходит за конец строки, или если count == npos, то возвращаемая подстрока - [pos, size()).

#include <string>
#include <iostream>

using namespace std;

int main()
{
	string a = "0123456789abcdefghij";

	// count равен npos, значит возвращает [pos, size()). То есть вернёт с 10 символа до конца строки
	string sub1 = a.substr(10);
	cout << sub1 << '\n';

	// оба pos и pos+count внутри границ, вернёт [pos, pos+count), то есть вернёт 3 символа начиная с пятого
	string sub2 = a.substr(5, 3);
	cout << sub2 << '\n';

	// pos внутри границ, pos+count нет, вернёт [pos, size()), то есть от третьего с конца символа до конца строки
	string sub4 = a.substr(a.size()-3, 50);
	cout << sub4 << '\n';

	try {
		// pos за пределами границ, вызвать исключение
		string sub5 = a.substr(a.size()+3, 50);
		cout << sub5 << '\n';
	} catch(const std::out_of_range& e) {
		cout << "pos превышает длину строки\n";
	}
}

Выведет:

abcdefghij
567
hij
pos превышает длину строки

В данном коде использовался новый оператор try — catch, пока не обращайте на него внимания, он будет рассмотрен позже.

Пример использования функции swap

Обменивается содержимым строки с другой. Все итераторы и ссылки могут быть недействительными.

#include <string>
#include <iostream>

using namespace std;

int main()
{
	string a = "AAA";
	string b = "BBB";

	cout << "перед свапом" << '\n';
	cout << "a: " << a << '\n';
	cout << "b: " << b << '\n';

	a.swap(b); // обмен содержимом a и b

	cout << "после свапа" << '\n';
	cout << "a: " << a << '\n';
	cout << "b: " << b << '\n';
}

Выведет:

перед свапом
a: AAA
b: BBB
после свапа
a: BBB
b: AAA

Сравнение char со строкой в C++

Сравнение char со строкой в кавычках в C++

Как мы уже знаем, char может использоваться для хранения строк наравне с экземплярами класса string, которые также хранят строки. Но тип char, как мы только что рассмотрели, являются не совсем обычными строками и в некоторых ситуациях они ведут себя не совсем так, как мы интуитивно ожидаем. Рассмотрим следующий пример кода (инструкция if будет рассмотрена далее):

#include <iostream>
using namespace std;

int main () {
	char first_string[] = "sum";
	if (first_string == "sum") {
		cout << "Строки равны!" << endl;
	}
}

Интуитивно представляется, что должна быть выведена надпись «Строки равны!», но на практике этого не происходит, то есть условие first_string == "sum" является false.

Объяснение: в C строка — это указатель на область памяти, которая содержит байты. Сравнение char* с char* с использованием оператора равенства не будет работать должным образом, потому что вы сравниваете места в памяти строк, а не их байтовое содержимое.

Сравнение char и string в C++

Первый способ решения указанной проблемы сравнения char — это сравнивать её не со строкой в кавычках, а с экземпляром класса string, то есть переменной, являющейся string.

Следующий код отработает так, как ожидается:

#include <iostream>
#include <string>
using namespace std;

int main () {
	char first_string[] = "sum";
	string second_string = "sum";
	if (first_string == second_string) {
		cout << "Строки равны!" << endl;
	}
}

Будет выведено:

Строки равны!

Конвертация char и string в C++

При присвоении значения char переменной типа string, она конвертируется в string — при этом даже не нужно использовать специальные функции — это происходит автоматически. А переменные типа string ведут себя более интуитивно предсказуемо (так, как мы привыкли в других языках программирования), в следующем коде значение переменной char мы присваиваем строке и уже эту строку сравниваем с "sum":

#include <iostream>
#include <string>
using namespace std;

int main () {
	char first_string[] = "sum";
	string real_string = first_string;
	if (real_string == "sum") {
		cout << "Строки равны!" << endl;
	}
}

В результате будет выведено:

Строки равны!

Сравнение char в функции strcmp()

Функция strcmp() будет перебирать обе строки, проверяя их байты, чтобы увидеть, равны ли они. strcmp() вернёт 0, если они равны, и ненулевое значение, если они различаются.

Обратите внимание, что в следующем коде нам не нужно использовать заголовок #include <string>, но мы используем заголовок #include <cstring>, поскольку он содержит функцию strcmp:

#include <iostream>
#include <cstring>
using namespace std;

int main () {
	char first_string[] = "sum";
	if (strcmp(first_string, "sum") == 0) {
		cout << "Строки равны!" << endl;
	}
}

В результате будет выведено «Строки равны!».

Выводы

char нельзя непосредственно сравнивать со строкой в кавычках, поскольку это даст неправильный результат. char можно сравнивать с переменной типа string, либо присвоить значение переменной типа string и затем сравнить со строкой в кавычках, либо можно использовать функцию strcmp для сравнения char со строкой в кавычках.

Справочная информация по функциям C++

Последние примеры функций показали, что у функции может быть различное количество аргументов, классы могут содержать различные члены. То есть кроме синтаксиса языка, нужно знать, какие имеются классы и их содержимое. Информацию об этом можно найди в справочной документации по C++: https://en.cppreference.com.

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

Ещё один сайт со справочной информацией: http://www.cplusplus.com/reference

Основы ввода/вывода C++

Стандартные библиотеки C++ предоставляют обширный набор возможностей ввода/вывода, которые мы увидим в следующих главах. В этой главе будут обсуждаться самые основные и наиболее распространённые операции ввода-вывода, необходимые для программирования на C++.

C++ I/O происходит в потоках, которые представляют собой последовательности байтов. Если байты передаются из устройства, такие как клавиатура, диск, сетевое соединение и т. д., в основную память, это называется операцией ввода, и если байты передаются из основной памяти в устройство, такое как экран дисплея, принтер, диск или сетевое соединение и т. д., это называется операцией вывода.

Заголовочные файлы библиотеки ввода/вывода

Существуют следующие заголовочные файлы, важные для программ на C++:

Заголовочный файл Функция и описание
<iostream>

Этот файл определяет объекты cin, cout, cerr и clog, которые соответствуют стандартному входному потоку, стандартному выходному потоку, небуферизованному стандартному потоку ошибок и буферизованному стандартному потоку ошибок, соответственно.

<iomanip>

В этом файле объявляются службы, полезные для выполнения форматированного ввода-вывода с помощью так называемых параметризованных потоковых манипуляторов, таких как setw и setprecision.

<fstream>

Этот файл объявляет службы для управляемой пользователем обработки файлов. Мы обсудим это подробно в главе, связанной с файлами и потоками.

Стандартный поток вывода (cout)

Предопределённый объект cout является экземпляром класса ostream. Говорят, что объект cout «подключён» к стандартному устройству вывода, которым обычно является экран дисплея. Cout используется вместе с оператором вставки потока, который записывается как <<, то есть два знака меньше, как показано в следующем примере.

#include <iostream>

using namespace std;

int main() {
	char str[] = "Привет C++";

	cout << "Значением str является : " << str << endl;
} 

Результат выполнения кода:

Значением str является : Привет C++

Компилятор C++ также определяет тип данных переменной для вывода и выбирает соответствующий оператор вставки потока для отображения значения. Оператор << перегружается для вывода элементов данных встроенных типов integer, float, double, strings и значений указателей.

Оператор вставки << может использоваться более одного раза в одном выражении, как показано выше, а endl используется для добавления символа новой строки (new-line) в конце строки.

Стандартный входной поток (cin)

Предопределённый объект cin является экземпляром класса istream. Говорят, что объект cin прикреплён к стандартному устройству ввода, которым обычно является клавиатура. Cin используется вместе с оператором извлечения потока, который записывается как >>, то есть как два знака больше, как показано в следующем примере.

#include <iostream>
 
using namespace std;
 
int main() {
	char name[50];
 
	cout << "Пожалуйста, введите ваше имя: ";
	cin >> name;
	cout << "Ваше имя: " << name << endl;
 
}

Результат выполнения программы:

Компилятор C++ также определяет тип данных введённого значения и выбирает соответствующий оператор извлечения потока, чтобы извлечь значение и сохранить его в заданных переменных.

Оператор извлечения потока >> может использоваться более одного раза в одном выражении. Чтобы запросить более одного элемента данных, вы можете использовать следующее:

cin >> name >> age;

Это будет эквивалентно следующим двум выражениям:

cin >> name;
cin >> age;

Стандартный поток вывода ошибок (cerr)

Предопределённый объект cerr является экземпляром класса ostream. Считается, что объект cerr присоединён к стандартному устройству ошибок, которое также является экраном дисплея, но объект cerr не буферизован, и каждая вставка потока в cerr приводит к немедленному отображению его вывода.

cerr также используется в сочетании с оператором вставки потока, как показано в следующем примере.

#include <iostream>
 
using namespace std;
 
int main() {
	char str[] = "Не получилось прочитать....";
 
	cerr << "Сообщение об ошибке: " << str << endl;
}

После компиляции и выполнения этот код выведет следующее:

Сообщение об ошибке: Не получилось прочитать....

Стандартный поток журнала (clog)

Предопределённый объект clog является экземпляром класса ostream. Говорят, что объект clog прикреплён к стандартному устройству ошибки, которое также является экраном дисплея, но объект clog буферизуется. Это означает, что каждая вставка для clog может привести к тому, что её вывод будет храниться в буфере до тех пор, пока буфер не будет заполнен или пока буфер не будет очищен.

clog также используется вместе с оператором вставки потока, как показано в следующем примере.

#include <iostream>
 
using namespace std;
 
int main() {
	char str[] = "Не получилось прочитать....";
 
	clog << "Сообщение ошибки: " << str << endl;
}

Результат выполнения кода:

Сообщение ошибки: Не получилось прочитать....

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

Как ввести в cin строки с пробелами в С++

По умолчанию cin (стандартный ввод) в С++ считывает данные до первого пробела. Рассмотрим способы, с помощью которых мы можем передать через стандартный ввод строку, содержащую один или нескольких пробелов, чтобы эта строка могла быть присвоена в качестве значения переменной в программе.

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

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

#include <iostream>

using namespace std;

int main() {
	string line;

	cout << "Введите ваше имя: ";
	cin >> line;
	cout << "Ваше имя: " << line << endl;
}

Для запуска этого кода сохраните его в файл test.cpp и скомпилируйте:

g++ test.cpp

Запуск скомпилированного файла:

./a.out

Попробуем ввести строку с пробелами:

Как можно увидеть, из введённой строки «Алексей Милосердов», сохранилось только часть до пробела, то есть «Алексей».

Чтение строки с getline

getline читает символы из входного потока и помещает их в строку — именно это нам и нужно. getline (как и использование строки), требует указать заголовок #include <string>. Отредактируем наш код:

#include <iostream>
#include <string>

using namespace std;

int main() {
	string line;

	cout << "Введите ваше имя: ";
	getline(cin, line);
	cout << "Ваше имя: " << line << endl;

} 

Выполним проверку:

Как можно убедиться, теперь строка считалась полностью, вместе с пробелами.

Изменение поведения cin с помощью noskipws

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

cin >> noskipws >> line;

noskipws включает пропуск начальных пробелов с помощью форматированных функций ввода (по умолчанию включено). Не влияет на вывод.

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

Чтобы стало понятнее, рассмотрим следующий код:

#include <iostream>
#include <sstream>
using namespace std;

int main()
{
	char c1, c2, c3;
	istringstream("a b c") >> c1 >> c2 >> c3;
	cout << "Поведение по умолчанию: c1 = " << c1 << " c2 = " << c2 << " c3 = " << c3 << '\n';
	istringstream("a b c") >> noskipws >> c1 >> c2 >> c3;
	cout << "Поведение с noskipws: c1 = " << c1 << " c2 = " << c2 << " c3 = " << c3 << '\n';
}

В результате работы этого кода будет выведено:

Поведение по умолчанию: c1 = a c2 = b c3 = c
Поведение с noskipws: c1 = a c2 =   c3 = b

Примеры программа ввода данных — анкета

Пример программы на C++ использующий стандартный ввод и стандартный вывод.

Далее показан небольшой пример «анкеты», которая кроме стандартного ввода и стандартного вывода также использует некоторые функции класса string:

#include <iostream>
#include <string>

using namespace std;

int main () {

    string name;
    int  age;
    int  length;
    int found_num;

    cout << "Введите ваше имя: ";
    getline(cin, name); // getline читает символы из входного потока и помещает их в строку

    cout << "Введите ваш возраст: ";
    cin >> age;

    found_num = name.find("е");
    cout << "В имене символ \"е\" встречается в позиции: " << found_num << endl;

    length = name.length();
    name = "Ваше имя: " + name;  // оператор + объединяет строки

    cout << "Длина вашего имени: " << length << endl;
    cout << name << endl << "Ваш возраст: " << age << endl;

    return 0;
}

Результат выполнения:

Обратите внимание на неверно указанную длину — она в два раза больше, поскольку используется двухбайтная кодировка. Аналогично неправильно указана позиция символа «е» - указано как 4, поскольку каждая буква занимает 2 байта, а счёт начинается с нулевой позиции. То есть в имени «Алексей» буква «А» занимает байты 0 и 1, буква «л» занимает байты 2 и 3 и, соответственно, первый байт буквы «е» занимает четвёртую позицию.

С именем, записанным английскими буквами, длина и номер позиции символа будет указан верно. Обратите внимание, что если строка не найдена, то функция find возвращает -1

Типы переменных C++

Если вы знакомы с другими языками программирования, то вы могли сталкиваться в них с тем, что тип переменной (строка, число, логическое значение и т. д.) может меняться в зависимости от присваиваемого переменной значения и, следовательно, при объявлении или инициализации переменной не нужно указывать её тип.

В языке C++ тип переменный необходимо указывать во время её объявления или инициализации и в дальнейшем нельзя поменять тип переменной. То есть если переменной типа int (целое число) попытаться присвоить строку, то это завершится ошибкой.

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

Имя переменной может состоять из букв, цифр и символа подчёркивания. Он должен начинаться либо с буквы, либо с подчёркивания. Прописные и строчные буквы различны, потому что C++ чувствителен к регистру.

Существуют следующие основные типы переменных в C++:

Тип переменной Описание
bool

Логическое значение. Хранит либо значение true, либо false.

char

Символ. Обычно один октет (один байт). Это целочисленный тип.

int

Целове число. Наиболее натуральный размер целого числа для машины.

float

Число с плавающей точкой (дробное число). Значение с плавающей запятой одинарной точности.

double

Число с плавающей точкой и большим количеством знаков. Значение с плавающей запятой двойной точности.

void

Представляет отсутствие типа

wchar_t

Тип символов из 2 или 4 байтов.

C++ также позволяет определять различные другие типы переменных, которые мы рассмотрим в следующих главах, таких как перечисление (Enumeration), указатель (Pointer), массив (Array), ссылка (Reference), структуры данных и классы.

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

Определение переменной в C++

Определение переменной сообщает компилятору, где и сколько памяти нужно создать для переменной. Определение переменной определяет тип данных и содержит список из одной или нескольких переменных этого типа следующим образом:

ТИП СПИСОК_ПЕРЕМЕННЫХ;

Здесь ТИП должен быть допустимым типом данных C++, включая char, w_char, int, float, double, bool или любой определённый пользователем объект и т. д., а СПИСОК_ПЕРЕМЕННЫХ может состоять из одного или нескольких имён идентификаторов, разделённых запятыми. Некоторые действительные определения показаны здесь:

int i, j, k;
char c, ch;
float f, salary;
double d;

Строка int i, j, k; объявляет и определяет переменные i, j и k; который инструктирует компилятор создавать переменные с именами i, j и k типа int.

Переменные могут быть инициализированы (им присвоено начальное значение) в их объявлении. Инициализатор состоит из знака равенства, за которым следует постоянное выражение:

ТИП ИМЯ_ПЕРЕМЕННОЙ = ЗНАЧЕНИЕ;

Далее несколько примеров:

extern int d = 3, f = 5; // объявление d и f.
int d = 3, f = 5; // определение и инициализация d и f.
byte z = 22; // определение и инициализация z.
char x = 'x'; // переменная x имеет значение 'x'.

Для определения без инициализатора: переменные со статической продолжительностью хранения неявно инициализируются с помощью NULL (все байты имеют значение 0); начальное значение всех других переменных не определено.

Объявление переменных в C++

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

Объявление переменной полезно, когда вы используете несколько файлов и определяете свою переменную в одном из файлов, которые будут доступны во время компоновки программы. Вы будете использовать ключевое слово extern для объявления переменной в любом месте. Хотя вы можете объявлять переменную несколько раз в вашей C++ программе, но она может быть определена только один раз в файле, функции или блоке кода.

Пример

Попробуйте следующий пример, где переменная была объявлена вверху, но она была определена внутри основной функции:

#include <iostream>
using namespace std;

// Объявление переменных:
extern int a, b;
extern int c;
extern float f;
  
int main () {
	// Определение переменных:
	int a, b;
	int c;
	float f;
 
	// настоящая инициализация
	a = 10;
	b = 20;
	c = a + b;
 
	cout << c << endl ;

	f = 70.0/3.0;
	cout << f << endl ;
 
	return 0;
}

Результат выполнения:

30
23.3333

Функции мы рассмотрим позже, сейчас же просто отметим, что та же концепция применяется к объявлению функции, когда вы предоставляете имя функции во время её объявления, и её фактическое определение может быть дано где-либо ещё. Например:

// объявление функции
int func();
int main() {
   // вызов функции
   int i = func();
}

// определение функции
int func() {
   return 0;
}

Тип переменной string?

Вы могли обратить внимание, что выше мы использовали слово string в схожих с объявлением и инициализацией фрагментах кода:

	string str1 = "Hello";
	string str2 = "World";
	string str3;

На самом деле, тип переменных string не существует, а в этом коде мы создавали экземпляры класса string. Различные классы имеют различный набор членов, в том числе методов (операции, которые можно выполнять над классом), поэтому ряд действий можно выполнить только над объектом string (например, выполнить поиск по подстроке), но нельзя выполнить с переменной типа int. О классах, методах и других основах объектно-ориентированного программирования будет рассказано далее.

Lvalues и Rvalues

В C++ существует два вида выражений:

lvalue — выражения, которые ссылаются на ячейку памяти, называются выражением «lvalue». Lvalue может отображаться как левая или правая сторона задания.

rvalue — термин rvalue относится к значению данных, которое хранится по некоторому адресу в памяти. Значение r - это выражение, которому не может быть присвоено значение, что означает, что значение r может появляться в правой, но не в левой части назначения.

Переменные являются lvalue и могут отображаться в левой части назначения. Числовые литералы являются r-значениями, поэтому не могут быть назначены и не могут отображаться слева. Следующее является верным утверждением:

int g = 20;

Но следующее не является допустимым утверждением и приведёт к ошибке во время компиляции:

10 = 20;

Зарезервированные слова C++ (ключевые слова C++)

В следующем списке показаны зарезервированные слова в C++. Эти зарезервированные слова не могут использоваться как константы или переменные или любые другие имена идентификаторов.

asm else new this
auto enum operator throw
bool explicit private true
break export protected try
case extern public typedef
catch false register typeid
char float reinterpret_cast typename
class for return union
const friend short unsigned
const_cast goto signed using
continue if sizeof virtual
default inline static void
delete int static_cast volatile
do long struct wchar_t
double mutable switch while
dynamic_cast namespace template

Операторы в C++

Оператор — это символ, который указывает компилятору выполнять определённые математические или логические манипуляции. C++ богат встроенными операторами и предоставляет следующие типы операторов:

  • Арифметические операторы
  • Операторы отношений
  • Логические операторы
  • Битовые операторы
  • Операторы присваивания
  • Разные операторы

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

Арифметические Операторы

Существуют следующие арифметические операторы, поддерживаемые языком C++ (предположим, что переменная A содержит 10, а переменная B содержит 20, тогда):

Оператор Описание Пример
+ Складыавет два операнда A + B даст 30
- Вычитает второй операнд из первого A - B даст -10
* Перемножает оба операнда A * B даст 200
/ Делет числитель на знаменатель B / A даст 2
% Оператор модуля и остаток от целочисленного деления B % A даст 0
++ Оператор приращения, увеличивает целочисленное значение на единицу A++ даст 11
-- Оператор уменьшения, уменьшает целочисленное значение на единицу A-- даст 9

Попробуйте следующий пример, чтобы понять все арифметические операторы, доступные в C++.

Скопируйте и вставьте следующую программу C++ в файл arithmatic.cpp, скомпилируйте и запустите эту программу.

#include <iostream>
using namespace std;

int main() {
    int a = 21;
    int b = 10;
    int c ;

    cout << "Начальные значения:" << endl << "a = 21" << endl << "b = 10" << endl << endl ;

    c = a + b;
    cout << "Значение a + b равно: " << c << endl ;

    c = a - b;
    cout << "Значение a - b равно: " << c << endl;

    c = a * b;
    cout << "Значение a * b равно: " << c << endl ;

    c = a / b;
    cout << "Значение a / b равно: " << c << endl ;

    c = a % b;
    cout << "Значение a % b равно: " << c << endl ;

    a++;
    c = a;
    cout << "Значение a++ равно: " << c << endl ;

    a--;
    c = a;
    cout << "Значение a-- равно: " << c << endl ;

    return 0;
}  

Результат работы:

Начальные значения:
a = 21
b = 10

Значение a + b равно: 31
Значение a - b равно: 11
Значение a * b равно: 210
Значение a / b равно: 2
Значение a % b равно: 1
Значение a++ равно: 22
Значение a-- равно: 21

Операторы инкремента и декремента в C++

Оператор увеличения ++ добавляет 1 к своему операнду, а оператор уменьшения -- вычитает 1 из своего операнда. Таким образом:

x = x+1;

это то же самое, что и:

x++;

И аналогично:

x = x-1;

это то же самое, что и:

x--;

Операторы увеличения и уменьшения могут либо предшествовать (префикс), либо следовать (постфикс) операнда. Например:

x = x+1;

может быть записано как

++x; // префиксная форма

или как:

x++; // постфиксная форма

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

Пример

Ниже приведён пример, чтобы понять эту разницу.

Оператор увеличения ++ добавляет 1 к своему операнду, а оператор уменьшения -- вычитает 1 из своего операнда. Таким образом:


#include <iostream>
using namespace std;

int main() {
       int a = 21;
       int c ;

       cout << "Начальное значение: a = 21" << endl << endl;

       // Значение a не будет увеличено перед назначением c.
       c = a++;
       cout << "В c = a++ значение a++ равно: " << c << endl;

       // После предыдущего выражения значение a увеличено
       cout << "Значение a всё-таки равно: " << a << endl;

       // Значение a будет увеличено перед назначением
       c = ++a;
       cout << "Значение ++a равно: " << c << endl;
       return 0;
}

Результат работы программы:

Начальное значение: a = 21

В c = a++ значение a++ равно: 21
Значение a всё-таки равно: 22
Значение ++a равно: 23

Операторы отношений

В языке C++ поддерживаются следующие реляционные операторы (предположим, что переменная A равна 10, а переменная B равна 20, тогда):

Оператор Описание Пример
== Проверяет, равны ли значения двух операндов или нет, если да, тогда условие становится истинным. (A == B) не истина.
!= Проверяет, равны ли значения двух операндов или нет, если значения не равны, тогда условие становится истинным. (A != B) является истиной.
> Проверяет, больше ли значение левого операнда, чем значение правого операнда, если да, тогда условие становится истинным. (A > B) не истина.
< Проверяет, меньше ли значение левого операнда, чем значение правого операнда, если да, тогда условие становится истинным. (A < B) является истиной.
>= Проверяет, больше ли значение левого операнда или равно значению правого операнда, если да, тогда условие становится истинным. (A >= B) не истина.
<= Проверяет, меньше ли значение левого операнда или равно значению правого операнда, если да, тогда условие становится истинным. (A <= B) является истиной.

Попробуйте следующий пример, чтобы понять все реляционные операторы, доступные в C++.

Скопируйте и вставьте следующую программу C++ в файл test.cpp, скомпилируйте и запустите эту программу.

#include <iostream>
using namespace std;

int main() {
	int a = 21;
	int b = 10;

	cout << "Начальное значение a = 21, значание b = 10" << endl;

	if( a == b ) {
		cout << "1: a равно b" << endl;
	} else {
		cout << "1: a не равно b" << endl;
	}

	if( a < b ) {
		cout << "2: a меньше, чем b" << endl;
	} else {
		cout << "2: a не меньше, чем b" << endl;
	}

	if( a > b ) {
		cout << "3: a больше, чем b" << endl;
	} else {
		cout << "3: a не больше, чем b" << endl;
	}

	/* Let's change the values of a and b */
	a = 5;
	b = 20;

	cout << endl << "Новые значения a = 5, b = 20" << endl;

	if( a <= b ) {
		cout << "4: a либо меньше, либо равно  b" << endl;
	}

	if( b >= a ) {
		cout << "5: b больше или равно a" << endl;
	}

	return 0;
} 

Результат выполнения:

1: a не равно b
2: a не меньше, чем b
3: a больше, чем b

Новые значения a = 5, b = 20
4: a либо меньше, либо равно  b
5: b больше или равно a

Логические Операторы

В языке C++ поддерживаются следующие логические операторы (предположим, что переменная A равна 1, а переменная B равна 0, тогда):

Оператор Описание Пример
&& Называется логический оператор И. Если оба операнда отличны от нуля, условие становится истинным. (A && B) это ложь.
|| Вызывается логическим оператором ИЛИ. Если любой из двух операндов отличен от нуля, условие становится истинным. (A || B) это истина.
! Вызывается логическим оператором НЕ. Используйте для изменения логического состояния своего операнда. Если условие истинно, то он станет ложью и наоборот. !(A && B) это истина.

Попробуйте следующий пример, чтобы понять все логические операторы, доступные в C++.

Скопируйте и вставьте следующую программу C++ в файл test.cpp, скомпилируйте и запустите эту программу.

#include <iostream>
using namespace std;

int main() {
	int a = 5;
	int b = 20;

        cout << "Начальные значения a = 5 и b = 20" << endl;

	if(a && b) {
		cout << "a && b: условие истино" << endl;
	}

	if(a || b) {
		cout << "a || b: условие истино" << endl;
	}

	/* Давайте поменяем значения a и b */
	a = 0;
	b = 10;

        cout << endl << "Новые значения a = 0 и b = 10" << endl;

	if(a && b) {
		cout << "a && b: условие истино" << endl;
	} else {
		cout << "a && b: условие не истино" << endl;
	}

	if(!(a && b)) {
		cout << "!(a && b): условие истино" << endl;
	}

	return 0;
}

Результат выполнения:

Начальные значения a = 5 и b = 20
a && b: условие истино
a || b: условие истино

Новые значения a = 0 и b = 10
a && b: условие не истино
!(a && b): условие истино

Битовые операторы

Побитовый оператор работает с битами и выполняет побитовую операцию. Таблицы истинности для &, | и ^ следующие:

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

Предположим, если А = 60; и B = 13; теперь в двоичном формате они будут выглядеть следующим образом -

A = 0011 1100

B = 0000 1101

-----------------

A & B = 0000 1100

A | B = 0011 1101

A ^ B = 0011 0001

~ A = 1100 0011

Побитовые операторы, поддерживаемые языком C++, перечислены в следующей таблице. Предположим, что переменная A содержит 60, а переменная B содержит 13, тогда:

Оператор Описание Пример
& Двоичный оператор AND копирует результат бита, если он существует в обоих операндах. (A & B) даст 12 что является 0000 1100
| Оператор двоичного OR копирует бит, если он существует в любом из операндов. (A | B) даст 61 что является 0011 1101
^ Двоичный оператор XOR копирует бит, если он установлен в одном операнде, но не в обоих. (A ^ B) даст 49 что является 0011 0001
~ Оператор дополнения двоичных единиц является унарным и имеет эффект «переворачивания» битов. (~A )даст -61 что является 1100 0011 в форме дополнения 2 из-за двоичного числа со знаком.
<< Двоичный оператор левого сдвига. Значение левого операнда перемещается влево на количество битов, указанное правым операндом. A << 2 даст 240 что является 1111 0000
>> Оператор двоичного правого сдвига. Значение левого операнда перемещается вправо на количество битов, указанное правым операндом. A >> 2 даст 15 что является 0000 1111

Попробуйте следующий пример, чтобы понять все побитовые операторы, доступные в C++.

Скопируйте и вставьте следующую программу C++ в файл test.cpp, скомпилируйте и запустите эту программу.

#include <iostream>
using namespace std;

int main() {
	unsigned int a = 60;	  // 60 = 0011 1100
	unsigned int b = 13;	  // 13 = 0000 1101
	int c = 0;

	cout << "Начальные значения: " << endl << "a = 60 (0011 1100)" << endl << "b = 13 (0000 1101)" << endl << endl;
	c = a & b;             // 12 = 0000 1100
	cout << "значение a & b равно: " << c << endl;

	c = a | b;             // 61 = 0011 1101
	cout << "значение a | b равно: " << c << endl;

	c = a ^ b;             // 49 = 0011 0001
	cout << "значение a ^ b равно: " << c << endl;

	c = ~a;                // -61 = 1100 0011
	cout << "значение ~a равно: " << c << endl;

	c = a << 2;            // 240 = 1111 0000
	cout << "значение a << 2 равно: " << c << endl;

	c = a >> 2;            // 15 = 0000 1111
	cout << "значение a >> 2 равно: " << c << endl;

	return 0;
}

Результат выполнения:

Начальные значения: 
a = 60 (0011 1100)
b = 13 (0000 1101)

значение a & b равно: 12
значение a | b равно: 61
значение a ^ b равно: 49
значение ~a равно: -61
значение a << 2 равно: 240
значение a >> 2 равно: 15

Операторы присваивания

В языке C++ поддерживаются следующие операторы присваивания:

Оператор Описание Пример
= Простой оператор присваивания, присваивает значения от правых операндов к левому операнду. C = A + B назначит значение A + B в C
+= Оператор добавления И присваивания, он добавляет правый операнд к левому операнду и присваивает результат левому операнду. C += A эквивалентно C = C + A
-= Оператор вычитания И присваивания, вычитает правый операнд из левого операнда и присваивает результат левому операнду. C -= A эквивалентно C = C - A
*= Оператор умножения И присвоения, умножает правый операнд на левый операнд и присваивает результат левому операнду. C *= A эквивалентно C = C * A
/= Оператор деления И присваивания, делит левый операнд на правый операнд и присваивает результат левому операнду. C /= A эквивалентно C = C / A
%= Модуль И оператор присваивания. Он принимает модуль с использованием двух операндов и присваивает результат левому операнду. C %= A эквивалентно C = C% A
<<= Левый сдвиг И оператор присваивания. C <<= 2 то же самое, что и C = C << 2
>>= Сдвиг вправо И оператор присваивания. C >>= 2 то же самое, что и C = C >> 2
&= Побитовое И оператор присваивания. C &= 2 то же самое, что и C = C & 2
^= Побитовое исключающее ИЛИ и оператор присваивания. C ^= 2 то же самое, что и C = C ^ 2
|= Побитовое ИЛИ и оператор присваивания. C |= 2 то же самое, что и C = C | 2

Попробуйте следующий пример, чтобы понять все операторы присваивания, доступные в C++.

Скопируйте и вставьте следующую программу C++ в файл test.cpp, скомпилируйте и запустите эту программу.

#include <iostream>
using namespace std;

int main() {
	int a = 21;
	int c ;

	cout << "Начальное значение a = 21" << endl << endl;

	c = a;
	cout << "1. Оператор c = a. Значение c = " << c << endl;

	c += a;
	cout << "2. Оператор c += a. Значение c = " << c << endl;

	c -= a;
	cout << "3. Оператор c -= a. Значение c = " << c << endl;

	c *= a;
	cout << "4. Оператор c *= a. Значение c = " << c << endl;

	c /= a;
	cout << "5. Оператор c /= a. Значение c = " << c << endl;

	c = 200;
	cout << endl << "Теперь c = 200" << endl << endl;

	c %= a;
	cout << "6. Оператор c %= a. Значение c = " << c << endl;

	c <<= 2;
	cout << "7. Оператор c <<= 2. Значение c = " << c << endl;

	c >>= 2;
	cout << "8. Оператор c >>= 2. Значение c = " << c << endl;

	c &= 2;
	cout << "9. Оператор c &= 2. Значение c = " << c << endl;

	c ^= 2;
	cout << "10. Оператор c ^= 2. Значение c = " << c << endl;

	c |= 2;
	cout << "11. Оператор c |= 2. Значение c = " << c << endl;

	return 0;
}

Результат выполнения:

Начальное значение a = 21

1. Оператор c = a. Значение c = 21
2. Оператор c += a. Значение c = 42
3. Оператор c -= a. Значение c = 21
4. Оператор c *= a. Значение c = 441
5. Оператор c /= a. Значение c = 21

Теперь c = 200

6. Оператор c %= a. Значение c = 11
7. Оператор c <<= 2. Значение c = 44
8. Оператор c >>= 2. Значение c = 11
9. Оператор c &= 2. Значение c = 2
10. Оператор c ^= 2. Значение c = 0
11. Оператор c |= 2. Значение c = 2

Разные операторы

В следующей таблице перечислены некоторые другие операторы, которые поддерживает C++.

Оператор Описание
sizeof

оператор sizeof возвращает размер переменной. Например, sizeof(a), где «a» - целое число, и возвращает 4.

УСЛОВИЕ ? X : Y

Условный оператор (?). Если УСЛОВИЕ истинно, то он возвращает значение X, в противном случае возвращает значение Y.

,

Оператор запятая вызывает выполнение последовательности операций. Значение всего выражения запятой является значением последнего выражения списка, разделенного запятыми.

. (точка) и -> (стрела)

Операторы-члены используются для ссылки на отдельных членов классов, структур и объединений.

Кастинг

Операторы приведения преобразуют один тип данных в другой. Например, int(2.2000) вернет 2.

&

Оператор указателя & возвращает адрес переменной. Например, &a; даст фактический адрес переменной.

*

Оператор указателя * является указателем на переменную. Например *var; будет указателем на переменную var.

Приоритет операторов в C++

Приоритет оператора определяет группировку различных действий в выражении. Это влияет на то, в каком порядке выполняются действия в выражении. Некоторые операторы имеют более высокий приоритет, чем другие; например, оператор умножения имеет более высокий приоритет, чем оператор сложения.

Например, х = 7 + 3 * 2; здесь x будет присвоено 13, а не 20, потому что оператор * имеет более высокий приоритет, чем +, поэтому он сначала умножается на 3 * 2, а затем прибавляется к 7.

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

Категория  Оператор  Ассоциативность 
Постфикс  () [] -> . ++ - -   Слева направо
Одинарные  + - ! ~ ++ - - (type)* & sizeof  Справа налево
Мультипликативные   * / %  Слева направо
Аддикативные   + -  Слева направо
Смещение   << >>  Слева направо
Отношения   < <= > >=  Слева направо
Равенство   == !=  Слева направо
Побитовое AND  Слева направо
Побитовое XOR  Слева направо
Побитовое OR  Слева направо
Логическое AND  &&  Слева направо
Логическое OR  ||  Слева направо
Условие  ?:  Справа налево
Присваивание  = += -= *= /= %=>>= <<= &= ^= |=  Справа налево
Запятая  Слева направо

Попробуйте следующий пример, чтобы понять концепцию приоритета операторов, доступную в C++. Скопируйте и вставьте следующую программу C++ в файл test.cpp, скомпилируйте и запустите эту программу.

Проверьте простую разницу с и без скобок. Это даст разные результаты, потому что (), /, * и + имеют разный приоритет. Операторы с более высоким приоритетом будут вычисляться первыми.

#include <iostream>
using namespace std;

int main() {
	int a = 20;
	int b = 10;
	int c = 15;
	int d = 5;
	int e;

	cout << "Начальные значения:" << endl;
	cout << "a = 20" << endl;
	cout << "b = 10" << endl;
	cout << "c = 15" << endl;
	cout << "d = 5" << endl << endl;

	e = (a + b) * c / d;      // ( 30 * 15 ) / 5
	cout << "Значение (a + b) * c / d равно: " << e << endl;

	e = ((a + b) * c) / d;    // (30 * 15 ) / 5
	 cout << "Значение ((a + b) * c) / d равно: " << e << endl;

	 e = (a + b) * (c / d);   // (30) * (15/5)
	 cout << "Значение (a + b) * (c / d) равно: " << e << endl;

	e = a + (b * c) / d;     //  20 + (150/5)
	cout << "Значение (a + (b * c) / d равно: " << e << endl;

	return 0;
}

Результат выполнения:

Начальные значения:
a = 20
b = 10
c = 15
d = 5

Значение (a + b) * c / d равно: 90
Значение ((a + b) * c) / d равно: 90
Значение (a + b) * (c / d) равно: 90
Значение (a + (b * c) / d равно: 50

Математические операции C++

Мы уже изучили числа (int, short, long, float и double) и арифметические операции в C++. Теперь расширим наши знания математическими функциями языка C++.

Диапазоны и точность чисел в C++

Типы данных:

Тип Минимальный размер Примечание
short 2 байта  
int 2 байта Обычно 4 байта на современных архитектурах
long 4 байта  
long long 8 байт Тип C99/C++11

Диапазоны целых знаковых чисел:

Размер/тип Диапазон
1 байт со знаком от -128 до 127
2 байт со знаком от -32,768 до 32,767
4 байт со знаком от -2,147,483,648 до 2,147,483,647
8 байт со знаком от -9,223,372,036,854,775,808 до 9,223,372,036,854,775,807

Типы данных:

Категория Тип Минимальный размер Типичный размер
floating point float 4 байта 4 байта
  double 8 байт 8 байт
  long double 8 байт 8, 12 или 16 байт

Диапазоны чисел с плавающей точкой:

Размер Диапазон Точность
4 байта от ±1.18 x 10-38 до ±3.4 x 1038 6-9 значимых цифр, обычно 7
8 байт от ±2.23 x 10-308 до ±1.80 x 10308 15-18 значимых цифр, обычно 16
80-бит (обычно использует 12 или 16 байт) от ±3.36 x 10-4932 до ±1.18 x 104932 18-21 значимых цифр
16 байт от ±3.36 x 10-4932 до ±1.18 x 104932 33-36 значимых цифр

Почему в C++ для double в числе только 5 цифр после запятой

К примеру, переменная с типом данных float — это число с плавающей точкой, для хранения которого используется 4 байта, а это 6-9 значимых цифр, обычно 7.

А переменная с типом данных double — это число с плавающей точкой, для хранения которого используется 8 байт, а это примерно 15-18 значимых цифр, обычно 16.

Зная это, рассмотрим следующий простейший код — для его выполнения, сохраните код в файл test.cpp:

#include <iostream>
using namespace std;

int main () {
   // определение чисел:
   short  s;
   int    i;
   long   l;
   float  f;
   double d;

   // присвоение значений числам;
   s = 10;
   i = 1000;
   l = 1000000;
   f = 230.4732;
   d = 30949.12345678;

   // печать чисел;
   cout << "short  s :" << s << endl;
   cout << "int    i :" << i << endl;
   cout << "long   l :" << l << endl;
   cout << "float  f :" << f << endl;
   cout << "double d :" << d << endl;

   return 0;
}

Теперь скомпилируйте его:

g++ test.cpp

И выполните:

./a.out

Результат выполнения очень необычен:

short  s :10
int    i :1000
long   l :1000000
float  f :230.473
double d :30949.1

Число 230.4732 обрезано до 230.473 — потерян одна цифра после запятой. А в числе типа double, значение которого 30949.12345678, обрезалось до 30949.1 — то есть вместо предполагаемых 15-18 значимых цифр получено только 6…

Отсюда возникает вопрос, почему в числе типа double можно использовать только 6 значимых цифр?

На самом деле, число double d содержит все цифры после запятой, которые присвоены этой переменной — всё дело в том, как выполняется проверка числа. У метода cout имеются свои настройки по умолчанию для вывода и форматирования чисел — если в числе больше 6 разрядов, то обрезаются цифры после запятой, если до запятой также больше 6 цифр, то используется научная запись числа, например 1.23457e+14.

Такое поведение по умолчанию cout можно исправить. Для этого, во-первых, необходимо добавить новый заголовок #include <iomanip>.

Во-вторых нужно использовать std::setprecision(n), где n — это новая величина точности.

При использовании в выражении out << setprecision(n) или in >> setprecision(n) устанавливает для параметра точности потока out или in значение ровное n.

Отредактирует код нашей программы:

#include <iostream>
#include <iomanip>
using namespace std;

int main () {
   // определение чисел:
   short  s;
   int    i;
   long   l;
   float  f;
   double d;

   // присвоение значений числам;
   s = 10;
   i = 1000;
   l = 1000000;
   f = 230.4732;
   d = 30949.12345678;

   // печать чисел;
   cout << "short  s :" << s << endl;
   cout << "int    i :" << i << endl;
   cout << "long   l :" << l << endl;
   cout << setprecision(7) << "float  f :" << f << endl;
   cout << setprecision(13) << "double d :" << d << endl;

   return 0;
}

Заново скомпилируем и выполним его. Результат:

short  s :10
int    i :1000
long   l :1000000
float  f :230.4732
double d :30949.12345678

Именно этот результат мы и ожидали:

Отметим ещё раз — в самой программе используются все возможные знаки и разряды чисел, цифры обрезались в момент вывода (источник).

Математические функции в C++

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

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

Базовые операции

abs(float)

fabsf

absf

fabsl

абсолютное значение с плавающей запятой (|x|)

fmod

fmodf

fmodl

остаток от операции деления с плавающей запятой

remainder

remainderf

remainderl

остаток операции деления со знаком

remquo

remquof

remquol

остаток со знаком, а также три последних бита операции деления

fma

fmaf

fmal

операция умножения-сложения

fmax

fmaxf

fmaxl

большее из двух значений с плавающей точкой

fmin

fminf

fminl

меньшее из двух значений с плавающей точкой

fdim

fdimf

fdiml

положительная разница двух значений с плавающей точкой (max(0,x−y))

nannanfnanl

не-число (NaN)

Линейная интерполяция

lerp

функция линейной интерполяции

Экспоненциальные функции

exp

expf

expl

возвращает e, возведенный в данную степень (ex)

exp2

exp2f

exp2l

возвращает 2, возведенные в заданную степень (2x)

expm1

expm1f

expm1l

возвращает е, возведенное в данную степень, минус один (ex−1)

log

logf

logl

вычисляет натуральный (основание е) логарифм (ln x)

log10

log10f

log10l

вычисляет общий (основание 10) логарифм (log10x)

log2

log2f

log2l

логарифм с основанием 2 данного числа (log2x)

log1p

log1pf

log1pl

натуральный логарифм (к основанию е) 1 плюс заданное число (ln(1+x))

Функции возведения в степень

pow

powf

powl

возводит число в заданную степень (xy)

sqrt

sqrtf

sqrtl

вычисляет квадратный корень (√x)

cbrt

cbrtf

cbrtl

вычисляет кубический корень (3√x)

hypot

hypotf

hypotl

вычисляет квадратный корень из суммы квадратов двух заданных чисел (√x2+y2)

Тригонометрические функции

sin

sinf

sinl

вычисляет синус (sin x)

cos

cosf

cosl

вычисляет косинус (cos x)

tan

tanf

tanl

вычисляет тангенс (tan x)

asin

asinf

asinl

вычисляет арксинус (arcsin x)

acos

acosf

acosl

вычисляет арккосинус (arccos x)

atan

atanf

atanl

вычисляет арктангенс (arctan x)

atan2

atan2f

atan2l

арктангенс, используя знаки для определения квадрантов

Операции округления с плавающей точкой

ceil

ceilf

ceill

ближайшее целое число не меньше заданного значения

floor

floorf

floorl

ближайшее целое число не больше заданного значения

Чтобы использовать эти функции, вам нужно включить файл математического заголовка <cmath>.

Ниже приведён простой пример, демонстрирующий несколько математических операций:

#include <iostream>
#include <cmath>
using namespace std;

int main () {
	// определение чисел:
	short  s = 10;
	int    i = -1000;
	long   l = 100000;
	float  f = 230.47;
	double d = 200.374;

	// математические операции;
	cout << "sin(d) :" << sin(d) << endl;
	cout << "abs(i)  :" << abs(i) << endl;
	cout << "floor(d) :" << floor(d) << endl;
	cout << "sqrt(f) :" << sqrt(f) << endl;
	cout << "pow( d, 2) :" << pow(d, 2) << endl;

	return 0;
}

Результат выполнения:

sin(d) :-0.634939
abs(i)  :1000
floor(d) :200
sqrt(f) :15.1812
pow( d, 2) :40149.7

Случайные числа в C++

Есть много случаев, когда вы захотите сгенерировать случайное число. На самом деле есть две функции, которые вам нужно знать о генерации случайных чисел. Первый — rand(), эта функция будет возвращать только псевдослучайное число. Способ исправить это — сначала вызвать функцию srand().

Ниже приведён простой пример генерации нескольких случайных чисел. В этом примере функция time() используется для получения количества секунд вашего системного времени и случайного заполнения функции rand().

Для функций rand() и srand() используется новый заголовок <cstdlib>.

Для функции time() используется новый заголовок <ctime>.

В приведённом коде используется ещё незнакомый оператор for, он будет рассмотрен позже:

#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;

int main () {
	int i,j;

	// устанавливаем сид (источник для случайного числа)
	srand( (unsigned)time( NULL ) );

	/* генерируем 10 случайных чисел. */
	for( i = 0; i < 10; i++ ) {
		// непосредственно операция создания случайного числа
		j = rand();
		cout <<"Случайное число: " << j << endl;
	}

	return 0;
}

Результат выполнения:

Случайное число: 1468431111
Случайное число: 1609318277
Случайное число: 1367788215
Случайное число: 1643790991
Случайное число: 1373267050
Случайное число: 1161991869
Случайное число: 977096179
Случайное число: 1989640887
Случайное число: 1877448243
Случайное число: 2115657605

Операторы принятия решений в C++ (if, if…else, switch)

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

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

Инструкция if в C++

Оператор if состоит из логического выражения, за которым следует одно или несколько операторов. Синтаксис оператора if в C++:

if(ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ) {
	// оператор(ы) для выполнения если ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ истино
}

Если ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ имеет значение true, тогда будет выполнен блок кода внутри оператора if. Если логическое выражение имеет значение false, то будет выполнен первый набор кода после конца оператора if (после закрывающей фигурной скобки).

Схема потока:

Пример кода:

#include <iostream>
using namespace std;

int main () {
	// объявление локальной переменной:
	int a = 10;

	// проверка логического улосвия
	if( a < 20 ) {
		// если условие истино, то будет напечатано следующее
		cout << "a меньше, чем 20;" << endl;
	}
	cout << "значение a равно: " << a << endl;

	return 0;
}

Результат его работы:

a меньше, чем 20;
значение a равно: 10

Инструкция if…else в C++

За оператором if может следовать необязательный оператор else, который выполняется, когда логическое выражение имеет значение false.

Синтаксис оператора if … else в C++:

if(ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ) {
	// код, который будет выполнен, если ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ истинно
} else {
	// код, который будет выполнен, если ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ ложно
}

Если ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ имеет значение true, тогда будет выполнен блок if, в противном случае будет выполнен блок кода.

Схема потока:

Пример кода:

#include <iostream>
using namespace std;

int main () {
	// объявление локальной переменной:
	int a = 100;

	// проверка значения логического выражения
	if( a < 20 ) {
		// если условие истино, то будет напечатано следующее
		cout << "a меньше, чем 20;" << endl;
	} else {
		// а если условие ложно, то будет напечатано следующее
		cout << "a не меньше, чем 20;" << endl;
	}
	cout << "значение a равно: " << a << endl;

	return 0;
}

Результат его работы:

a не меньше, чем 20;
значение a равно: 100

Инструкция if…else if…else

За оператором if может следовать необязательный оператор else if … else, который очень полезен для проверки различных условий, используя единственный оператор if … else if.

При использовании операторов if…else if…else необходимо учитывать несколько моментов:

  • У if может быть ноль или одна else, и она должен идти после любого другого if.
  • if может иметь от нуля до большого количества else if, и они должны предшествовать else.
  • Если логическое выражение в else if истино, ни один из оставшихся else if не будет проверен.

Синтаксис оператора if … else if … else в C++:

if(ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ 1) {
	// Выполняется, если ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ 1 является истиной
} else if(ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ 2) {
	// Выполняется, если ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ 2 является истиной
} else if(ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ 3) {
	// Выполняется, если ЛОГИЧЕСКОЕ_ВЫРАЖЕНИЕ 3 является истиной
} else {
	// выполняется, когда ни одно из условий выше не является истиной.
}

Пример кода:

#include <iostream>
using namespace std;

int main () {
	// объявление локальной переменной:
	int a = 100;

	// проверка условия логического выражения
	if( a == 10 ) {
		// если условие истино, тогда напечатать следующее
		cout << "Значение a равно 10" << endl;
	} else if( a == 20 ) {
		// если предыдущее условие не истино, но истино это, то напечатать следующее
		cout << "Значение a равно 20" << endl;
	} else if( a == 30 ) {
		// если предыдущие условия не истины, но истино это, то напечатать следующее
		cout << "Значение a равно 30" << endl;
	} else {
		// если ни одно из условий выше не истино
		cout << "Значение a не совпало ни с одним условием" << endl;
	}
	cout << "Точное значение a равно: " << a << endl;

	return 0;
}

Результат выполнения:

Значение a не совпало ни с одним условием
Точное значение a равно: 100

Инструкция switch в C++

Инструкция switch позволяет проверять переменную на соответствие списку значений. Каждое значение называется case, переменная проверяется для каждого case.

Синтаксис для инструкции switch в C++ следующий:

switch(ВЫРАЖЕНИЕ) {
   case ПОСТОЯННОЕ_ВЫРАЖЕНИЕ:
      КОД ДЛЯ ВЫПОЛНЕНИЯ;
      break; // необязательно
   case ПОСТОЯННОЕ_ВЫРАЖЕНИЕ:
      КОД ДЛЯ ВЫПОЛНЕНИЯ;
      break; // необязательно
  
   // можно иметь любое количество инструкций case.
   default : // необязательно
      КОД ДЛЯ ВЫПОЛНЕНИЯ;
}

Следующие правила применяются к инструкции switch:

  • ВЫРАЖЕНИЕ, используемое в инструкции switch, должно иметь целочисленный или перечислимый тип или быть типом класса, в котором класс имеет единственную функцию преобразования в целочисленный или перечислимый тип.
  • Вы можете иметь любое количество операторов case внутри switch. За каждым case следует значение для сравнения и двоеточие.
  • ПОСТОЯННОЕ_ВЫРАЖЕНИЕ для case должно быть того же типа, что и переменная в switch, и оно должно быть константой или литералом.
  • Когда включаемая переменная равна case, операторы, следующие за этим case, будут выполняться до тех пор, пока не будет достигнут оператор break.
  • При достижении оператора break, switch завершается, и поток управления переходит к следующей строке, следующей за оператором switch.
  • Не каждый case обязан содержать break. Если break не появляется, поток управления переходит к последующим case, пока не будет достигнут break.
  • Оператор switch может иметь необязательный default case, который должен находиться в конце switch. default case можно использовать для выполнения задачи, если ни один из case не является истинным. В default case не требуется break.

Схема потока:

Пример кода:

#include <iostream>
using namespace std;

int main () {
	// Объявление локальной переменной:
	char grade = 'D';

	switch(grade) {
	case 'A' :
		cout << "Превосходно!" << endl;
		break;
	case 'B' :
	case 'C' :
		cout << "Нелохо" << endl;
		break;
	case 'D' :
		cout << "Вы прошли" << endl;
		break;
	case 'F' :
		cout << "Лучше попробовать ещё" << endl;
		break;
	default :
		cout << "Неверная оценка" << endl;
   }
	cout << "Ваша оценка: " << grade << endl;

	return 0;
}

Результат выполнения:

Вы прошли
Ваша оценка: D

Вложенные инструкции if в C++

Всегда допустимо вкладывать операторы if-else, что означает, что вы можете использовать один оператор if или else if внутри другого оператора if или else if.

Синтаксис для вложенного оператора if следующий:

if(ЛОГИЧЕСКОЕ ВЫРАЖЕНИЕ 1) {
	// Выполняется, когда ЛОГИЧЕСКОЕ ВЫРАЖЕНИЕ 1 является истиной
	if(ЛОГИЧЕСКОЕ ВЫРАЖЕНИЕ 2) {
		// Выполняется, когда ЛОГИЧЕСКОЕ ВЫРАЖЕНИЕ 2 является истиной
	}
}

Вы можете вкладывать другие if … else так же, как вы вкладываете оператор if.

Пример программы на C++ с вложенными if:

#include <iostream>
using namespace std;

int main () {
	// объявление локальных переменных:
	int a = 100;
	int b = 200;

	// проверка условия логического выражения
	if( a == 100 ) {
		// если условие истино, то проверяется следующее
		if( b == 200 ) {
			// если и это условие истино, то затем печатается следующее
			cout << "Значение a равно 100 и b равно 200" << endl;
		}
	}
	cout << "Точное значение a равно: " << a << endl;
	cout << "Точное значение b равно: " << b << endl;

	return 0;
}

Результат работы данной программы:

Значение a равно 100 и b равно 200
Точное значение a равно: 100
Точное значение b равно: 200

Вложенные инструкции switch в C++

Можно иметь switch как часть кода внутри другого switch. Даже если константы case внутреннего и внешнего switch содержат общие значения, никаких конфликтов не возникнет.

В спецификации C++ указано, что для инструкциям switch должно быть разрешено не менее 256 уровней вложенности.

Синтаксис для вложенной инструкции switch следующий:

switch(ch1) {
	case 'A': 
		cout << "Эта A является частью внешнего switch";
		switch(ch2) {
			case 'A':
				cout << "Эта A является частью внутреннего switch";
				break;
			case 'B': // ...
		}
	break;
	case 'B': // ...
}

Пример программы на C++ с вложенными switch:

#include <iostream>
using namespace std;

int main () {
	// объявление локальный переменных:
	int a = 100;
	int b = 200;

	switch(a) {
		case 100:
			cout << "Эта часть от внешнего switch" << endl;
			switch(b) {
				case 200:
				cout << "Эта часть от внутреннего switch" << endl;
			}
		}
	cout << "Точное значение a равно: " << a << endl;
	cout << "Точное значение b равно: " << b << endl;

	return 0;
}

Результат выполнения скомпилированной программы:

Эта часть от внешнего switch
Эта часть от внутреннего switch
Точное значение a равно: 100
Точное значение b равно: 200

Условный оператор ? :

Условный оператор «? :» может использоваться в качестве замены инструкций if…else. Он имеет следующую общую форму:

Exp1 ? Exp2 : Exp3;

где Exp1, Exp2 и Exp3 являются выражениями. Обратите внимание на использование и размещение двоеточия. Значение выражения «? :» определяется следующим образом: Exp1 вычисляется. Если это истина, то Exp2 вычисляется и становится значением целого выражение. Если Exp1 имеет значение ложь, то Exp3 вычисляется, и его значение становится значением выражения.

? называется тернарным (троичным) оператором, потому что он требует трёх операндов и может использоваться для замены операторов if-else, которые имеют следующую форму:

if(УСЛОВИЕ) {
	var = X;
} else {
	var = Y;
}

В качестве примера изучите следующий код:

if(y < 10) { 
	var = 30;
} else {
	var = 40;
}

Предыдущий код можно переписать следующим образом:

var = (y < 10) ? 30 : 40;

Здесь x присваивается значение 30, если y меньше 10, и 40, если это не так. Вы можете попробовать следующий пример:

#include <iostream>
using namespace std;

int main () {
	// Объявление локальных переменных:
	int x, y = 10;

	x = (y < 10) ? 30 : 40;
	cout << "значение x: " << x << endl;

	return 0;
}

Результат его выполнения:

значение x: 40

Примеры программ на C++ для решения школьных задач (нахождение площади треугольника)

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

Программа для нахождения площади треугольника по длине трёх сторон. Эта программа проверяет введённые данные на правильность, а затем находит площадь треугольника, когда известны три стороны.

#include <iostream>
#include <cmath>
using namespace std;

int main () {

	cout << "\n Введите длины трёх сторон треугольника" << endl;
	float a,b,c,P,S;
	cout << "\na=";
	cin >> a;
	cout << "\nb=";
	cin >> b;
	cout << "\nc=";
	cin >> c;
	// проверяем данные на правильность
	if (a>0 && b>0 && c>0 && a+b>c && a+c>b && b+c>a)
	{
		// находим половину периметра треугольника
		P=(a+b+c)/2;
		// находим площадь треугольника
		S=sqrt(P*(P-a)*(P-b)*(P-c));
		cout << "\nПлощадь треугольника=" << S << endl;
	}
	else cout << "\n Неверные исходные данные." << endl;
}

Обратите внимание на использование символа (экранированной последовательности) \n — он означает символ новой строки (newline). В Windows вместо \n нужно использовать «\r\n». На самом деле, уже знакомый нам endl является универсальным способом указать перевод строки и следует использовать именно его. А \n приведены здесь в качестве примера, который вы можете встретить в коде.

Также обратите внимание на использование инструкции else — отсутствуют фигурные скобки и команда для выполнения находится в той же строке, что и else — такое допускается, если необходимо выполнить только одну команду.

Пример работы программы:

Задания для самостоятельной работы: напишите программы для

  • нахождения решений системы двух уравнений
  • нахождения решений системы трёх уравнений
  • решения квадратных уравнений.

Типы циклов C++

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

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

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

Цикл while в C++

Оператор while многократно запускает целевой код, пока указанное условие является true (истиной).

Синтаксис цикла while в C++:

while(УСЛОВИЕ) {
	КОД;
}

Здесь КОД может быть отдельным оператором или блоком операторов. УСЛОВИЕМ может быть любое выражение, а true — любое ненулевое значение. Цикл повторяется, пока условие true.

Когда условие становится false, управление программой переходит на строку, следующую непосредственно за циклом.

Схема потока:

Здесь ключевым моментом цикла while является то, что цикл может никогда не выполниться. Когда условие проверено и результат false, тело цикла будет пропущено, и будет выполнен первый оператор после цикла while.

Пример кода с while на C++:

#include <iostream>
using namespace std;

int main () {
	// Объявление локальной переменной:
	int a = 10;

	// выполнение цикла while
	while( a < 20 ) {
		cout << "значение a равно: " << a << endl;
		a++;
	}

	return 0;
}

Результат работы программы:

значение a равно: 10
значение a равно: 11
значение a равно: 12
значение a равно: 13
значение a равно: 14
значение a равно: 15
значение a равно: 16
значение a равно: 17
значение a равно: 18
значение a равно: 19

Цикл for в C++

Цикл for — это структура управления повторением, которая позволяет эффективно написать цикл, который должен выполняться определённое количество раз.

Синтаксис цикла for в C++:

for ( ИНИЦИАЛИЗАЦИЯ; УСЛОВИЕ; ПРИРАЩЕНИЕ ) {
	КОД;
}

Объяснение потока управления в цикле for:

  • Шаг ИНИЦИАЛИЗАЦИЯ выполняется первым и только один раз. Этот шаг позволяет вам объявить и инициализировать любые переменные управления циклами. Вы не обязаны сюда что-либо до точки с запятой.
  • Далее оценивается УСЛОВИЕ. Если оно равно true, тело цикла выполняется. Если значение равно false, тело цикла не выполняется, и поток управления переходит к следующему оператору сразу после цикла for.
  • После выполнения тела цикла for поток управления возвращается обратно к оператору ПРИРАЩЕНИЯ. Это утверждение можно оставить пустым, если после УСЛОВИЯ стоит точка с запятой.
  • УСЛОВИЕ теперь оценивается снова. Если оно равно true, цикл выполняется, и процесс повторяется (тело цикла, затем шаг ПРИРАЩЕНИЕ, а затем снова проверка УСЛОВИЯ). После того, как УСЛОВИЕ становится false, цикл for завершается.

Схема потока:

Пример программы с for на C++:

#include <iostream>
using namespace std;

int main () {
	// выполнение цикла for
	for( int a = 10; a < 20; a = a + 1 ) {
		cout << "значение a равно:" << a << endl;
	}
	return 0;
}

Результат выполнения кода:

значение a равно:10
значение a равно:11
значение a равно:12
значение a равно:13
значение a равно:14
значение a равно:15
значение a равно:16
значение a равно:17
значение a равно:18
значение a равно:19

Цикл do…while в C++

В отличие от циклов for и while, которые проверяют условие цикла в верхней части цикла, цикл do…while проверяет своё состояние в нижней части цикла.

Цикл do…while похож на цикл while, за исключением того, что цикл do…while гарантированно будет выполнен как минимум один раз.

Синтаксис цикла do…while в C++:

do {
	ОПЕРАТОР(Ы);
} 
while( УСЛОВИЕ );

Обратите внимание, что выражение УСЛОВИЕ появляется в конце цикла, поэтому ОПЕРАТОР(Ы) в цикле выполняется один раз перед проверкой условия.

Если УСЛОВИЕ истинно, поток управления переходит обратно вверх для повторного выполнения, и ОПЕРАТОР(Ы) в цикле выполняется снова. Этот процесс повторяется до тех пор, пока данное УСЛОВИЕ не станет ложным.

Схема потока:

Пример кода do…while в C++:

#include <iostream>
using namespace std;

int main () {
	// Объявление локальной переменной:
	int a = 10;

	// выполнение цикла do
	do {
		cout << "Значение переменной a равно:" << a << endl;
		a = a + 1;
	} while( a < 20 );

	return 0;
}

Результат работы программы:

Значение переменной a равно:10
Значение переменной a равно:11
Значение переменной a равно:12
Значение переменной a равно:13
Значение переменной a равно:14
Значение переменной a равно:15
Значение переменной a равно:16
Значение переменной a равно:17
Значение переменной a равно:18
Значение переменной a равно:19

Вложенный циклы C++

Цикл может быть вложен в другой цикл. C++ допускает как минимум 256 уровней вложенности.

Синтаксис вложенного цикла for в C++ следующий:

for ( ИНИЦИАЛИЗАЦИЯ; УСЛОВИЕ; ПРИРАЩЕНИЕ ) {
	for ( ИНИЦИАЛИЗАЦИЯ; УСЛОВИЕ; ПРИРАЩЕНИЕ ) {
		КОД;
	}
	КОД; // здесь также может быть код.
}

Синтаксис для вложенного оператора while в C++ выглядит следующим образом:

while(УСЛОВИЕ) {
	while(УСЛОВИЕ) {
		КОД;
	}
	КОД; // здесь также может быть код.
}

Синтаксис для вложенного оператора цикла do…while в C++ следующий:

do {
	КОД; // здесь также может быть код.
	do {
		КОД;
	} while( УСЛОВИЕ );
} while( УСЛОВИЕ );

Следующая программа использует вложенный цикл for для поиска простых чисел от 2 до 100:

#include <iostream>
using namespace std;

int main () {
	int i, j;

	// Первый цикл - увеличивает значение i на единицу, пока это значение не достигнет 100
	for(i = 2; i<100; i++) {
		// выполняется увеличение j на единицу до тех пор, пока значение i/j не станет больше или равно самой j
		for(j = 2; j <= (i/j); j++)
			// если остаток от деления i/j равен 0, то оборвать выполнение текущего цикла, поскольку это не простое число
			if(!(i%j)) break;
			if(j > (i/j)) cout << i << " это простое число\n";
		}

	return 0;
}

Результат выполнения приведённого выше кода:

2 это простое число
3 это простое число
5 это простое число
7 это простое число
11 это простое число
13 это простое число
17 это простое число
19 это простое число
23 это простое число
29 это простое число
31 это простое число
37 это простое число
41 это простое число
43 это простое число
47 это простое число
53 это простое число
59 это простое число
61 это простое число
67 это простое число
71 это простое число
73 это простое число
79 это простое число
83 это простое число
89 это простое число
97 это простое число

Чтение стандартного ввода в C++

Мы уже рассмотрели вариант стандартного ввода — ввод данных с клавиатуры. Также возможна передача данных по трубе (|) - это также является стандартным вводом (подробности смотрите в статье «Азы работы в командной строке Linux (часть 3)».

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

В качестве примера возьмём следующий код:

#include <iostream>
#include <string>

using namespace std;

int main() {
	string line;
	int size;

	getline(cin, line);

	size = line.size();
	cout << "Длина: " << size << "\t" << line << endl;
}

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

Команду можно запустить так:

./a.out

Затем введите что-нибудь вроде

test string 1234

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

Длина: 16	test string 1234

Данные в программу можно передать и так:

echo "test string 1234" | ./a.out 
Длина: 16	test string 1234

Как видим, получен идентичный результат.

А что если мы хотим передать много строк, к примеру, имеется файл и мы хотим посчитать длину каждой строки в нём? Что нужно сделать, чтобы можно было передать по стандартному вводу множество строк, к примеру, командой вида:

cat dic.txt | ./a.out

Для этого инструкцию getline(cin, line) нужно поместить в цикл while следующим образом:

while (getline(cin, line)) {.......}

В результате стандартный ввод будет считываться до тех пор, пока не закончится файл.

Пример рабочего кода с примером чтением ввода из командной строки:

#include <iostream>
#include <string>

using namespace std;

int main() {
	string line;
	int size;

	while (getline(cin, line)) {
	size = line.size();
	cout << "Длина: " << size << "\t" << line << endl;
	}
}

Результат запуска команды:

cat dic.txt | ./a.out

Как можно увидеть, обработана каждая строка файла.

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

Конвертирование из одного типа данных в другой в C++

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

Как конвертировать char в string

Аргументы командной строки передаются в программу как массив данных с типом char.

Тип char может на лету преобразовываться в string, то есть для преобразования char в string не требуется специальной функции, например, следующий код не вызовет ошибок:

#include <iostream>
#include <string>
using namespace std;

int main() {
	char p[] = "111.11";
	string s;

	s = p;
	cout << s << endl;
	return 0;
} 

О некоторых нюансах смотрите раздел «6.3 Сравнение char со строкой в C++».

Как преобразовать число в строку

Для этого используется функция to_string, пример:

#include <iostream>
#include <string>
using namespace std;

int main() {
	double d = 111.22;
	string s;

	s = to_string(d);
	cout << s << endl;
 	return 0;
}

Результат:

111.220000

Результат немного неожиданный. Если вам не нужна дробная часть, то вы можете предварительно конвертировать число с плавающей точкой (double или float) в целое число (о преобразовании различных типов чисел между самой чуть дальше), а затем конвертировать его в строку:

#include <iostream>
#include <string>
using namespace std;

int main() {
    double d = 111.22;
    string s;

    s = to_string((int)d);
    cout << s << endl;
    return 0;
}

Результат:

111

Ещё несколько примеров:

#include <iostream>
#include <string>
using namespace std;

int main()
{
	double f = 23.43;
	double f2 = 1e-9;
	double f3 = 1e40;
	double f4 = 1e-40;
	double f5 = 123456789;
	string f_str = to_string(f);
	string f_str2 = to_string(f2); // Примечание: возвращает "0.000000"
	string f_str3 = to_string(f3); // Примечание: Не возвращает "1e+40".
	string f_str4 = to_string(f4); // Примечание: возвращает "0.000000"
	string f_str5 = to_string(f5);
	cout << "cout: " << f << '\n'
		<< "to_string: " << f_str  << "\n\n"
		<< "cout: " << f2 << '\n'
		<< "to_string: " << f_str2 << "\n\n"
		<< "cout: " << f3 << '\n'
		<< "to_string: " << f_str3 << "\n\n"
		<< "cout: " << f4 << '\n'
		<< "to_string: " << f_str4 << "\n\n"
		<< "cout: " << f5 << '\n'
		<< "to_string: " << f_str5 << '\n';
}

Результат:

cout: 23.43
to_string: 23.430000

cout: 1e-09
to_string: 0.000000

cout: 1e+40
to_string: 10000000000000000303786028427003666890752.000000

cout: 1e-40
to_string: 0.000000

cout: 1.23457e+08
to_string: 123456789.000000

Как преобразовать строку в число

В следующих группах функции различаются последней буквой. В этих именах функций:

  • i — означает int
  • f — означает float
  • d — означает double
  • l — означает long
  • ld — означает long double
  • ll — означает long long

Функции для преобразования строки в целое число со знаком:

Пример кода:

#include <iostream>
#include <string>
using namespace std;

int main()
{
	string str1 = "45";
	string str2 = "3.14159";
	string str3 = "31337 со словами";
	string str4 = "слова и 2";

	int myint1 = stoi(str1);
	int myint2 = stoi(str2);
	int myint3 = stoi(str3);


	cout << "stoi(\"" << str1 << "\") это " << myint1 << '\n';
	cout << "stoi(\"" << str2 << "\") это " << myint2 << '\n';
	cout << "stoi(\"" << str3 << "\") это " << myint3 << '\n';

} 

Вывод:

stoi("45") это 45
stoi("3.14159") это 3
stoi("31337 со словами") это 31337

Функции для преобразования строки в целое число без знака:

Функции для преобразования строки в значение с плавающей запятой

Преобразование различных типов чисел

К примеру, нужно преобразовать целочисленное число (int) в число с плавающей точкой (float или double). Либо наоборот, дробное число преобразовать в цело число.

1-й способ: преобразование целочисленного числа в число с плавающей точкой при арифметическом действии. Следующий код демонтирует это:

#include <iostream>
using namespace std;

int main() {
	int a=5;

	cout << "Результатом a/2 будет: " << a/2 << endl;
	cout << "А результатом (a + 0.0)/2 является: " << (a + 0.0)/2 << endl;
	return 0;
}

Вывод:

Результатом a/2 будет: 2
А результатом (a + 0.0)/2 является: 2.5

То есть в первой строке целочисленное число поделено на 2 и поскольку тим числа int, то дробная часть утеряна.

Во второй строке мы прибавили дробное число к int, в результате тип числа a изменён на число с плавающей точкой. После этого при делении на 2 получен верный результат без потери дробной части.

2-й способ: кастинг, то есть явное указание типа числа. Для этого в скобках перед переменной указывается новый тип. Пример кода кастинга чисел:

#include <iostream>
using namespace std;

int main() {
	double a = 21.09399;
	float b = 10.20;
	int c;
	int d;

	c = (int) a;
	cout << "Значение (int)a равно: " << c << endl;

	c = (int) b;
	cout << "Значение (int)b равно: " << c << endl;

	 return 0;
}

Результат:

Значение (int)a равно: 21
Значение (int)b равно: 10

Преобразование последовательность символов в целочисленное значение или значение с плавающей точкой

TBD

to_chars

Преобразование целого числа или значение с плавающей запятой в строку

TBD

from_chars

Доступ к аргументам командной строки в C++

При запуске консольных приложений очень часто используются аргументы (опции) команды — они указываются через пробел после имени запускаемого файла. Например:

программа arg1 arg2 arg3

Рассмотрим, как передать аргументы команды в программу C++ и как получить доступ к аргумент командной строки из программы C++.

Чтобы в программе на C++ прочитать переданные аргументы, замените строку объявления главной функции:

int main () {

на следующую строку:

int main (int argc, char *argv[]) {

В этой строке сразу 3 новых концепции, которые мы не успели рассмотреть — мы изучим их чуть позже:

  • объявление функции и передача аргументов в функцию
  • указатели (символ звёздочки *)
  • массив (обозначается квадратными скобками [])

На данный момент нам достаточно знать, что переменная argc, которая представляет собой целое число (int), содержит количество переданных аргументов. А сами аргументы содержатся в элементах массива с обозначениями argv[1], argv[2], argv[3] и так далее.

Элемент массива argv[0] будет содержать имя самой программы.

Продемонстрируем это следующей простой программой:

#include <iostream>
#include <cmath>
using namespace std;

int main (int argc, char *argv[]) {

	cout << "Всего передано аргументов: " << argc << endl;
	cout << "Значение первого аргумента: " << argv[1] << endl;
	cout << "Значение второго аргумента: " << argv[2] << endl;
	cout << "Значение третьего аргумента: " << argv[3] << endl;
	cout << "Имя файла программы: " << argv[0] << endl;
}

Скомпилируйте и запустите её примерно следующим образом:

./a.out 12345 "Второй аргумент" 'Последний аргумент'

Результат работы программы:

Всего передано аргументов: 4
Значение первого аргумента: 12345
Значение второго аргумента: Второй аргумент
Значение третьего аргумента: Последний аргумент
Имя файла программы: ./a.out

Аргументы командной строки разделяются пробелом, если вы хотите передать аргумент с пробелом, например «hello world», то используйте кавычки.

Более подробно аргументы, в том числе специальная утилита getopt для парсинга аргументов командной строки C++, будут рассмотрены позже в одной из следующих глав:

man 3 getopt

Пример консольного калькулятора на C++

Итак, подытожим наши знания и применим их для написания калькулятора с интерфейсом командной строки.

В программе используется:

  • консольный ввод и вывод
  • переменные разных типов
  • конвертация разных типов данных
  • чтение аргументов командной строки
  • изменение точности в выводе с помощью setprecision
  • инструкции if и else для управления логикой программы
  • однострочные и многострочные комментарии
  • арифметические действия

Код:

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

int main (int argc, char *argv[]) {

float f1,f2;
string s;

// проверяем количество аргументов. Должно быть 4, т.к. самый первый это имя программы
if (argc < 4) {
	cout << "Нужно указать 3 аргумента:" << endl;
	cout << "ДЕЙСТВИЕ ЧИСЛО1 ЧИСЛО2" << endl;
	cout << "ДЕЙСТВИЕМ может быть sum (сложение), mul (умножение), sub (вычитание), div (деление)" << endl;
	return 1;
}

/* присваиваем значение аргументам.
 при этом char автоматически конвертируется в string, а
 а также char конвертируется в float функциями stof
*/
	s = argv[1];
	f1 = stof(argv[2]);
	f2 = stof(argv[3]);

	if (s == "sum") {
		 cout << "Сумма равна: " << setprecision(16) << f1 + f2 << endl;
	}

	else if ((s == "mul")) {
		 cout << "Произведение равно: " << setprecision(16) << f1 * f2 << endl;
	}

	else if ((s == "sub")) {
		cout << "Разность равна: " << setprecision(16) << f1 - f2 << endl;
	}

	else if ((s == "div")) {
		cout << "Деление равно: " << setprecision(16) << f1 / f2 << endl;
	}
	
	else {
		cout << "Вы неправильно ввели название действия: " << argv[1] << endl;
	}

	return 0;
}

Примеры запуска

./a.out sum 434 113
Сумма равна: 547

./a.out mult 23.3 54250.345
Вы неправильно ввели название действия: mult

./a.out mul 23.3 54250.345
Произведение равно: 1264033

./a.out sub 32 900
Разность равна: -868

./a.out div 32900 876
Деление равно: 37.55707931518555

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

 

 

 

[В ПРОЦЕССЕ НАПИСАНИЯ]

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

 

 

Рекомендуется Вам:

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

Ваш адрес email не будет опубликован.