- •Часть 1
- •Практическое занятие 1. Работа в среде Microsoft Visual Studio
- •Проекты и решения
- •Создание консольного приложения
- •Отладка в Visual Studio
- •Отладка программ
- •Практическое занятие 3. Операции и выражения. Линейные программы Операции и выражения
- •Логические операции
- •Поразрядные (побитовые) операции
- •Практическое занятие 4. Разветвляющиеся алгоритмы
- •If (выражение) оператор_1 else оператор_2
- •Операции сравнения (отношения)
- •Тернарная (условная) операция
- •Выражение_1 ? выражение_2 : выражение_3
- •Практическое занятие 5. Организация циклов. Операторы цикла
- •Оператор while
- •Оператор do…while
- •Оператор for
- •Операторы передачи управления Оператор break
- •Оператор continue
- •Указатели
- •Инициализация указателей
- •Операции над указателями
- •Одномерные массивы
- •Практическое занятие 7. Двумерные массивы. Организация работы с динамической памятью Двумерные массивы
- •Динамические массивы
- •Практическое занятие 8. Структуры. Форматный ввод/вывод данных. Структуры в языке с
- •Форматный ввод/вывод данных в стиле языка с
- •Int printf(строка_форматир-я [, список_переменных]);
- •Int scanf(const char * строка_форматирования,
- •Практическое занятие 9. Функция. Способы передачи параметров в функцию.
- •Выход из функции
- •Прототип (описание, объявление) функции
- •Рекурсия
- •Передача параметров в функцию
- •Передача массивов в качестве параметров функции
- •Практическое занятие 10. Перегрузка функций. Шаблоны функций Перегрузка функций
- •Перегрузка и область видимости
- •Шаблоны функций
- •Прототип шаблона
- •Параметры шаблона, не являющиеся типами
- •Явная специализация шаблонной функции
- •Директива #include
- •Директива #define
- •Символических констант
- •Макроимён, управляющих условной компиляцией:
- •Препроцессорные операторы # и ##
- •Директива #undef
- •Директивы условной компиляции #if, #ifdef, #ifndef
- •Вспомогательные директивы
- •Практическое занятие 12. Поразрядные операции Операции с разрядами Машинное слово
- •Представление машинных слов в программе
- •Технология работы с машинными словами
- •Поразрядная операция и
- •Поразрядная операция или
- •Операция поразрядной инверсии
- •Поразрядная операция исключающее или
- •Операция сдвиг влево
- •Операция сдвиг вправо
- •Формы представления числовых данных Целое без знака
- •Представление отрицательных чисел Дополнительный код
- •Преобразование типов операндов в выражениях
- •Стандартные программные решения Преобразование типов операндов в выражениях
- •Подсчет количества единичных битов
- •Упаковка данных полями переменной длины
- •Машинная арифметика – целые произвольной точности
- •01000 Хххххххх 00011 ххх 10000 хххххххххххххххх 00000.
- •Практическое занятие 13. Пространства имен
- •Пространство имен std
- •Приложение 1. Простые алгоритмы сортировки одномерных массивов
- •Сортировка простыми обменами (пузырьковая)
- •Сортировка простыми вставками (прямого включения)
- •Приложение 2. Создание файла с результатами препроцессорной обработки в среде Visual Studio
- •Создание файла с результатами препроцессорной обработки из командной строки
- •Приложение 3. Использование генератора случайных чисел
- •Рекомендуемая литература
- •Содержание
Рекурсия
Рекурсивной называют функцию, которая в своём теле вызывает саму себя (прямая рекурсия). Когда две или более функций вызывают друг друга, возникает косвенная рекурсия.
Пример: вычисление факториала числа (0! = 1 и 1! = 1)
n
!
= 123(n–1)n
// Листинг 9.2
#include <iostream>
using namespace std;
int factorial(int); // Прототип функции
int main() {
int k = 4;
cout <<"k="<< k <<"; k! ="<< factorial(k) <<endl;
return 0; }
int factorial(int n) {
if (n < 0) {
cout << "ERROR!" << endl; return -1;
}
// Рекурсивный вызов
return (n > 1) ? n*factorial(n–1) : 1;
}
Каждое обращение к функции при рекурсии сопровождается организацией в стеке нового полного набора её локальных переменных и переданных ей параметров. Поэтому рекурсивными функциями следует пользоваться с осторожностью, оценивая глубину рекурсии (иначе возможно переполнение стека).
Очень важно при организации рекурсивных функций предусмотреть проверку условия выхода из рекурсии. Иначе можно «улететь» в бесконечную рекурсию. Любую рекурсивную функцию можно реализовать без использования рекурсии.
Достоинство рекурсии – компактная запись.
Недостатки рекурсии – расход времени и памяти на повторные вызовы функции и передачу ей копий параметров, а также опасность переполнения стека.
Передача параметров в функцию
При передаче параметров в функцию используется неявное преобразование типов в соответствии с существующей в языке иерархией типов:
bool, char, shortint;
floatdouble.
В заголовке функции можно указать значения параметров по умолчанию. Они должны быть последними в списке и могут опускаться при вызове функции. Если при вызове параметр опущен, должны быть опущены и все параметры, стоящие в списке за ним.
В качестве значений параметров по умолчанию могут использоваться константы, глобальные переменные, выражения.
Например,
int f1(int x, int y = 0);
void f2(int, int = 20, char * = 0);
i
nt
a = 15;
// Вызовы функций:
f1(5); // x = 5, y = 0
f1(a, 1); // x = a, y = 1
f2(a); // 1-й параметр = a, 2-й = 20, 3-й = 0
f2(a, 10); // 1-й параметр = a, 2-й = 10, 3-й = 0
f2(7, 100, "text"); // 1-й параметр = 7, 2-й = 100,
// 3-й = указателю на строку "text"
// f2(a, , "text"); неверно: поскольку опущен 2-й
// параметр, должен быть опущен и 3-й.
В языке С++ имеются два способа передачи параметров в функцию – передача по значению и передача по ссылке (или по указателю). Когда параметр передаётся по значению, создаётся копия параметра, и она передаётся вызываемой функции. Изменения копии не влияют на значение параметра-оригинала в операторе вызова. Параметр, переданный в функцию по значению, является локальной переменной этой функции. В случае передачи по ссылке оператор вызова даёт вызываемой функции возможность прямого доступа к передаваемым данным, а также возможность изменения этих данных.
Язык С++ снабжён двумя средствами для передачи по ссылке.
Первый способ – передача по ссылке с аргументами-ссылками (стиль языка С++). Ссылочный параметр – это псевдоним (синоним имени) соответствующего аргумента. Чтобы показать, что параметр функции передан по ссылке, тип формального параметра в определении и прототипе функции задаётся с использованием символа амперсанда &. В вызове функции достаточно указать имя переменной, и она будет передана по ссылке. Тогда упоминание в теле вызываемой функции переменной по имени её параметра в действительности является обращением к области памяти с исходной переменной в вызывающей функции, и значение этой исходной переменной может быть изменено непосредственно вызываемой функцией.
Например, так в этом случае будет выглядеть функция, предназначенная для того, чтобы обменять значениями переданные ей аргументы:
void swap1(int & a, int & b) { // Передаются ссылки
int temp = a;
a = b;
b = temp;
}
Вызов этой функции:
int x = 5, y = 11;
swap1(x, y); // Аргументы передаются по ссылке
cout << "x=" << x << " y=" << y << endl; //x=11 y=5
Второй способ – передача по ссылке с аргументами-указателями (стиль языка С). Указатели, подобно ссылкам, также можно использовать для модификации одного или более значений переменных в вызывающем операторе, или передавать указатели на большие объекты данных, чтобы избежать накладных расходов (при создании копий), сопутствующих передаче объектов по значению. При вызове функции с аргументами, которые должны быть модифицированы, передаются адреса аргументов. Это обычно сопровождается операцией & получения адреса переменной, которая должна быть модифицирована. При передаче функции адреса переменной в теле функции может использоваться операция * (косвенной адресации или разыменования) для модификации значения ячейки в памяти вызывающего оператора.
В этом случае аналогичная функция будет выглядеть так:
void swap2(int *pa, int *pb){//Передаются указатели
int temp = *pa; // К указателям применяется
*pa = *pb; // операция разыменования *
*pb = temp;
}
а её вызов так:
int x = 5, y = 11;
swap2(&x,&y);//Использ-ся операция получения адреса
cout << "x=" << x << " y=" << y << endl; //x=11 y=5
