
- •Часть 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. Динамические структуры данных
- •Варианты индивидуальных заданий
6) Присваивание указателей друг другу
p1 = p; // содержимое p копируется в p1, т.е. p1 теперь
// указывает на тот же элемент массива либо
// переменную, что и p
Указатель может быть присвоен другому указателю, если оба указателя имеют один и тот же тип. В противном случае нужно использовать операцию приведения типа. Исключением является указатель типа void.
4.5. Тип void
Ключевое слово void говорит об отсутствии информации о размере элемента данных в памяти.
Практическое значение имеет только понятие указателя на тип данных void. Все остальные применения этого ключевого слова носят скорее синтаксическую нагрузку.
Объявление указателя типа void:
void *p;
Такому указателю может быть присвоен указатель на любой тип, и наоборот. В обоих случаях применение операции приведения типа не требуется.
Над указателем типа void нельзя выполнить операцию косвенной адресации (разыменования) без явного приведения типа, так как компилятор не знает размер типа данных, т.е. число байт, участвующих в операции.
Например:
unsigned a = 0x1234;
void *p = &a;
char b;
unsigned c;
b = *(char *)p; // Приводит указатель типа void к типу
// char и присваивает b значение
// переменной, на которую он указывает
printf("%.2x\n", b); // Выводит 34
c = *(unsigned *)p;
printf("%.4x\n", c); // Выводит 1234
Строка формата "%.2x\n" означает, что число будет выведено в его шестнадцатиричном представлении с двумя знаками. В случае, если число представимо меньшим количеством цифр, оно будет дополнено слева нулями до заданной длины. Аналогично "%.4x\n" означает вывод шестнадцатиричного числа с 4 знаками. Более подробную информацию о строке формата, например "%.4x\n", можно получить в справочной системе среды программирования.
Перед использованием указателя на void в адресной арифметике он также должен быть приведен к нужному типу операцией приведения типа.
4.6. Связь между указателями и массивами
В Си массивы и указатели тесно связаны между собой и являются практически взаимозаменяемыми.
Имя массива является указателем-константой на первый элемент массива.
Объявим переменные:
int a[5];
int *p;
Можно присвоить указателю адрес первого элемента массива двумя способами:
p = a;
p = &a[0];
Есть несколько способов доступа к элементам массива.
Обычный способ, через указание имени массива и индекса, например, a[3]
Способ указатель/смещение: например, *(p + 3). Константа 3 называется смещением и показывает, на какой элемент массива производится ссылка, т.е. значение смещения равно значению индекса массива. В выражении используются скобки, так как приоритет операции * выше, чем операции +. В случае без скобок в выражении *p+3 к значению *p прибавляется число 3 (в данном случае к значению элемента a[0] будет прибавлено 3).
Для того чтобы перемещаться по массиву, можно использовать операции инкремента и декремента. Операция
*(p++)
получает значение переменной по адресу p и устанавливает указатель p на следующий элемент массива. Операция
*(--p)
перемещает указатель к предыдущему элементу массива и получает значение этого элемента.
Имя массива (т.к. является указателем) можно использовать в арифметике указателей. Например, выражение *(a+3) будет ссылаться на элемент массива a[3].
Указатели, в свою очередь, могут быть использованы вместо имен массива. Если, p=&a[0], то p[1] и a[1] обращаются к одной и той же ячейке памяти.
Выражение a+=3 является недопустимым, так как имя массива – это указатель-константа, которая всегда указывает на первый элемент массива. А здесь делается попытка изменить значение начального адреса массива.
Объявим двумерный массив:
int a[3][3];
Выражения наподобие а[0], a[1], a[2] при компиляции заменяются адресами первых элементов соответственно первой, второй и третьей строк массива, a
a[0]-> a[0][0] a[0][1] a[0][2]
a[1]-> a[1][0] a[1][1] a[1][2]
a[2]-> a[2][0] a[2][1] a[2][2]
Очевидны следующие равенства:
a[i]+j == &a[i][j]; // адрес j-го элемента i-строки массива
*(a[i]+j) == a[i][j]; // содержимое j-го элемента i-ой строки массива
*(*(a+i)+j) == a[i][j]; // содержимое j-го элемента i-ой строки массива