Uploaded by konstantin3520

Методичка основы Основы программирования (С++)

advertisement
Содержание:
1. Среда разработки
2
2. Создание проекта
2
3. Стандартный шаблон программы
6
4. Написание первой программы
10
5. Отправка задач в тестирующую систему
13
6. Переменные. Арифметические операторы
6.1. Переменные
6.2. Арифметические операторы. Сложение, вычитание и умножение
6.3. Арифметические операторы. Деление
18
18
21
21
7. Перевод из одного типа данных в другой
23
8. Условия. Операторы ветвления
24
9. Точность вычислений
31
10. Циклы
32
11. Массивы
36
12. Символы. Строки
39
13. Двумерные массивы
42
14. Процедуры и функции, глобальные переменные
45
15. Рекурсия
49
16. Структуры данных
52
17. Указатели. Списки
55
18. Дебаг
58
19. Вместо эпилога
63
Основы программирования (C++)
2
1. Среда разработки
Для работы с языком программирования C++ вам необходима среда разработки,
в которой можно будет писать, отлаживать и исполнять код. Для обладателей устройств
под управлением операционной системы Microsoft Windows мы рекомендуем
использовать среду Microsoft Visual Studio, она обладает всем набором необходимых
инструментов. На сайте https://www.visualstudio.com/ru/free-developer-offers/ можно
загрузить бесплатную версию данной среды разработки.
После установки первый запуск может длиться достаточно долго.
2. Создание проекта
Для дальнейшей работы вам потребуется создать проект. Для этого на
появившейся странице можно выбрать пункт бокового меню "Создать проект" (“New
project”), либо использовать вкладки верхней строки меню “Файл” -> “Создать” ->
“Проект” ("File" -> "New" -> “Project”).
В категории Visual C++ следует выбрать шаблон “Консольное приложение Win32”
(“Win32 Console Application”) и ввести название проекта. Для дальнейшего удобства
можно назвать его именем задачи, над которой вы работаете (например, “MyFirstTask”).
Далее выбирается директория, в которой будут храниться ваши проекты (в нашем
случае это стандартное размещение проектов "Мои документы" -> "Visual Studio 2015" > "Projects"). После этого – подтверждение кнопкой "OK".
Основы программирования (C++)
3
Нажмите кнопку “Далее” (“Next”).
Теперь выберите опцию "Пустой проект" (“Empty project”), уберите галочку с
пункта “Проверки жизненного цикла разработки безопасного ПО (SDL)” (“Security
Development Lifecycle (SDL) checks”) и нажмите кнопку "Готово" (“Finish”).
Основы программирования (C++)
4
У вас появится пустой только что созданный проект.
Далее необходимо создать файл исходного кода, в котором вы будете работать.
Для этого в "Обозревателе решений" (“Solution explorer”) нажмите правой кнопкой мыши
на папке "Файлы исходного кода" (“Source files”) и выберите "Добавить" -> "Создать
элемент" (“Add” -> “New Item”).
Основы программирования (C++)
5
В открывшемся окне выберите "Файл C++" (“C++ File”) и нажмите кнопку
"Добавить" (“Add”).
Поздравляем, вы создали основной рабочий файл! Именно в нем вы и будете
работать со своим кодом.
Основы программирования (C++)
6
3. Стандартный шаблон программы
Теперь вам необходимо написать стандартный шаблон программы. Обратите
внимание на приведенный ниже код:
Разберем написанное построчно:
#include <iostream>
Эта строка подключает к вашему файлу библиотеку iostream, содержащую большое
количество функций, которые будут необходимы в дальнейшем процессе написания
программ. В этом блоке можно подключить и другие библиотеки.
Совет: не подключайте слишком много библиотек без необходимости. От их количества
зависит скорость компиляции и вес вашей программы.
Обратите внимание: точка с запятой в конце строки не ставится!
using namespace std;
Эта строка подключает пространство имен std. Подробнее об этом вы узнаете немного
позже, а пока просто запомните, что эта строка необходима. Не забудьте в конце строки
поставить точку с запятой (это важно)!
int main()
{}
Эти строки - основное "тело" программы. Внутри фигурных скобок вы будете писать код
(пример будет дальше).
Обратите внимание: точка с запятой не ставится ни перед открывающейся фигурной
скобкой(“{“), ни после закрывающейся(“}”)!
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
Эти строки делают возможной работу с файлами. То есть вместо использования
консольного ввода и вывода вы можете считывать данные из файла “input.txt” и
выводить в файл “output.txt”. Файловый ввод и вывод данных необходимы для более
Основы программирования (C++)
7
удобной отладки вашего кода и его проверки в тестирующей системе.
Для того, чтобы создать эти файлы, в разделе "Обозреватель решений" (“Solution
Explorer”) правой кнопкой мыши нажмите на название вашего проекта (в нашем случае
– "MyFirstTask", которое находится 2-ым пунктом). В открывшемся внизу меню найдите
"Открыть папку в проводнике" (“Open folder in File Explorer”). Эта команда откроет
местоположение вашего проекта.
В данной папке вам необходимо создать текстовые файлы “input.txt” и “output.txt”.
Для этого правой кнопкой нажимаете на пустом пространстве -> "Создать" ->
"Текстовый документ" и вводите название.
Внимание, если у вас при создании не отобразилось расширение .txt, то его,
соответственно, дописывать не нужно! Просто создаете файлы input и output.
Основы программирования (C++)
8
Для более удобного взаимодействия с этими файлами необходимо перенести их
в среду разработки. Для этого выберите файл и, удерживая его левой кнопкой мыши,
переместите в рабочее окно среды разработки. После перемещения ваши файлы
должны открыться.
Над окном ввода находятся вкладки с этими файлами, с ними можно
взаимодействовать точно так же, как и с вкладками в браузере.
Поздравляем, проект готов к написанию вашей первой программы!
ВНИМАНИЕ!!!
Работа с файлами, для ввода и вывода из программы - это важная и удобная
возможность при разработке алгоритмов, чем более сложный алгоритм вы будете
Основы программирования (C++)
9
разрабатывать, тем более удобным это будет. Однако система CodeHedgehoge не
работает с файлами как способом ввода-вывода, поэтому когда будете отправлять
решение в систему закомментируйте строки с freopen, т.е. у вас оно должно выглядеть
вот так
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
комментирование позволяет компилятору игнорировать то, что закомментировано, и
при проверке вашего решения эти команды не будут исполняться
Основы программирования (C++)
10
4. Написание первой программы
После создания шаблона, можно приступить к написанию кода первой
программы. Для примера создадим программу, которая выводит в файл фразу "Hello,
World!".
Для этого в блоке "main" напишите команду вывода “cout << “Hello, World!”;”.
Подробнее рассмотрим особенности функции "cout <<".
Команда "cout <<" выводит данные (строку "Hello, World!") в поток вывода (в
нашем случае - в файл). Если вам необходимо вывести переменную (пусть у вас будет
переменная int a – целочисленная переменная a), то напишите "cout << a;". На выходе
вы получите не букву "a", а содержимое переменной a.
Если вам необходимо вывести строку/слово/букву/символ, то вы их заключаете
в двойные кавычки (""). Например, "cout << “Hello, World!”;".
Для переноса на следующую строку используется команда endl. Пример: "cout
<< “Hello,” << endl << ”World!”;". Данная команда выведет "Hello," на одной строке, а
"World!" - на другой.
Основы программирования (C++)
11
Код написан. Теперь необходимо его исполнить. Для этого можно нажать либо
кнопку "Локальный отладчик Windows" (в англ. версии – "Local Windows Debugger"),
либо кнопку "F5". После окончания выполнения появится окно, которое будет
запрашивать у вас разрешение на изменение файла. Нажмите "Да" (“Yes”).
После этого открываете вкладку “output.txt” и смотрите, что же вывела ваша
программа.
Основы программирования (C++)
12
Если вы видите "Hello, World!", то поздравляем - начало изучения языка C++
положено!
Основы программирования (C++)
13
5. Отправка задач в тестирующую систему
Для оценки решения вашей задачи вы будете использовать автоматическую
тестирующую систему. Эта система проверит ваше решение на некотором количестве
контрольных значений и сообщит вердикт проверки. Тестирующая система доступна по
адресу https://code.hits.university/
Когда вы зайдёте на сайт, вам будет необходимо авторизоваться при помощи
сервиса ТГУ.Аккаунты.
Затем перейдите на страницу “Классы”, чтобы открыть свой класс. Выбираем
его(Если у вас его нету, то свяжитесь с преподавателем).
Основы программирования (C++)
14
Чтобы выбрать задачу необходимо выбрать “Задачи”, или перейти на страницу
“Темы задач”, чтобы увидеть список тем и связанные с ними задачи. Когда вы выберите
интересующую вас тему, вам будет показан список задач, входящих в неё. Для каждой
задачи вы можете посмотреть её номер, название, тему, а также количество баллов,
которое вы получите, если решите её.
Основы программирования (C++)
15
Нажмите на название интересующей вас задачи. Откроется страница с её
условием. Внимательно прочитайте условие, ограничения, формат входных и выходных
данных, разберите пример. Затем решите задачу. Когда у вас будет готовое решение,
нажмите на ссылку “Отправить решение”, расположенную над условием.
Основы программирования (C++)
16
Вам откроется страница с формой отправки. Ваше решение вы можете
отправить, прикрепив файл с кодом, либо скопировав и вставив код в текстовое поле
“Решение”. Затем выберите язык программирования в выпадающем списке. ВАЖНО!!!
Это должен быть язык, на котором вы написали свое решение.
ТАКЖЕ ВАЖНО!!! Перед отправкой решений откомментируйте или удалите строчки с
freopen
После этого нажмите на кнопку ”Отправить”. Откроется страница с очередью
тестирования.
Основы программирования (C++)
17
В таблице вы увидите ваши отправленные задачи, дату отправки и вердикт
тестирующей системы. Разберём каждый из возможных вердиктов:
Вердикт Описание
Pending
Решение ожидает тестирования. Подождите немного и обновите
страницу.
Testing
Решение в данный момент проверяется. Обновите страницу позднее.
OK
Ваше решение полностью верное.
WA
Ваше решение выдало неверный ответ на одном из тестов.
CE
Ошибка компиляции.
RT
Ошибка при работе программы.
TL
Превышен лимит времени. Ваша программа выполняется слишком долго.
PE
Неправильный формат выходных данных.
ML
Превышен лимит памяти.
SE
Нарушены ограничения безопасности.
Нажмите кнопку “[More]” рядом с вердиктом, чтобы увидеть ваше решение и
расшифровку вердикта.
Перейдите на страницу “Результаты”, чтобы увидеть свою успеваемость. Для
каждой темы, задачи из которой вы пытались решать, вы увидите таблицу. В таблице
указаны задачи, решения которых вы отправляли, актуальный вердикт и количество
попыток (в скобках), полученные вами баллы за задачу, вердикт преподавателя
(“Accepted” - “Принято” или “Rejected” - “Отклонено”), комментарий преподавателя.
Внизу таблицы вы увидите суммарное количество баллов за тему, а в самом низу
страницы - баллы за все решённые вами задачи во всех темах. Учтите, что баллы
начисляются только в том случае, если преподаватель примет ваше решение!
Основы программирования (C++)
18
6. Переменные. Арифметические операторы
6.1. Переменные
В программировании, естественно, можно не только выводить заданные слова
или числа. Зачастую перед выводом требуется что-либо сделать с этими словами,
числами, и т. д. Для этого требуется предварительно записать интересующие нас
данные в переменную. Переменная - это участок в памяти, где будет храниться
необходимая нам информация. Для объявления (создания) переменных на языке C++
используется следующая конструкция: Тип_переменной Имя_переменной_1,
Имя_переменной_2; (если требуется объявить 1 переменную, то после имени 1
переменной просто ставим точку с запятой).
Тип переменной определяет какие значения возможно использовать при работе
с этой переменной. Например, одним из таких типов является int - целочисленный тип
данных, который позволяет работать с целыми числами в диапазоне от −2 31 до 231 −
1. Это наиболее распространенный тип целочисленных данных. Существуют также
символьный тип (char), в одной переменной которого можно хранить ровно один символ
(буква, цифра, спец. символ), логический тип (bool), в котором может храниться лишь
значение true или false, “длинное длинное” целое (long long int, можно просто long
long) - целые числа, хранящиеся в диапазоне −2 63 + 1 до 263 − 1, вещественные
типы (float и double), которые могут хранить в себе дробные числа, и т. д. Имя
переменной может состоять из букв, цифр и спец. символов. Важно: имя переменной
не может начинаться с цифры!
После того, как мы объявили переменную, нам требуется что либо записать в
нее. Это можно сделать как напрямую в коде, так и при считывании из потока ввода
(файла или консоли/командной строки).
Для присваивания переменной определенного значения (в коде) используется
оператор присваивания (=). Например, если нам требуется в переменную типа int
записать значение 5, то код будет выглядеть следующим образом:
int a;
a = 5;
Также присвоить значение значение переменной можно и в момент ее объявления:
int a = 5;
Если нам требуется считать значение из потока (файла или консоли/командной
строки), то для этого требуется команда cin >> Имя_переменной. Если требуется
считать несколько переменных подряд, то для этого используем следующую
конструкцию:
cin >> Имя_переменной_1 >> Имя_переменной_2. Переменная_1 и переменная_2 не
обязательно должны иметь одинаковый тип. Главное, чтобы данные во входном файле
соответствовали типу переменных. Во входном файле переменная_1 и переменная_2
могут быть записаны хоть через пробел, хоть на следующей строке. Главное - чтобы
между ними был разделитель (пробел, перенос строки или табуляция) и не было
никаких других данных. Теперь напишем программу, которая будет считывать 2 числа и
выводить их в обратном порядке (сначала 2-е число, затем первое).
Создадим (или откроем уже имеющийся) проект и подготовим шаблон. Далее
создадим две целочисленных переменных и считаем их.
Основы программирования (C++)
19
После напишем команду, которая выведет их через пробел в обратном порядке
(т.е. сначала содержимое переменной b, а затем содержимое переменной a).
Теперь нужно добавить необходимые входные данные в файл input.txt.
Основы программирования (C++)
20
Запускаем программу (F5) и ждем ее выполнения. После подтверждения
разрешения на изменение файлов в среде разработке, открываем output.txt и видим:
У нас все получилось! Поздравляю, мы научились считывать и выводить
переменные.
Основы программирования (C++)
21
6.2. Арифметические операторы. Сложение, вычитание и умножение
В программе можно совершать различные операции над переменными перед
тем, как их использовать. Например, нам требуется совершить над ними
арифметические операции: сложение, вычитание, умножение. Они реализуются при
помощи операторов “+”, “-” и “*” соответственно. С делением все немного сложнее. О
нем поговорим позже.
Напишем программу, от которой требуется вывести сумму 2 чисел. На вход
программы приходит 2 числа (возьмем из примера выше 73 и 15). На выходе мы должны
получить 1 число - сумму двух введённых чисел.
Т.к. в результате сложения двух переменных типа int может получиться число,
большее, чем 2^32, то мы будем для результирующей переменной использовать тип
long long.
Получим примерно следующий код:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int a, b;
cin >> a >> b;
long long res;
res = a + b;
cout << res;
return 0;
}
И в результате работы программы мы должны получить число 88.
6.3. Арифметические операторы. Деление
Основы программирования (C++)
22
Рассмотрим теперь арифметическую операцию “Деление”. В программе её
можно совершить при помощи оператора “/”. Поскольку при делении у нас может
получиться не обязательно целое число, рассмотрим, как данная операция будет вести
себя с разными типами данных.
Сначала разберём деление с переменными типа int. Напишем простую
программу:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int a, b;
cin >> a >> b;
int res = a / b;
cout << res;
return 0;
}
Что выведет данная программа, если мы подадим на вход, например, 12 и 2?
Очевидно, что при делении 12 на 2 мы получим 6. Это и будет напечатано в выходном
файле.
Но что произойдёт, при вводе, например, 16 и 3? Поскольку тип int хранит только
целочисленные значения, то в переменную res будет записана целая часть от деления
16 на 3. То есть в выходной файл будет напечатано число 5.
Мы знаем, как узнать целую часть при делении одного целого числа на другое.
Но что, если мы хотим получить остаток от деления? Для этого существует оператор
“%”. Немного перепишем нашу программу:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int a, b;
cin >> a >> b;
int res = a % b;
cout << res;
return 0;
}
Теперь программа будет считать остаток от деления переменной a на
переменную b. Если мы дадим на вход программе числа в 16 и 3, то на выходе получим
число 1. Действительно, остаток от деления 16 на 3 равен 1.
Основы программирования (C++)
23
Мы разобрали, как будет вести себя операция деления с целочисленными
переменными. Но что будет происходить при попытке поделить переменные типа
double? Double хранит в себе дробь в десятичном виде. Напишем следующую
программу:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
double a, b;
cin >> a >> b;
double res = a / b;
cout << res;
return 0;
}
Если теперь мы дадим программе на вход числа 5 и 2, то на выходе ожидаемо
получим 2.5.
Стоит отметить, что если переменная a будет типа double, а переменная b - типа
int, то при входных данных 5 и 2 мы так же получим 2.5 на выходе. Но если и переменная
a, и переменная b будут типа int, то в переменную res будет записана целая часть от
деления 5 на 2 (то есть 2), даже не смотря на то, что res имеет тип double.
Заметим, что существует более краткая форма записи арифметических
действий. К примеру, нам нужно к переменной a = 10; прибавить число 8. Мы можем
сделать это следующим образом: “a = a + 8;”. Однако, это же действие можно было
записать как “a += 8;”. Данная запись более короткая, но является равносильной той,
что описана выше.
Аналогично, мы можем записать “-=”, “*=” и “/=”, что означает “вычесть”,
“умножить” и “разделить”.
7. Перевод из одного типа данных в другой
Вам может понадобиться конвертировать один тип данных в другой. Например,
записать в переменную типа int значение переменной типа double, или же что-то ещё.
Вот несколько способов выполнить перевод из одного типа данных в другой.
Например, чтобы в переменную int a записать значение из переменной double
b, можно воспользоваться следующей записью: “a = (int) b;”. В данном случае
Основы программирования (C++)
24
компилятор будет воспринимать переменную b как целочисленную и запишет в a целую
часть от дробного числа, хранящегося в b.
Если мы запишем выражение по типу “double a = 5 / 2;”, то в a будет записано 2.
Это происходит потому, что по умолчанию компилятор воспринимает числа как
целочисленные значения. А значит при делении одного на другое он берёт только
целую часть. Чтобы дать ему понять, что мы работаем с дробными числами, можно
воспользоваться следующей записью: “double a = 5.0 / 2;”. Ноль после точки не влияет
на значение числа. Но он- показывает, что данное число мы рассматриваем как
дробное. Теперь в переменную a будет записано значение 2.5. Аналогично, если есть
переменная “int a = 5;”, то записать результат её деления на 2 можно следующим
образом: “double b = 1.0 * a / 2;”.
В будущем вам может понадобиться конвертировать char в int. Если мы
запишем “int a = ‘5’;”, то в переменную a будет записан номер символа в ASCII. В
данном случае - 53. Если же мы хотим перевести символ именно в цифру, можно
воспользоваться следующим приёмом: “int a = ‘5’ - ‘0’;”. В этом случае в переменную a
будет записано число 5.
Если мы хотим записать в char символ с определённым номером в ASCII, то
можно сделать это следующим образом: “char a = 67;”. В переменную a будет записан
символ “C”.
О работе с символами вы узнаете в следующих разделах.
8. Условия. Операторы ветвления
Мы научились выполнять простейшие арифметические операции. Но теперь мы,
возможно, захотим проверить результат их работы и в зависимости от этого выполнить
то или иное действие в программе. Например, нам необходимо написать программу,
которая определит, является ли введённое пользователем число чётным или нет. Если
число чётное - будем выводить “Yes” в выходной файл, если нет - выведем “No”.
В программе мы можем использовать условия. Например, мы можем сравнивать
числа или переменные, используя операторы сравнения “>”, “<”, “>=”, “<=”, “==” или
Основы программирования (C++)
25
“!=”. Они означают “больше”, “меньше”, “больше или равно”, “меньше или равно”,
“равно”, “не равно” соответственно.
Например, если у нас есть некие переменные a и b, и мы хотим узнать, значение
a больше значения b или нет, то можем записать такое выражение: “a > b”.
Оно вернёт true (истина), если a действительно больше b, и false (ложь) в противном
случае.
Но где мы можем использовать данные выражения? И как нам заставить
выполнять программу различные действия в зависимости от возвращённого ими
значения? Для этого можно использовать оператор ветвления if.
“If” дословно означает “если”. Этот оператор имеет следующую конструкцию:
if ([Условие])
[Действие]
После оператора if обязательно в круглых скобках идёт условие. Если условие
истинно, то будет выполнено действие, описанное сразу после if. Если условие ложно,
то программа пропустит это действие и продолжит выполняться дальше. Важно, в
данной записи у нас может идти только одно действие!
Вернёмся к задаче про чётность числа. Для начала вспомним, что чётное число
- это число, которое при делении на 2 даёт остаток 0. То есть если есть переменная a и
выражение “a % 2 == 0” истинно, значит значение a чётно. Заметим, что в условии нам
не обязательно сравнивать только переменные. Мы можем записать туда любые
выражения, и сначала будет посчитано выражение, а лишь затем выполнится
сравнение.
Используя конструкцию выше, попробуем решить задачу.
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int a;
cin >> a;
if(a % 2 == 0)
cout << "Yes";
return 0;
}
Теперь, если пользователь введёт чётное число, то программа выведет “Yes”.
Но если пользователь введёт нечётное число, то программа ничего не напечатает.
Наше решение ещё не полное. Нам нужно как-то обрабатывать случаи, когда остаток от
деления a на 2 не равен нулю. То есть нужно, чтобы помимо нашего “если” было
Основы программирования (C++)
26
действие “иначе”. Для этого есть оператор else, что в переводе и означает то самое
“иначе”. Его использование выглядит следующим образом:
if ([Условие])
[Действие 1]
else
[Действие 2]
Теперь, в случае истинности условия, программа выполнит [Действие 1]. В
противном случае будет выполнено [Действие 2].
Дополним наше решение задачи:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int a;
cin >> a;
if(a % 2 == 0)
cout << "Yes";
else
cout << "No";
return 0;
}
Теперь, если мы введём чётное число (например 12), программа выведет “Yes”.
Если введём нечётное (например, 23), программа выдаст “No”.
Мы решили поставленную задачу. Но что делать, если бы нам понадобилось
выполнить не одно действие, а несколько? Например, что если помимо ответа, чётное
число или нет, нам нужно будет вывести целую часть от деления этого числа на 2?
Внутри конструкции if - else мы можем выполнять не просто одно действие, но и
последовательность действий. Но для этого эту последовательность необходимо
прописывать внутри фигурных скобок:
if ([Условие])
{
[Действие
[Действие
...
}
else
{
[Действие
[Действие
...
1]
2]
3]
4]
Основы программирования (C++)
27
}
Теперь при истинности условия будут выполняться [Действие 1], [Действие 2] (и
другие действия, которые будут описаны), в противном случае - [Действие 3], [Действие
4] (и другие описанные действия). В данном случае использование else тоже не
обязательно, и мы вполне можем убрать его вместе с действиями 3 и 4, оставив лишь
if и действия 1 и 2, обёрнутые в фигурные скобки.
Адаптируем нашу программу под дополненное условие:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int a;
cin >> a;
if(a % 2 == 0)
{
cout <<
int res
cout <<
}
else
{
cout <<
int res
cout <<
}
return 0;
"Yes - ";
= a / 2;
res;
"No - ";
= a / 2;
res;
}
Если мы запустим нашу программу и введём число 12, то она выдаст “Yes - 6”.
Если введём число 5, то она выведет “No - 2”.
Конечно, мы могли бы вычислить целую часть от деления и после оператора if.
Но данный пример демонстрирует, как можно использовать этот оператор с
последовательностью действий.
При составлении условий в операторе if мы так же можем использовать
логические операции “И” и “ИЛИ”. В c++ они обозначаются как “&&” и “||”
соответственно. Так же отдельные части условия можно оборачивать в круглые скобки,
чтобы объяснить компилятору, что нужно выполняться сначала, а что потом. Таким
образом можно создавать сколь угодно сложные логические выражения.
Например, если бы в задаче мы хотели проверить, что число делится и на 2 и на
3, или делится на 5, то условие имело бы вид ((a % 2 == 0) && (a % 3 == 0)) || (a % 5 ==
0).
В данном случае программа проверит делимость числа на 2, потом делимость
числа на 3, далее выяснит, выполняются ли эти условия одновременно, а затем
рассмотрит делимость числа на 5. И если хотя бы одно из условий будет верно (либо
Основы программирования (C++)
28
число делится и на 2 и на 3, либо на 5), то выражение вернёт истину (true), иначе ложь
(false). Попробуем написать программу с данным логическим выражением:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int a;
cin >> a;
if(((a % 2 == 0) && (a % 3 == 0)) || (a % 5 == 0))
cout << "Yes";
else
cout << "No";
return 0;
}
Если мы введём число 6, программа выведет “Yes”, т.к. 6 делится на 2 и на 3.
Если число 10, то программа тоже выведет “Yes”, т.к. 10 делится на 5. Если мы введём
число 30, то программа опять выведет “Yes”. Но если мы дадим на вход число 8, то
программа выведет “No”, так как наше условие не выполнятеся.
Помимо оператора ветвления if, в c++ так же имеется оператор switch. Он
позволяет в зависимости от значения переменной или выражения выполнить ту или
иную операцию. Причём возможных вариантов развития событий может быть сколь
угодно много:
switch ([Переменная или выражение])
{
case [Вариант 1]:
{
[Набор действий 1]
break;
}
case [Вариант 2]:
{
[Набор действий 2]
break;
}
case [Вариант 3]:
{
[Набор действий 3]
break;
}
default:
{
[Набор действий по умолчанию]
}
Основы программирования (C++)
29
}
Теперь в зависимости от значения переменной или выражения будет выполнено
одно из действий, описанных после соответствующего оператора case. В случае, если
мы не предусмотрели заранее какое-либо из возможных значений, то будет выполнены
действия, описанные после оператора default.
Важно, что переменная или выражение должны обязательно быть
целочисленными, а также могут являться логическими true или false, или же иметь
символьный тип. В противном случае при компиляции программы вы получите ошибку.
Заметьте, после каждой последовательности действий, описанных после
оператора case, следует оператор break. Он нужен для того, чтобы после выполнения
указанных действий прервать исполнение оператора switch и продолжить выполнение
программы после него.
Давайте рассмотрим на примере, как можно использовать оператор switch.
Предположим, нам необходимо написать простейший калькулятор. На вход ему будут
подаваться 3 числа. Первое из них описывает действие, которое нужно совершить над
числами (1 - означает сложение, 2 - вычитание, 3 - умножение, 4 - деление), а второе и
третье - сами числа, над которыми нужно произвести операцию. В случае, если
пользователь ввёл неверный номер операции, программа должна вывести “Invalid
operation”. Тогда алгоритм, решающий данную задачу, может быть описан следующим
образом:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int op;
double a, b;
double res;
cin >> op >> a >> b;
switch (op)
{
case 1:
{
res = a
cout <<
break;
}
case 2:
{
res = a
cout <<
break;
+ b;
res;
- b;
res;
Основы программирования (C++)
}
case 3:
{
res = a
cout <<
break;
}
case 4:
{
res = a
cout <<
break;
}
default:
{
cout <<
}
30
* b;
res;
/ b;
res;
"Invalid operation";
}
return 0;
}
Теперь если мы подадим на вход программе числа 1 12 3, то на выходе получим
15. Если подадим числа 2 12 3, то получим 9. Если дать на вход программе числа 3 12
3, то на выходе будет 36. А если подать числа 4 12 3, то программа выведет 4. Если же
первое число будет иное, например мы подадим на вход 7 12 3, то программа выведет
“Invalid operation”.
Таким образом мы рассмотрели, в каких случаях нам может быть полезен
оператор switch, а в каких нам нужно использовать оператор if.
Основы программирования (C++)
31
9. Точность вычислений
Все действия с действительными числами выполняются приближенно. Поэтому
два действительных числа никогда нельзя сравнивать на точное равенство. Мы будем
считать два числа равными, если они отличаются не больше, чем на некоторое
значение ε. Определение правильного ε — некоторое умение. Для справки: машинная
точность вычислений (машинное эпсилон) равно 1.19209e-07 для действительных
чисел одинарной точности и 2.22045e-16 для действительных чисел двойной точности.
Итак, если есть два действительных числа x и y, то мы считаем, что
x = y, если |x − y| < ε,
x != y, если |x − y| > ε,
x < y, если x < y − ε,
x <= y, если x < y + ε,
x > y, если x > y + ε,
x >= y, если x > y − ε.
В c++ есть возможность выводить ответ с определённым количеством знаков
после запятой. Для этого есть функция cout.precision():
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
double a = 5.0 / 3;
cout.precision(6);
cout << fixed << a;
}
Программа выведет 1.666667.
Число в скобках обозначает, сколько знаков должно идти после запятой.
Обратите внимание, что перед выводом числа a стоит манипулятор fixed. Если его
убрать и написать просто “cout << a;”, то вместо шести знаков после запятой будет
выведено всего 6 значащих знаков. В этом случае программа выведет 1.66667.
Основы программирования (C++)
32
10. Циклы
Теперь мы умеем выполнять простые операции в программе, а также
использовать операторы ветвления для того, чтобы программа по разному реагировала
на входные данные или изменения переменных. Но теперь возникает вопрос, что если
нам необходимо выполнять какое-то действие многократно? Мы можем скопировать
некоторую часть программы несколько раз. Но что, если нам надо, чтобы она
выполнялась сто раз? Тысячу? Миллион? Или что если мы заранее даже не знаем,
сколько раз эта часть программы должна выполняться.
Для решения этой проблемы в программировании есть циклы. Циклы позволяют
выполнять какую-то часть программы некоторое количество раз. Причём это количество
может быть разным, в зависимости от введённых пользователем данных или хода
выполнения программы.
Чаще всего используются циклы for и while. Рассмотрим каждый из них.
Для рассмотрения цикла for сформулируем следующую задачу. Пусть нам
необходимо написать программу, которая выводит все натуральные числа от 1 до n,
причём значение n пользователь вводит сам. Мы могли бы с помощью оператора if или
switch предусмотреть все возможные значения n. Но таких значений слишком много,
написание программы займёт огромное количество времени, а её объём будет слишком
большой. Поэтому для решения данной задачи разумнее будет использовать циклы.
Для начала рассмотрим конструкцию цикла for. Он имеет следующий вид:
for ([Объявление переменной]; [Условие]; [Изменение переменной])
{
[Повторяющееся действия]
}
В [Объявление переменной] чаще всего объявляют так называемую индексную
переменную. Объявление индексной переменной происходит как и объявления всех
других переменных, и обычно она имеет тип int. Но это поле можно оставить пустым,
если переменная была объявлена до цикла (первая точка с запятой в этом случае всё
равно сохраняется, просто перед ней ничего не будет написано). Кстати, обычно для
индексных переменных в первую очередь выбирают буквы i, j, k. Но это никак не влияет
на работу программы.
В [Условие] должно быть описано некоторое выражение, возвращающее либо
true, либо false (как и в случае с оператором if). Цикл будет повторяться пока это
выражение истинно. Как только оно станет ложно, цикл прекратит работу. Обычно
истинность этого выражения зависит от текущего значения индексной переменной.
В [Изменение переменной] обычно описывают то, как должна изменяться
индексная переменная с каждым повторением цикла. Например, если у нас была
переменная int i = 0, то написав в последнем поле i = i + 1, с каждым повторением
цикла она будет увеличиваться на единицу. Стоит отметить, что мы можем сократить
выражение, записав вместо i = i + 1 более короткий вариант i++. В обоих случаях
переменная будет увеличена на единицу.
Основы программирования (C++)
33
Далее, внутри фигурных скобок, описываются действия, которые должны
повторяться.
Вернёмся теперь к нашей задаче. Нам нужно вывести все числа от 1 до n.
Попробуем описать это, используя цикл for:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
cout << i << " ";
}
return 0;
}
В примере выше, в цикле for мы объявили индексную переменную - i. С каждой
новой итерацией (повторением действий в цикле), она увеличивается на 1. Таким
образом, переменная i будет принимать значения 1, 2, 3, … , n. То есть, если n = 5, то i
будет поочерёдно принимать значения 1, 2, 3, 4, 5.
Далее, внутри цикла, мы выводим текущее значение переменной i, а затем
пробел (чтобы выходной файл был более читабельным). Стоит отметить, что вы
можете использовать индексную переменную внутри цикла как угодно. В том числе, её
можно использовать для вычисления каких-либо других значений, или изменять само
её значение. Главное помнить, что при каждой новой итерации цикла, индексная
переменная изменяется в соответствии с правилом, описанным в for.
Теперь рассмотрим другую задачу. Пользователь вводит натуральное число, и
нам необходимо вывести сумму его цифр. Один из способов разбить число на цифры это вычислять остаток от деления числа на 10 (это будет последняя цифра числа), а
затем делить число на 10. Далее повторяем эти действия, пока число больше 0. То есть,
если у нас было число 23, то последовательность действий будет следующая:
1. Остаток от деления 23 на 10 равен 3. Это число мы можем запомнить или
прибавить к переменной, хранящей сумму цифр.
2. Далее делим 23 на 10. Получим число 2 (вспоминаем, как происходит деление
целого числа на целое).
3. Теперь считаем остаток деления 2 на 10. Это будет 2. Запоминаем или
прибавляем это число к сумме.
4. Делим 2 на 10. Получаем 0.
5. На этом этапе наша программа должна завершить работу, так как число стало
равно 0.
Основы программирования (C++)
34
Поскольку заранее мы не знаем количество разрядов в числе, то задачу
логичнее решать при помощи циклов. Но в данном случае, условие для цикла for
довольно неочевидно. Было бы удобнее выполнять данные действия, пока число не
равно 0. Для этих целей есть цикл while. Дословно “while” переводится как “пока”.
Данный цикл имеет следующую конструкцию:
while ([Условие])
{
[Повторяющееся действия]
}
В [Условие] пишется логическое выражение, которое может возвращать true или
false (как и в случае с if и for). Пока это выражение истинно, будут выполняться
[Повторяющиеся действия]. Как только выражение станет ложным, цикл прекратит
работу и программа продолжит своё выполнение.
Стоит отметить, что условие обычно зависит от переменных, изменяющихся
внутри цикла, и эти изменения рано или поздно приведут к тому, что выражение станет
ложным. В противном случае, программа будет выполняться бесконечно.
Вернёмся теперь к задаче. Используя цикл while, попробуем написать её
решение:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
cin >> n;
int sum = 0;
while (n > 0)
{
sum += n % 10;
n /= 10;
}
cout << sum;
return 0;
}
Сначала программа считает переменную n из входного файла. Далее, пока n
больше, чем 0, она будет отделять по одной цифре с конца и прибавлять её к
переменной sum, хранящей в себе сумму цифр числа. Когда число станет равно 0,
Основы программирования (C++)
35
программа выведет ответ и завершит работу. Например, для числа 436 ответом будет
13.
И так, мы познакомились с циклом while. Хочется отметить, что в c++ есть
похожий цикл do while, который имеет конструкцию:
do
{
[Повторяющееся действия]
}
while ([Условие])
Он отличается от цикла while только тем, что проверяет условие после
выполнения [Повторяющихся действий]. То есть цикл сначала совершает работу, а
потом проверяет условие. Если оно истинно, но цикл повторяется снова, в противном
случае - цикл прекращает работу. Таким образом цикл do while в любом случае хоть
раз выполнит последовательность действий, описанных в нём.
Основы программирования (C++)
36
11. Массивы
Мы умеем создавать переменные разных типов. Но часто возникает
необходимость, хранить большой объём однотипных значений. Например,
пользователь вводит 10 чисел, и нам необходимо запомнить каждое, чтобы проделать
с ними какие-либо операции. Мы можем создать 10 переменных. Но это неудобно,
особенно когда количество вводимых значений становится очень большим или не
определено заранее в принципе. Для решения этой проблемы в c++ существуют
массивы. Массив - это совокупность значений одного типа, каждое из которых
расположено в своей ячейке. В одном массиве мы можем хранить большое количество
таких значений, каждому из которых будет присвоен свой номер - индекс. И по этому
индексу мы всегда можем узнать, что записано в той или иной ячейке.
Чтобы лучше представить, что такое массив, вообразим себе такую картину: у
нас есть шкаф, в котором по порядку расположены ящики. У каждого ящика свой номер:
1, 2, 3, и т. д. Мы можем открыть любой ящик и положить туда что-то. И зная номер
ящика, в который мы положили предмет, его можно будет всегда забрать. Таких
предметов может быть очень много, но тем не менее - это всё один шкаф.
Давайте теперь посмотрим, как объявляются массивы в C++:
int a[100];
Int - это тип данных, которые будут храниться в массиве. В данном случае, мы
будем использовать только целочисленные значения. Учтите, что все ячейки массива
будут иметь такой тип. Массив может быть и других типов данных - char, double и т. д..
Далее идёт название массива. В нашем случае - a. Название массива должно
отвечать тем же критериям, что и название простых переменных (см. Переменные).
Потом, в квадратных скобках, мы указываем сколько элементов могут храниться
в массиве. В нашем случае - 100. После объявления массива мы ставим точку с запятой.
Мы создали массив, но пока что он пустой. Давайте попробуем записать в него
какое-нибудь значение. Сделать это можно следующим образом:
a[5] = 54;
Теперь в ячейку с индексом 5 будет записано значение 54. Учтите, что значение,
которое мы записываем в массив, должно соответствовать типу данных этого массива.
То есть в массив типа int мы записываем целочисленные значения.
Важно: Нумерация ячеек массива начинается с 0! Это означает, что если мы
создали массив на 100 элементов (как в примере выше), то индексы ячеек будут равны
0, 1, 2, 3, … , 97, 98, 99. Аналогично будет и с другим размером массива.
Кстати, мы могли бы заполнить массив сразу при его объявлении. Это можно
сделать так:
int a[5] = { 1, 4, 6, 0, -4 };
Основы программирования (C++)
37
В этом случае, после квадратных скобок мы не ставим точку запятой, а
прописываем знак “=” и после него, в фигурных скобках, пишем все значения ячеек
массива. Теперь в ячейке с индексом 0 будет число “1”, в ячейке 1 будет число “4“, в
ячейке 2 - число “6”, в ячейке 3 - число “0” и в ячейке 4 - число “-4”.
Давайте теперь решим такую задачу: пользователь вводит натуральное число N
- количество элементов, а затем N целых чисел - сами элементы. Мы должны вывести
эти числа в обратном порядке. То есть если пользователь введёт “4 1 2 3 4”, то
программа должны вывести “4 3 2 1”. Для решения этой задачи воспользуемся
массивами и циклами:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
int a[1000];
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
for (int i = n - 1; i >= 0; i--)
{
cout << a[i] << " ";
}
return 0;
}
В данной программе мы объявили переменную n - количество элементов, а
затем массив на 1000 элементов (элементов могло быть и больше, но для
демонстрации этого вполне хватит). Далее мы считываем n, а затем считываем n чисел
- каждое записывается в отдельную ячейку массива. Обратите внимание, как работает
цикл. Индексная переменная i проходит все значения от 0 до n - 1 (итого получается
равно n значений), причём по порядку. Эту же индексную переменную мы используем и
для заполнения массива. При каждой новой итерации цикла, мы обращаемся к новой
ячейке массива - с индексом, большим на 1 чем предыдущий. То есть в ячейки массива
с индексами 1, 2, 3, … , n-1 будут записаны все введённые пользователем числа по
порядку. Заметьте, что считывание числа в конкретную ячейку массива при помощи
команды cin происходит так же, как и считывание числа в переменную.
Во втором цикле индексная переменная принимает значения от n-1 до 0
(обратите внимание, как выглядит условие цикла и правило изменения переменной i).
Это значит, что мы пробежимся по всем элементам массива в обратном порядке. Далее,
с помощью команды cout мы выводим значение ячейки массива с индексом i. Таким
Основы программирования (C++)
38
образом, все элементы массива будут выведены в обратном порядке, что нам и
требовалось сделать.
Отметим, что количество элементов массива - константа. Её нельзя изменять
внутри программы или же вместо константы подставлять переменные. Но вам никто не
запрещает создавать массивы с запасом, а потом использовать только его часть.
Ограничения на максимальное количество элементов обычно даётся вместе с условием
задачи.
Основы программирования (C++)
39
12. Символы. Строки
В предыдущих разделах мы уже упоминали о таком типе, как char. В переменных
этого типа можно хранить символы ASCII. В данной кодировке каждом символу
присвоен свой номер. Например, у символа “A” номер равен 65. Переменная типа char
объявляется так же, как и целочисленная - “char x;”. Теперь мы можем записать в эту
переменную какой-либо символ: “x = ‘P’;”. Обратите внимание, символ записывается в
одинарных кавычках. В переменную этого типа также можно считывать данные,
используя “cin >> x;” (в этом случае считывается только один символ из входного
файла), и выводить её значение в выходной файл: “cout << x;”.
Для примера, напишем программу, решающую следующую задачу.
Пользователь вводит символ, а программа должна вывести его номер в таблице ASCII.
Как было сказано в разделе “Перевод из одного типа данных в другой”, чтобы узнать
номер символа, достаточно присвоить его переменной типа int. Решение выглядит
следующим образом:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
char x;
cin >> x;
int a = x;
cout << a;
return 0;
}
Сначала мы объявили переменную типа char, затем считали введённый
пользователем символ. Потом приравняли эту переменную типа char к переменной
типа int. Теперь в этой переменной хранится номер символа в таблице ASCII. Этот
номер мы и выводим в выходной файл.
Мы могли бы обойтись и без целочисленной переменной, если бы изменили
программу следующим образом:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
char x;
cin >> x;
Основы программирования (C++)
40
cout << (int) x;
return 0;
}
В таком варианте, поставив “(int)” перед переменной x, мы дали понять
компилятору, что хотим, чтобы он обработал данную переменную как целое число.
Поэтому в выходной файл также будет напечатан номер символа.
Мы знаем, как хранить один символ. Но как быть, если нам захочется сохранять
в программе слова, предложения, наборы символов или, проще говоря, строку? Для
этого в c++ есть такой тип переменных, как string (дословно - “строка”).
Перед тем, как использовать данный тип, нам необходимо после строчки
“#include <iostream>” добавить строку “#include <string>”. Тем самым мы подключим
библиотеку, позволяющую нам работать со строками. Как теперь их использовать?
Рассмотрим небольшую программу:
#include <iostream>
#include <string>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
string s;
cin >> s;
cout << s;
return 0;
}
Данная программа из входного файла считает строку, а потом выведет её в
выходной файл. Например, если мы дадим на вход “abc”, то в выходном файле будет
так же напечатано “abc”.
Стоит отметить, что на самом деле строка не что иное, как массив char’ов.
Поэтому мы можем обратиться к конкретному символу в строке так же, как и к ячейке
массива. Например, если у нас есть строка “string s = “abcd”;”, то при использовании
команды “cout << s[2];” в выходной файл будет напечатан символ “c” (помните, что
нумерация массива начинается с 0). Также обратите внимание, что в отличии от
символов, строки записываются в двойных кавычках.
Вы всегда можете узнать длину строки, использовав функцию length().
Например, если вы напишите “int a = s.length();”, где s - какая-то строка, то в
переменную a будет записана её длина.
К строке можно добавлять символы. Например, если есть строка “string s =
“abc”;”, и мы прибавим к ней символ: “s += ‘d’;”, то в итоге в строке s будет записано
“abcd”.
Основы программирования (C++)
41
Аналогично, мы можем прибавлять к строке строку. Если есть строки s1 = “abc”
и s2 = “def”, то написав в программе “s1 += s2;”, мы получим строку “abcdef”,
записанную в переменную s1.
Давайте теперь рассмотрим такую задачу. Пользователь вводит строку.
Программа должна для каждого символа строки вывести его номер в ASCII через
пробел. Решить эту задачу можно следующим образом:
#include <iostream>
#include <string>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
string s;
cin >> s;
for (int i = 0; i < s.length(); i++)
{
cout << (int) s[i] << " ";
}
return 0;
}
В данной программе мы объявили переменную s типа string. Далее записали в
неё данные из входного файла (заметьте, что string из входного файла считывает набор
символов до пробела. Например, если входной файл имел вид “abc def”, то в
переменную s будет записано только “abc”). Затем в цикле мы проходимся по всем
символам в строке, обращаясь к ним как к ячейке массива. Каждая такая ячейка в строке
имеет тип char, поэтому, как и в предыдущей задаче, мы выводим номер этого символа
просто приписав (int) перед s[i].
Таким образом, в c++ вы можете работать с символами, строками, а также
переводить эти типы данных в другие.
Основы программирования (C++)
42
13. Двумерные массивы
В предыдущих главах мы познакомились с массивами. Они представляли из
себя набор значений, идущих по порядку. Иначе говоря, это были одномерные массивы
(так как двигаться по ним мы могли только вдоль одного направления).
Зачастую есть необходимость использовать двумерные массивы. Например, как
нам представить в программе шахматную доску, где в каждой клетке стоит
определённая фигура? Мы можем записывать всё в одномерный массив длиной в 64
ячейки (если доска 8х8), присвоив каждой какую-то клетку доски. Но с этим неудобно
работать. Легче использовать двумерные массивы.
Двумерный массив можно представить как тетрадный лист, каждой клетки
которой присвоены два числа - индексы по горизонтали и вертикали. В эти клетки мы
можем записывать какие-либо значения (в соответствии с типом массива), а потом,
используя эти два индекса, обращаться к той или иной клетке.
Двумерные массивы объявляются так же, как и одномерные, за исключением
того, что к ним добавляется ещё одни квадратные скобки:
int a[10][30];
В данном примере мы создали массив, размером 10 на 30 ячеек. Теперь мы
можем обратиться к любой его ячейке следующим образом:
a[5][2] = 57;
Теперь в ячейке {5, 2} будет записано число 57. Аналогичным способом мы
можем получить значение конкретной ячейки:
cout << a[5][2]; // В выходной файл будет напечатано число 57
Давайте рассмотрим, как считать матрицу из входного файла в двумерный
массив, а затем вывести её:
#include <iostream>
#include <string>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int a[5][5];
for(int i = 0; i < 5; i++)
{
Основы программирования (C++)
43
for(int j = 0; j < 5; j++)
{
cin >> a[i][j];
}
}
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 5; j++)
{
cout << a[i][j] << " ";
}
cout << endl;
}
return 0;
}
В данном случае мы использовали вложенные циклы чтобы обойти всю
матрицу. У нас есть две индексные переменные, и можно сказать, что переменная j
отвечает за движение по горизонтали, а переменная i - по вертикали. Но заметьте, что
пока переменная j не пройдёт все значение от 0 до 4, переменная i не изменится. А
после того, как значение i увеличится на 1, значение j снова станет равно 0. Таким
образом, обход массива выглядит следующим образом:
Следующие два цикла аналогичны первым двум. Они проходят по массиву в том
же порядке и выводят значения его ячеек. Таким образом, входной и выходной файл
будут выглядеть следующим образом:
Основы программирования (C++)
44
Ввод пользователя
1
2
3
6
7
8
11
12
16
17
Вывод программы
4
5
1
2
3
9
10
6
7
8
9
10
13
14
15
11
12
13
14
15
18
19
20
16
17
18
19
20
21 22 23 24 25
4
5
21 22 23 24 25
Матрицу можно обходить любым способом, а не только описанным выше. Для
этого нужно будет изменить порядок индексных переменных или правила,
описывающие их изменения. Можете поэкспериментировать с этим на досуге и
посмотреть, что получится, если во вторых двух циклах поменять местами переменные
i и j в массиве (написать “cout << a[j][i];”). Вывод программы в этом случае будет
выглядеть как:
Ввод пользователя
1
2
3
6
7
8
11
12
16
17
21 22 23 24 25
Вывод программы
4
5
1
6
11
16
21
9
10
2
7
12
17
22
13
14
15
3
8
13
18
23
18
19
20
4
9
14
19
24
5 10 15 20 25
Как и одномерные массивы, двумерные могут иметь любой тип. Мы точно так же
можем создать двумерный массив типов char, double и других.
Основы программирования (C++)
45
14. Процедуры и функции, глобальные переменные
Часто бывает, что программе нужно исполнять один и тот же набор действий
несколько раз, причём это может быть необходимо сделать в разных местах кода. Для
уменьшения объёма программы мы можем выносить такой повторяющийся код в
процедуры и функции. Процедуры и функции могут вызываться по ходу программы,
производить вычисления или изменять переменные. Также они могут принимать на
вход некоторые значения и выполнять действия над ними. Функция отличается от
процедуры тем, что после выполнения своей работы она должна вернуть какое-то
значение. То есть вызвав функцию где-то в программе, мы можем получить от неё ответ
(например, результат каких-либо вычислений) и использовать его далее. Процедура же
просто выполняет операции с данными и ничего не возвращает. Однако результатом
этих операций может быть, например, изменение какой-то переменной, массива, запись
в файл и многое другое.
Объявить функцию можно следующим образом:
int foo(int a, char b)
{
[Действия]
return [Значение или переменная типа int].
}
Перед названием функции пишется её тип. Значение этого типа должна вернуть
функция после выполнения всех операций. В нашем случае функция имеет тип int, но
можно объявить функцию любого типа - double, bool, char и т. д.
Далее идёт название функции (оно не может начинаться с числа). Потом, в
круглых скобках, через запятую перечисляются все переменные, которые функция
принимает на вход. Они могут быть любыми и их может быть любое количество или не
быть вовсе. Этими переменными функция может оперировать.
После этого, в фигурных скобках, описываются действия, которые совершает
функция. Это может быть любой набор операций: циклы, условия, выражения и т. д.
Затем в функции обязательно должна идти команда return и некоторое
значение, которое будет возвращено. Это может быть переменная, результат работы
функции, константа. Но тип возвращаемого значения должен совпадать с типом
функции.
На самом деле, команда return может быть вызвана и до завершения всех
операций (например, при срабатывании какого-либо условия). Это приведёт к
немедленному завершению работы функции. Но следите за тем, чтобы вне
зависимости от хода выполнения действий, функция в любом случае что-то
возвращала.
Процедуры имеют подобную структуру. Но перед названием пишется тип void
(пустота), а return внутри процедуры писать не нужно (ведь она ничего не возвращает).
Процедура тоже может принимать некоторые значения или не принимать их вовсе.
Основы программирования (C++)
46
void foo(int a, char b)
{
[Действия]
}
Процедуры и функции объявляются в коде до функции main. То есть код будет
иметь следующую структуру:
#include <iostream>
using namespace std;
void foo (int a, char b)
{
[Действия]
}
int bar (int a)
{
[Действия]
return a;
}
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int a = 1;
char b = 'c';
foo(a, b);
int c = bar(a);
cout << c;
return 0;
}
Чтобы вызвать процедуру или функцию в коде, достаточно прописать её
название, а затем в скобках указать передаваемые значения через запятую
(рассмотрите действия, описанные в функции main выше). Как видите, мы можем
записать в переменную значение, которое вернёт функция: “int c = bar(a);”. В нашем
случае, в переменную c будет записано то, что вернёт функция bar().
Как вы могли заметить, переменные, которые объявляются внутри функций и в
круглых скобках имеют одинаковое название. Например, в функциях main, foo и bar
есть переменная int a. Тем не менее, в программе они все будут восприниматься как
разные переменные и могут иметь различные значения. Это локальные переменные
функции или процедуры, и использовать мы их можем только внутри этой функции
или процедуры. Например, в процедуре bar не объявлена переменная b. И если мы
Основы программирования (C++)
47
попробуем использовать её внутри bar, то получим ошибку, даже не смотря на то, что
b объявлена в другой функции.
Возникает логичный вопрос. Можно ли создать переменные, которые возможно
использовать во всех функциях и процедурах? Ответ - можно. Но это должны быть
глобальные переменные.
Глобальные переменные объявляются вне процедур и функций. Например,
после строки “using namespace std;”. Потом эти переменные можно использовать
внутри любых функций и процедур, притом они будут сохранять своё значение после
выполнения операций над ними:
#include <iostream>
using namespace std;
int a = 1;
void foo ()
{
a += 1;
}
int bar ()
{
a += 1;
return a;
}
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
foo(); // После вызова этой процедуры, переменная "а" будет равно 2;
int c = bar(); // Функция вернёт "3", ведь переменная "a" была увеличена
ранее
cout << c << endl; // В выходной файл будет выведено "3"
cout << a; // В выходной файл также будет выведено "3", так как
переменная “a” сохраняет своё изменённое значение
return 0;
}
Обратите внимание, что глобальная переменная должна быть объявлена
обязательно до функции или процедуры, в который вы хотите её использовать. Иначе
вы получите ошибку, что данная переменная ещё не была создана.
Массивы тоже можно создавать глобально. При этом максимальное количество
ячеек, которое можно объявить, будет больше, а все эти ячейки автоматически
заполнятся нулями. Это бывает удобно, и часто ограничения в задаче требую
глобального объявления массивов. Глобально объявлённые массивы также можно
использовать как угодно, значения ячеек будут сохраняться.
Основы программирования (C++)
48
Стоит отметить, что не следует называть локальные переменные тем же
именем, что и глобальные. Тогда, в отличии от ситуации, когда в различных функциях
локальные переменные имеют одинаковое название, возникнет неоднозначность.
Компилятор не знает, какую из переменных вы хотите использовать: локальную или
глобальную, и вернёт вам ошибку.
Давайте теперь напишем простую функцию, которая возвращает наибольшее из
двух передаваемых ей целых чисел. Она может выглядеть следующим образом:
int maximum (int a, int b)
{
if (a > b)
return a;
else
return b;
}
Заметьте, что в данной функции команда return встречается дважды. И в не
зависимости от хода выполнения алгоритма функции, она вернёт целое значение.
Теперь мы можем вызывать эту функцию в main, либо других процедурах и
функциях.
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
cout << maximum(5, 7); // Выведет "7"
return 0;
}
Важно: как и в случае с глобальными переменными, функции и процедуры
необходимо объявлять перед теми процедурами и функциями,, в которых вы хотите её
использовать. Иначе вы получите ошибку, что такой процедуры или функции не
существует.
Основы программирования (C++)
49
15. Рекурсия
Рекурсия в общем смысле - это описание, изображение, определение какоголибо объекта или процесса внутри этого же объекта или процесса. Одним из примеров
рекурсии является песня про попа:
У
попа
была
собака,
он
её
любил,
Она
съела
кусок
мяса,
поп
её
убил,
В
землю
закопал,
И надпись написал о том, что
"У
попа
была
собака,
он
её
любил,
Она
съела
кусок
мяса,
поп
её
убил,
В
землю
закопал,
И
надпись
написал
о
том,
что:
…
Другой способ понять рекурсию - это попробовать коктейль “рекурсивный”: вам
нужно смешать 30% воды, 20% апельсинового сока и 50% коктейля “рекурсивный”.
В программировании рекурсия - это когда процедура или функция вызывает
саму себя. Простой пример рекурсии выглядит так:
void foo()
{
foo();
}
Теперь, если мы сделаем в программе вызов foo(), то процедура сделает вызов
самой себя. Этот вызов приведёт к следующему вызову, тот ещё к одному и так деле…
Эти вызовы будут продолжаться бесконечно. Но на практике, вы просто получите
ошибку переполнения стека. Чтобы это не происходило, в рекурсии должно быть
условие выхода. Например:
int g = 0;
void foo()
{
if(g < 10)
{
g++;
foo();
}
}
Теперь если мы вызовем процедуру foo(), то рекурсивные вызовы будут
продолжаться, пока переменная g не станет равна 10. После того, как переменная
Основы программирования (C++)
50
достигнет этого значения, условие в операторе if перестанет быть верным и нового
вызова процедуры не последует.
Кстати, при рекурсивных вызовах процедуры или функции вы также можете
передавать ей на вход некоторые значения, оперировать ими, а потом снова давать на
вход при следующем рекурсивном вызове:
int foo(int g)
{
if(g < 10)
{
g++;
g = foo(g);
}
return g;
}
Теперь если мы сделаем вызов foo(0), то запустится цепочка рекурсивных
вызовов, которая в конечном итоге приведёт к тому, что функция вернёт значение “10”.
Заметим, что в функции, пока рекурсивный вызов не завершится, дальнейшие
операции выполняться не будут. То есть, если рассматривать пример выше, сначала
программа пройдёт по всей цепочке рекурсивных вызовов, уходя всё глубже и глубже,
и лишь затем дойдёт до return g. Причём когда условие станет ложным, то рекурсивно
вызванные экземпляры функции будут заканчивать свою работу в обратном порядке.
Легче всего это представить в виде лестницы: каждая новая ступенька вниз - это
рекурсивный вызов. Когда мы дойдём до самого низа, то начнём подниматься вверх в
обратном порядке.
Решим теперь такую задачу. Необходимо вывести n-ное число Фибоначчи по
порядку, причём значение n пользователь вводит сам. Ряд Фибоначчи имеет
следующий вид:
0 1 1 2 3 5 8 13 21 34 …
В нём первое число равно 0, второе число равно 1, а каждое следующее число
является суммой двух предыдущих. Поэтому, если пользователь введёт, например, “4”,
то мы должны вывести число “2”.
Основы программирования (C++)
51
Рекурсивное решение данной задачи выглядит следующим образом:
#include <iostream>
using namespace std;
int
{
foo(int
if(g
g)
==
1)
0;
2)
1;
return
if(g
==
return
return
foo(g
-
1)
+
foo(g
-
2);
}
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
cin >> n;
cout << foo(n);
return 0;
}
Если в функцию foo передать число 1, то она вернёт 0 (первое число Фибоначчи).
Если передать число 2, то она вернёт 1 (второе число Фибоначчи). Если мы дадим
функции числа 3, 4, 5 и т. д., то последуют два рекурсивных вызова функции foo,
которые вернут предыдущие два числа. Эти вызовы будут продолжаться, пока мы не
дойдём до первого и второго числа Фибоначчи. Далее каждый вызов будет возвращать
сумму двух предыдущих чисел, и в итоге мы получим нужное нам число. Попробуйте
проследить эту цепочку вызовов для различных значений.
Основы программирования (C++)
52
16. Структуры данных
Бывают случаи, когда при решении задачи нам нужно запоминать несколько
различных значений для некоторого объекта. Мы можем использовать одномерный
массив, где эти значения хранятся в разных ячейках, или двумерный массив, если таких
объектов много (тогда первый индекс массива может отвечать за номер объекта, а
второй - за конкретное значение из набора). Но это подходит только для тех случаев,
когда все такие значения одного типа. А что делать, если для конкретного объекта мы
одновременно хотим запомнить значения типов char, int, double и других? Например,
для решении задачи нам нужно помнить имена студентов, их группы и средний балл за
экзамены? Мы можем создать несколько массивов разных типов, где под одинаковыми
индексами мы будем запоминать эти данные для одного студента. Но это не очень
удобно. Гораздо удобнее в этих случаях использовать структуры.
Структура - это объединение нескольких переменных, массивов или даже других
структур. Они могут быть все разного типа. Этому объединению мы присваиваем имя,
и дальше можем создавать объект структуры как обычные переменные. Создание
структуры выглядит следующим образом:
struct baz
{
char a;
int b[100];
double c;
};
Объявлять структуры мы можем как глобально, так и локально. Сначала мы
пишем struct, затем название нашей структуры. В примере выше она будет называться
baz. Потом идут фигурные скобки, где мы описываем все переменные, входящие в
состав структуры. После фигурных скобок ставим точку с запятой.
Теперь мы можем создать объект структуры типа baz:
baz x;
Всё, объект структуры создан. Теперь мы можем обратиться к переменным,
входящим в состав структуры, чтобы записать в них значения:
x.a = 's';
x.b[5] = 45;
x.c = 5.3;
Или получить значения этих переменных:
Основы программирования (C++)
53
int d = x.b[5];
cout << d << endl;
cout << x.a;
Также мы можем создать структуру, в состав которой входит другая структура, и
обращаться к переменным, входящим в них:
struct bar
{
int a;
baz b; // Созданная ранее структура
};
bar.a = 16;
bar.baz.c = 5.24;
cout << bar.a << " " << bar.baz.c; // Выведет "16 5.24"
Мы можем создавать массивы структур, и обращаться к переменным структуры
в конкретной ячейке массива:
baz m[10];
m[4].a = 'v';
m[5].b[1] = 45;
cout << m[4].a;
А так же, создав два разных объекта структур, мы можем приравнять один к
другому:
baz s1;
baz s2;
s1.a = 'v';
s2 = s1;
cout << s2.a; // Выведет "v", т.к. все данные из s1 записались в s2;
Аналогично мы можем создать массив структур, и приравнивать одну его ячейку
другому. Значения всех переменных будут переписаны в эту ячейку:
baz s[10];
s[0].c = 5.23;
s[0].b[1] = 34;
s[1] = s[0]; // Все значение из s[0] перепишутся в s[1]
Для чего ещё могут быть полезны структуры? Например, при решении
геометрических задач. Мы можем создать структуры, описывающие точку и прямую на
координатной плоскости:
Основы программирования (C++)
54
struct point
{
double x; // Координата X
double y; // Координата Y
};
struct line
{
double A;
double B;
double C; // Коэффициенты уравнения прямой на плоскости
};
А потом написать функцию, которая будет принимать две точки плоскости, а
возвращать линию, которая через них проходит:
line foo (point p1, point p2)
{
line l;
l.A = p1.y - p2.y;
l.B = p2.x - p1.x;
l.C = p1.x * p2.y - p2.x * p1.y;
return l;
}
Теперь мы можем создать две точки и передать их в функцию, которая вернёт
нам линию:
point a, b;
a.x
a.y
b.x
b.y
=
=
=
=
0;
0;
1;
1;
line c = foo(a, b); // Вернёт линию, где c.A = -1, c.B = 1, c.C = 0
Как видно из примера выше, созданная нами структура также может быть типом
функции.
Основы программирования (C++)
55
17. Указатели. Списки
Указатель - это переменная, которая хранит в себе адрес ячейки памяти. То есть
он ссылается на блок данных из области памяти, причём на самое его начало.
Указатель может ссылаться на переменную или функцию. Для этого нужно узнать их
адрес. Чтобы узнать адрес переменной, в C++ есть операция взятия адреса “&”. Эта
операция извлекает адрес переменной, которые можно присвоить указателю.
Указатели используются, чтобы передавать не сами данные, а ссылки на них.
Это ускоряет процесс их обработки (особенно, если объём данных большой), так как мы
их не копируем, как при передаче значения. Указатели можно использовать для
динамического распределения памяти. Например, при создании массива, не надо будет
его ограничивать в размере.
Создать указатель можно как и любую переменную:
int *pt;
Объявление указателей выглядит так же, как и объявление переменных. Только
перед его именем мы ставим знак “*”. Тип указателя должен быть таким же, как и тип
переменной, адрес которой он будет хранить. Напишем теперь небольшую программу,
чтобы разобрать работу с указателями:
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int a = 123;
int *pt;
pt = &a; // Получаем адрес ячейки памяти
cout << pt << endl; // Выведет адрес ячейки памяти
cout << *pt; // Выведет значение, которое хранится в этой ячейке памяти
(значение переменной a) - 123
return 0;
}
Вначале мы объявили переменную типа int и присвоили ей некоторое значение.
Затем мы объявили указатель такого же типа. Далее, используя операцию взятия
адреса “&”, мы получили адрес ячейки памяти и записали его в указатель (заметьте, что
знак “&” ставится перед переменной, адрес которой мы хотим узнать).
Далее в выходной файл мы вывели адрес ячейки памяти. Чтобы вывести
значение, которое в этой ячейке хранится, мы воспользовались операцией
разыменования указателя “*” (символ “*” ставится перед указателем).
Основы программирования (C++)
56
При желании, мы можем создавать указатели на указатели. При этом в ячейках
памяти, на которые будут ссылаться одни указатели, будут храниться адреса других
указателей.
int a = 123;
int *pt1 = &a;
int **pt2 = &pt1;
int ***pt3 = &pt2;
cout << ***pt3; // Выведет значение a - 123
При создании каждого нового указателя на указатель, количество знаков “*”
увеличивается. Это количество показывает порядок указателя. При этом, чтобы потом
получить значение, на которое ссылается указатель, нам необходимо разыменовать его
соответствующее количество раз.
При помощи указателей мы можем реализовать такую вещь, как списки.
Односвязный список - это динамическая структура данных, где каждый элемент имеет
указатель на следующий элемент. Если мы добавим ещё ссылку на предыдущий
элемент, то получим двусвязный список. В отличии от массива, в списке мы можем
динамически добавлять и удалять элементы, оперируя с указателями. Давайте
попробуем разобраться со списками на примере простой программы:
#include <iostream>
using namespace std;
struct item
{
int val;
item *next = NULL;
}
void AddItem(item *cur, int val)
{
item *newitem = new item;
newitem->val = val;
cur->next = newitem;
}
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
item *first = new item;
first->val = 1;
AddItem(first, 2);
item *second = first->next;
AddItem(second, 3);
item *third = second->next;
Основы программирования (C++)
57
cout << first->val << " " << second->val << " " << third->val;
// Выведет "1 2 3"
return 0;
}
Первым делом мы объявили структуру item - элемент списка. В этой структуре
мы создали переменные, которые должны быть в том элементе (в нашем случае int
val), и указатель на объект этой структуры, который мы будем считать следующим
элементом (item *next = NULL;). Заметьте, что мы с самого начала присвоили
указателю значение NULL, чтобы потом можно было понять - ссылается ли он на что-то
ещё, или это последний элемент списка.
Далее мы создали процедуру AddItem, которая добавляет в список новый
элемент. Эта процедура принимает на вход два значения - текущий элемент списка
(cur) и значение (val), которое должно быть записано в переменную val следующего
элемента. Внутри процедуры, при помощи команды new мы создаём новый объект
структуры item. После того, как под этот объект будет выделена ячейка памяти, команда
new вернёт ссылку на неё. Эту ссылку мы записываем в указатель item *newitem. Далее
в этот новый элемент списка мы записывает значение val. Обратите внимание, что для
доступа к переменной val структуры мы используем “->” вместо точки (как это было
раньше), потому что мы работаем не с объектом структуры, а с указателем на него.
Теперь нам остаётся лишь записать в текущий объект структуры ссылку на только что
созданный, следующий: “cur->next = newitem;”. Поскольку cur - не локальная
переменная, а указатель на некоторый объект структуры (ссылку на которую мы
передали в процедуру), то значение указателя next будет изменено у этого объекта
структуры. Всё, новый элемент создан.
Теперь, в функции main(), мы создаём первый элемент списка, и его адрес
записываем в указатель на этот элемент - first. В переменную val мы записываем
нужное нам значение. Далее мы создаём новый элемент списка и в указатель second
записываем ссылку на него. Обратите внимание, что после вызова процедуры
AddItem(), в указатель next первого элемента записалась ссылка на следующий,
которую мы можем получить при помощи “first->next”. Точно так же мы создаём третий
элемент списка, а затем в выходной файл выводим значение переменной val для
каждого элемента.
Заполнять список можно и при помощи цикла. Также вы можете написать
процедуры, для удаления элемента или добавления нового в середину списка. Списки
позволяют динамически создавать, удалять, менять элементы, что может быть полезно
при решении некоторых задач.
Основы программирования (C++)
58
18. Дебаг
Не всегда программа с первого раза работает так, как нам надо. И даже если
долго всматриваться в код, может быть не очевидно, где ошибка. Для этого в
большинстве сред разработки есть пошаговый дебаг (“Debug”). Этот процесс позволяет
увидеть шаг за шагом, как ведёт себя программа, как изменяются переменные и т. д.
Рассмотрим этот процесс в среде разработки Microsoft Visual Studio.
Первым делом надо надо указать точку входа в дебаг - брейкпоинт (“breakpoint”).
Именно в этой точке программа остановит свою работу, давая нам возможно пошагово
следить за выполнением операций. Чтобы сделать это, достаточно кликнуть на серую
полоску слева напротив нужной строчки, либо, находясь на этой строчке, нажать
клавишу F9. Слева появится красная точка.
Теперь мы можем запустить программу. Когда алгоритм дойдёт до этой строчки,
её выполнение приостановится. Если у вас появилось высплывающее окно, нажмите
“Да” (“Yes”).
Основы программирования (C++)
59
Теперь слева, на серой вертикальной полосе, появилась жёлтая стрелка. Она
указывает, какую именно строку программа сейчас должна выполнять. Находясь в
режиме дебага мы можем просматривать текущее значение переменных. Для этого
достаточно навести курсор на ту, которая нас интересует. Появится всплывающее
окошко со значением.
Нажав на иконку с канцелярской кнопкой в этом окошке, мы можем закрепить его
и переместить в любое удобное место. В этом окошке всегда будет показываться
текущее значение переменной, которое может обновляться по мере выполнения
программы.
Основы программирования (C++)
60
Также внизу, на вкладках “Видимые” (“Autos”) и “Локальные” (“Local”)
показываются названия и значения переменных текущей функции. Открыв вкладку
“Контрольные значения” (“Watch”) мы можем запросить значение переменных,
массивов и т. д. по их названию. Для этого кликните на левую часть пустой строки,
введите название нужной переменной и нажмите Enter.
Чтобы перейти на следующий шаг выполнения программы, вы можете нажать
клавиши F10 или F11 (или соответствующие кнопки на панеле инструментов сверху).
Причём, если вы нажмёте F11 находясь на строке, где вызывается функция или
процедура, то программа зайдёт в неё и покажет ход исполнения этой процедуры или
функции. Если же вы нажмёте F10, программа не будет заходить в процедуру и
функцию, а просто выполнит её и дебаг перейдёт на следующую строку.
Основы программирования (C++)
61
Вы можете создавать одновременно несколько брейкпоинтов. Если вы нажмёте
F5, программа продолжит своё обычное выполнение, пока не встретит очередной
брейкпоинт или не завершится.
Основы программирования (C++)
62
Дебаг - очень полезный инструмент в программировании. Он позволяет лучше
понять, как работает ваша программа и выяснить причину, по которой она делает чтото не так.
Основы программирования (C++)
63
19. Вместо эпилога
Данное руководство должно помочь вам сделать первые шаги в изучении C++.
Мы не можем рассмотреть все особенности данного языка, но знаний, которые вы
получили в результате его прочтения, вам хватит, чтобы начать решать задачи.
Некоторые моменты могут показаться трудными и непонятными. Но если вы будете
практиковаться, то со временем станете гораздо лучше понимать C++ и
программирование в целом.
Если у вас возникают трудности, то вы всегда можете обратиться к своему
преподавателю, либо попытаться найти решение проблемы в интернете. На сайте
https://msdn.microsoft.com/ru-ru/library/3bstk3k5.aspx имеется документация по всем
особенностям языка Visual C++.
Не бойтесь изучать что-то новое. Многие вещи в программировании
оказываются не такими страшными, как казалось на первый взгляд. Главное, чтобы у
вас было желание разобраться в этом.
Мы надеемся, что это руководство было полезно для вас. Желаем успехов в
изучении программирования!
Download