
- •Часть 1
- •Общие сведения Сведения об эумк
- •Методические рекомендации по изучению дисциплины
- •Рабочая учебная программа
- •Учреждение образования
- •«Белорусский государственный университет
- •Информатики и радиоэлектроники»
- •Часть 2 __184__
- •Содержание дисциплины
- •1. Индивидуальные практические занятия, их характеристика
- •2. Контрольные работы, их характеристика
- •3. Курсовой проект, его характеристика
- •4. Литература
- •4.1. Основная
- •4.2. Дополнительная
- •5. Перечень компьютерных программ, наглядных и других пособий, методических указаний и материалов и технических средств обучения
- •Протокол согласования учЕбной программы по изучаемой учебной дисциплине с другими дисциплинами специальности
- •Теоретический раздел Введение
- •1. Основные типы данных
- •1.1. Общие сведения
- •1.2. Данные типа int
- •1.3. Данные типа char
- •1.4. Модификаторы доступа const и volatile
- •1.5. Данные вещественного типа (с плавающей точкой)
- •1.6. Элементарный ввод-вывод
- •1.7. Структура простой программы на языке Си
- •2. Операции и выражения
- •2.1. Выражение и его интерпретация
- •2.2. Основные операции
- •2.2.1. Арифметические операции
- •2.2.2. Побитовые логические операции
- •2.2.3. Операции сдвига
- •2.2.4. Операция присваивания
- •2.2.5. Операция sizeof
- •2.2.6. Преобразование типов в выражениях
- •2.2.7. Операция преобразования типов
- •2.2.8. Приоритеты в языке Си
- •3. Операторы управления вычислительным процессом
- •3.1. Оператор if
- •3.2. Операции отношения
- •3.3. Логические операции
- •3.4. Операция запятая
- •3.5. Операция условия ?:
- •3.6. Оператор безусловного перехода goto
- •3.7. Оператор switch
- •`` ` `3.8. Операторы цикла
- •3.8.1. Оператор for
- •3.8.2. Оператор while
- •3.8.3. Оператор do...While
- •3.9. Оператор break
- •3.10. Оператор continue
- •4. Массивы и указатели
- •4.1. Одномерные массивы и их инициализация
- •4.2. Многомерные массивы и их инициализация
- •4.3. Объявление указателей
- •4.4. Операции над указателями
- •1) Взятие адреса
- •2) Косвенная адресация или разыменование указателя
- •3) Увеличение или уменьшение значения указателя на целое число
- •4) Разность указателей
- •5) Сравнение указателей
- •6) Присваивание указателей друг другу
- •4.6. Связь между указателями и массивами
- •4.7. Динамическое распределение памяти
- •4.8. Массивы указателей
- •5. Функции
- •5.1. Общие сведения
- •5.2. Область видимости переменных
- •5.2.1. Локальные переменные
- •5.2.2. Глобальные переменные
- •5.3. Передача параметров в функцию
- •5.4. Рекурсивные функции
- •5.5. Использование функций в качестве параметров функций
- •5.6. Указатели на функции
- •5.7. Структура программы на Си
- •5.8. Передача параметров в функцию main()
- •6. Строки
- •7. Классы хранения и видимость переменных
- •7.1. Общие сведения
- •7.2. Автоматический класс хранения (auto)
- •7.3. Регистровый класс хранения (register)
- •7.4. Статический класс хранения (static)
- •7.5. Внешний класс хранения (extern)
- •7.6. Заключение
- •8. Структуры, объединения и перечисления
- •8.1. Общие сведения
- •8.2. Инициализация структурных переменных
- •8.3. Вложенные структуры
- •8.4. Указатели на структуры
- •8.5. Массивы структурных переменных
- •8.6. Передача функциям структурных переменных
- •8.7. Оператор typedef
- •8.8. Поля битов в структурах
- •8.9. Объединения
- •8.10. Перечисления
- •9. Динамические структуры данных
- •9.1. Общие сведения
- •9.2. Связные списки
- •9.2.1. Односвязные списки
- •9.2.2. Двусвязные списки
- •9.2.3. Циклические списки
- •9.3. Стеки
- •9.4. Очереди
- •9.5. Деревья
- •9.5.1. Понятие графа
- •9.5.2. Бинарные деревья
- •10. Файлы
- •10.1. Общие сведения
- •10.2. Открытие и закрытие файлов
- •10.3. Функции ввода-вывода для работы с текстовыми файлами
- •10.4. Произвольный доступ к файлу
- •10.5. Функции ввода-вывода для работы с бинарными файлами
- •11. Директивы препроцессора
- •11.1. Основные понятия
- •11.2. Директива #include
- •11.3. Директивы препроцессора #define и #undef
- •11.3.1. Символические константы
- •11.3.2. Макросы с параметрами
- •11.3.3. Директива #undef
- •11.4. Условная компиляция
- •11.5. Директивы # и ##
- •12. Модульное программирование
- •13. Введение в объектно-ориентированное программирование
- •13.1. Постановка задачи
- •13.2. Решение задачи средствами Си
- •13.5. Наследование
- •13.6. Перегрузка
- •13.7. Ссылочный тип
- •Литература
- •Приложение 1. Рекомендации по оформлению текстов программ
- •Тесты к теоретическому разделу Вопросы к разделу 1. Основные типы данных
- •Вопросы к разделу 2. Операции и выражения
- •Вопросы к разделу 3. Операторы управления вычислительным процессом
- •Вопросы к разделу 4. Массивы и указатели
- •Вопросы к разделу 5. Функции
- •Вопросы к разделу 6. Строки
- •Вопросы к разделу 7. Классы хранения и видимость переменных
- •Вопросы к разделу 8. Структуры, объединения и перечисления
- •Вопросы к разделу 9. Динамические структуры данных
- •Вопросы к разделу 10. Файлы
- •Вопросы к разделу 11. Директивы препроцессора
- •Вопросы к разделу 12. Модульное программирование
- •Вопросы к разделу 13. Введение в ооп
- •Правильные ответы на вопросы тестов к теоретическому разделу
- •Вопросы к теоретическому зачету
- •Варианты индивидуальных заданий
- •Контрольная работа №2
- •Варианты индивидуальных заданий
- •Индивидуальные практические работы Указания к выбору варианта индивидуальных практических работ
- •Индивидуальная практическая работа № 1. Массивы и строки
- •Варианты индивидуальных заданий
- •Индивидуальная практическая работа № 2. Динамические структуры данных
- •Варианты индивидуальных заданий
5.4. Рекурсивные функции
Функция может вызывать саму себя. Это называется рекурсией, которая может быть прямой и косвенной. Если функция вызывает саму себя – это прямая рекурсия, если же она вызывает другую функцию, которая в свою очередь вызывает первую, то это косвенная рекурсия. Рекурсия полезна в тех случаях, когда выполняется процедура над данными и потом эту же процедуру надо выполнить над полученным результатом.
Важно рекурсию когда-нибудь прекратить (задать некоторое условие), иначе рекурсивная функция будет вызывать себя до тех пор, пока приложение не будет аварийно завершено в результате переполнения стека. Также при каждом обращении к такой функции ей должны передаваться модифицированные данные, а после завершения каждого экземпляра рекурсивной функции в вызывающую должен возващаться некоторый результат для дальнейшего использования. Рекурсивый процесс должен шаг за шагом так упрощать задачу, чтобы в конце концов на последнем шаге для нее появилось нерекурсивное решение.
Когда функция вызывает саму себя, передаётся новая копия данных этой функции, что приводит иногда к большим затратам памяти. Локальные переменные во второй версии независимы от локальных переменных первой и не могут непосредственно влиять друг на друга.
Пример использования рекурсии рассмотрим на программе нахождения определённого члена ряда Фибоначчи:
1,1,2,3,5,8,13,21,34…
Каждое число ряда представляет собой сумму двух предыдущих чисел. В общем случае n-e число равно сумме (n-2)-го и (n-1)-го чисел.
Для рекурсивных функций необходимо условие прекращения рекурсии, в ряду Фибоначчи условием прекращения будет n<3.
#include <stdio.h>
int fib (int);
void main()
{
int n, answer;
printf(“Введите номер для нахождения: ”);
scanf(“%d”, &n);
answer = fib(n);
printf(“\n answer is: %d”, answer);
}
int fib(int n)
{
if (n<3)
return 1;
else
return (fib(n-2) + fib(n-1));
}
После ввода параметра, программа проверяет, не меньше ли он числа 3, и, если это так, то функция fib() возвращает значение 1. В противном случае выводится сумма значений, возвращаемых при вызове функции fib() с параметрами n-2 и n-1. Таким образом, эту программу можно представить как циклический вызов функции fib(). Единственными вызовами, которые немедленно возвращают 1, являются вызовы функций fib(1) и fib(2). Рекурсивное использование функции fib() показано на рис 5.3.
Рис.5.3. Использование рекурсии
5.5. Использование функций в качестве параметров функций
Вполне допустимо для одной функции принимать в качестве параметра значение, возвращаемое другой функцией. Это можно рассмотреть на простом примере:
Имеются некоторые функции: double() – удвоение числа, triple() – утроение числа, square() – возведение в квадрат, cube() – возведение в куб, возвращающие некоторые целые значения. Можно записать:
answer = (doubleValue(tripleValue(square(cube(x)))));
Это выражение принимает переменную х, и передаёт её в качестве параметра функции cube(), возвращаемое значение которой (куб числа) передаётся как параметр функции square(). После этого возвращаемое значение функции (квадрат числа) передаётся в качестве параметра функции tripleValue(). Возвращаемое значение данной функции (утроенное число) передаётся как параметр функции doubleValue(). Наконец, значение возврата функции doubleValue() (удвоенное число) присваивается переменной answer.
В данном примере, при возникновении ошибки, достаточно трудно выявить ''виноватую функцию'', для решения этой задачи предлагается альтернативный вариант, где показаны промежуточные значения:
unsigned long x = 2;
unsigned long cub = cube(x); // 2 в кубе = 8
unsigned long squar = square(cub); // 8 в квадрате = 64
unsigned long tripl = tripleValue(squar); // 64 * 3 = 192
unsigned long answer = doubleValue(tripl); // 192 * 2 = 384
Применены значения параметров, используемые по умолчанию.
Для каждого параметра, объявляемого в прототипе и определении функции, должно быть передано соответствующее значение в вызове функции. Передаваемое значение должно иметь объявленный тип. Из этого правила существует исключение. Если в прототипе функции для параметра объявляется стандартное значение, то это значение используется, если при вызове функции для этого параметра не установлено никакого значения. Например, прототип функции:
long myFunc(int x = 50);
Если при вызове этой функции в программе параметр не будет представлен, по умолчанию он будет равен числу 50. Поскольку в прототипах функций имена параметров не обязательны, то последний вариант можно представить:
long myFunc(int = 50);
Имя параметра, для которого в прототипе устанавливается значение по умолчанию, может не совпадать с именем параметра, указываемого в заголовке функции (значение, заданное по умолчанию присваивается по позиции, а не по имени).