- •Часть 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. Динамические структуры данных
- •Варианты индивидуальных заданий
11.3.3. Директива #undef
Определения символических констант и макросов могут быть аннулированы при помощи директивы препроцессора #undef, имеющей вид:
#undef идентификатор
Директива отменяет определение символической константы или макроса с указанным идентификатором. Таким образом, область действия символической константы или макроса начинается с места их определения и заканчивается явным их аннулированием директивой #undef или концом файла. После аннулирования соответствующий идентификатор может быть снова использован в директиве #define.
Например, возможен следующий код:
#define MyConst 128
// Здесь константа MyConst равна 128
. . .
#undef MyConst
// Здесь константу MyConst использовать нельзя
. . .
#define MyConst 64
// Здесь константа MyConst равна 64.
11.4. Условная компиляция
Условная компиляция дает возможность программисту управлять выполнением директив препроцессора и компиляцией программного кода. Каждая условная директива препроцессора вычисляет значение целочисленного константного выражения. Операции преобразования типов, операция sizeof, константы перечислимого типа и переменные не могут участвовать в выражениях, вычисляемых в директивах препроцессора, так как эти операции и иницилизация переменных происходят на этапе компиляции или выполнения программы, в то время, как обработка директив препроцессора происходит перед компиляцией. Поэтому, при условной компиляции используются операции сравнения (>, <, >=, <=, ==), операции логического И(&&), ИЛИ(||) и отрицания(!) в сочетании с константными переменными или символическими константами, определёнными с помощью директивы #define
Условная директива препроцессора #if во многом похожа на оператор if. Ее синтаксис имеет вид:
#if условие
фрагмент кода
#endif
Предупреждение: в условии могут содержаться только константные величины – либо символические константы, определённые с помощью оператора #define, либо константные переменные.
Предупреждение: между #if и #endif фигурные скобки не ставятся.
Предупреждение: не забывайте закрывать каждый #if соответствующим #endif.
В этой записи условие является целочисленным выражением. Если это выражение возвращает не нуль (истинно), то фрагмент кода, заключенный между директивой #if и директивой #endif компилируется. Если же выражение возвращает нуль (ложно), то этот фрагмент игнорируется и препроцессором, и компилятором.
В условиях, помимо обычных выражений, можно использовать конструкцию
defined идентификатор
defined возвращает 1, если ранее указанный идентификатор был определен директивой #define, и возвращает 0 в противном случае. Например, возможен следующий код:
#if defined Debug && !defined MyConst
фрагмент кода
#endif
Фрагмент кода будет выполняться, если ранее была объявлена директива
#define Debug
и не было директивы
#define MyConst
или эта директива была отменена директивой
#undef MyConst
Конструкция #if defined может быть заменена эквивалентной ей директивой #ifdef, а конструкция #if !defined – директивой #ifndef.
Например, тексты
#ifdef Size
...
#endif
и
#if defined Size
...
#endif
эквивалентны.
Оператор #if defined часто используется при включении заголовочных файлов, для исключения повторной вставки кода заголовочного файла. Например:
#if !defined(MYLIB_H)
#define MYLIB_H
/* Текст объявляемых заголовков */
#include "MyBibl.h"
...
#endif /* Конец MYLIB_H */
В первый раз, когда константа MYLIB_H ещё не объявлена !defined(MYLIB_H) возвращает 1 и операторы между #if и #endif выполняются. В том числе оператором #define MYLIB_H объявляется MYLIB_H. Поэтому при достижении препроцессором следующего вхождения этой директивы вложенное в неё содержимое будет игнорироваться.
Можно использовать более сложные конструкции условных директив препроцессора при помощи директив #elif (эквивалент else if в обычной структуре if) и #else (эквивалент else в структуре if). Например, в коде
#if условие 1
фрагмент кода 1
#elif условие 2
фрагмент кода 2
#else
фрагмент кода 3
#endif
фрагмент кода 1 будет компилироваться, если выполняется условие 1, фрагмент кода 2 будет компилироваться, если выполняется условие 2 и не выполняется условие 1, а фрагмент кода 3 будет компилироваться, если не выполняется ни одно из предыдущих условий.
Условная компиляция может быть полезна во многих случаях. Например, нередко в процессе отладки приложения в него полезно ввести различные фрагменты кода, обеспечивающие вывод отладочной информации и позволяющие следить за ходом выполнения программы. Если эти фрагменты кода используются только при отладке и не нужно, чтобы они оставались в окончательном варианте программы, то в разных местах приложения следует ввести конструкции вида
#ifdef Debug
операторы отладки
#endif
Тогда, если в начале программы вы введете директиву
#define Debug
операторы отладки будут компилироваться и выполняться. Но когда вы уберете или закомментируете эту директиву #define, определяющую введенный вами идентификатор Debug, все операторы отладки исчезнут из текста.
Конечно, можно поступить иначе: ввести переменную булева типа (переменная, которая может принимать два значения – “истина” и “ложь”. В Си такого типа не существует, однако переменную можно создать используя тип unsigned char или unsigned int и учитывать, что значение “0” и есть “0” (false), а все остальные значения подразумевают “1” (true). Этот же принцип использован в условных операторах языка Си (if; switch/case)) Debug, задать ей в начале выполнения приложения значение true и оформлять процесс отладки следующим образом:
if (Debug)
{
операторы отладки
}
Если в дальнейшем заменить задаваемое значение Debug на false, то операторы отладки перестанут выполняться. Отличие этого подхода от использования директив препроцессора заключается в том, что коды операторов отладки в этом случае останутся в тексте программы, увеличивая размер выполняемого модуля. А директивы условной компиляции просто уберут отладочный код из программы.
