
- •1. Основные понятия информатики
- •1.1. Понятие и задачи информатики
- •1.2. Системы счисления
- •1.2.1. Двоичная система счисления
- •1.2.2. Восьмеричная система счисления
- •1.2.3. Шестнадцатеричная система
- •1.3. Обобщенная структура и состав персонального компьютера
- •1.4. Организация вычислительных процессов при решении инженерных задач
- •1.5. Алгоритмы
- •1.5.1. Алгоритм: основные свойства и способы представления
- •1.5.2. Базовые элементы и структуры программирования
- •1.5.3. Представление линейных, разветвленных и циклических структур
- •2. ОБщие сведения об операционных системах
- •2.1. Общие сведения об операционных системах
- •2.1.1. Предпосылки создания и краткая история операционных систем ms-dos и Windows
- •2.1.1.1. Операционная система ms-dos
- •2.1.1.2. История создания операционной системы Windows
- •2.1.2. Основные отличия версий операционных систем
- •2.1.2.1. Операционная система Mac os
- •2.1.1.2. Операционная система Linux
- •2.1.1.3. Операционная система Windows
- •2.1.3. Основные команды операционной системы ms-dos
- •2.2. Основные элементы интерфейса операционной системы Windows
- •2.2.1. Элементы интерфейса ос Windows
- •2.2.2. Работа с файловыми системами операционной системы
- •3.2. Элементы языка с
- •3.2.1. Алфавит языка с (используемые символы)
- •3.2.2. Идентификаторы
- •3.2.3. Константы
- •3.2.4. Ключевые слова
- •3.2.5. Знаки операций
- •3.2.6. Комментарии
- •3.3. Лекция 6. Типы данных и их объявление
- •3.3.1. Основные типы данных
- •3.3.2. Объявление типов данных
- •3.4. Лекция 7. Указатели и массивы
- •3.4.1. Объявление указателей
- •3.4.2. Инициализация указателей
- •3.4.3. Составные указатели
- •3.4.4. Операции над указателями
- •3.4.5. Ссылки
- •3.5. Лекция 8. Массивы
- •3.5.1. Одномерные массивы
- •3.5.2. Многомерные массивы
- •3.5.3. Динамические массивы
- •3.5.3.1. Одномерные динамические массивы
- •3.5.3.2. Динамический многомерный массив
- •3.5.4. Символьные массивы (строки)
- •3.6. Лекция 9. Выражения и присваивания
- •3.6.1. Операции инкремента и декремента (увеличения и уменьшения на 1)
- •3.6.2. Операция определения размера типа
- •3.6.4. Операции деления ( / ) и нахождения остатка от деления ( % )
- •3.6.7. Поразрядные операции
- •3.6.8. Логические операции
- •3.6.9. Операции присваивания
- •3.6.10. Условная операция
- •3.6.11. Приоритеты выполнения операций
- •3.6.12. Преобразование типов
- •3.7. Лекция 10. Операторы
- •3.7.1. Операторы ветвления
- •3.7.1.1. Условный оператор if
- •If (выражение) [оператор_1]; [ else оператор_2 ; ]
- •3.7.1.2. Оператор switch
- •3.7.2. Операторы цикла
- •3.7.2.1. Цикл с предусловием (while)
- •3.7.2.2. Цикл с постусловием (do while)
- •3.7.2.3. Цикл с параметрами ( for )
- •3.7.3. Операторы передачи управления
- •3.7.3.1. Оператор безусловного перехода goto
- •3.7.3.2. Оператор прерывания break
- •3.7.3.3. Оператор пропуска continue
- •3.7.3.4. Оператор возврата из функции return
- •4. Модульное программирование
- •4.1. Лекция 11. Функции
- •4.1.1. Объявление функций
- •4.1.2. Определение функций
- •4.1.3. Вызов функций
- •4.1.4. Передача параметров в функцию
- •4.1.5. Передача массивов в функцию
- •В примере:
- •4.1.6. Функции с переменным числом параметров
- •4.1.7. Рекурсивные функции
- •4.1.8. Функция main()
- •4.1.9. Перегрузка функций
- •4.1.10. Шаблоны функций
- •4.2. Лекция 12. Директивы препроцессора
- •4.2.1. Директива #include
- •4.2.1. Директива # define
- •4.2.3. Директивы условной компиляции
- •4.2.4. Директивы #undef
- •4.3. Лекция 13. Пользовательские типы данных
- •4.3.1. Переименование типов
- •4.3.2. Перечисления
- •4.3.3. Структуры
- •4.3.4. Битовые поля
- •4.3.5. Объединения
- •5. Программирование графических изображений в языке с
- •5.1. Лекция 14. Программирование графических изображений
- •5.1.1. Графический режим видеоадаптера
- •5.1.2. Функции управления графическим окном
- •5.1.3. Управление цветом и стилем заполнения фигур
- •5.1.4. Рисование простейших графических фигур
- •5.1.5. Отображение текстовой информации в графическом режиме
- •5.1.7. Преобразование координат и анимационные эффекты
- •6.1.1.3. Функция gets()
- •6.1.1.4. Функция puts()
- •6.1.1.5. Функции printf() и scanf()
- •Потоковые объекты ввода/вывода (форматируемые):
- •6.1.2.1 Форматирование данных с помощью флагов и методов
- •6.2. Функции файлового ввода и вывода
- •6.2.1. Файловый ввод и вывод средствами с
- •6.3. Строки: операции с текстовыми файлами
- •6.3.1. Операции над строками
- •6.3.2. Методы и функции ввода и вывода строк
- •6.4. Лекция 18. Операции со структурами и бинарными файлами
- •6.5. Лекция 19. Списки: операции с динамическими структурами данных; организация списков и их обработка
- •6.5.1. Линейные списки
- •6.5.2. Стеки
- •6.5.3. Очередь
- •6.5.4. Бинарные деревья
3.4. Лекция 7. Указатели и массивы
3.4.1. Объявление указателей
При обработке оператора определения переменной, например, int i = 10 ; компилятор выделяет память в соответствие с типом (int) и инициализирует её с указанным значением (10). Все обращения в программе к переменной по её имени (i) заменяются компилятором на адрес области памяти, в которой хранится значение переменной.
Программист может определить собственные переменные для хранения адресов областей памяти. Такие переменные называются указателями.
Указатели — это переменные, предназначенные для хранения адресов областей памяти.
Различают три вида указателей:
— указатели на функцию;
— указатели на объект;
— указатели на void.
Указатель на функцию содержит адрес области памяти в сегменте кода, по которому располагается исполняемый код функции.
Используется для:
— косвенного вызова функции (не через имя, а через обращение к переменной, хранящей ее адрес);
— передачи имени функции в другую функцию в качестве параметра.
Формат записи указателя на функцию имеет вид:
тип (*имя) (список_типов_аргументов);
Например, объявление вида:
int (*cooler) (double, double);
задаёт указатель cooler на функцию, возвращающую значение типа int и имеющую два аргумента типа double.
Указатель на объект содержит адрес области памяти, в которой хранятся данные основного или составного типа.
Формат указателя на объект в простейшем варианте имеет вид:
тип *имя;
где: тип — может быть любым типом, кроме ссылки и битового поля;
* — относится к имени.
Например:
int *a, b, *c ;
В данном примере описываются два указателя на целое с именами a и c, а также целая переменная b. Размер указателя зависит от модели памяти. Можно определить указатель на указатель и т.д.
Указатель на void применяется в тех случаях, когда конкретный тип объекта, адрес которого требуется хранить, не определен (например, если в одной и той же переменной в разные моменты времени требуется хранить адреса объектов различных типов).
Форматы указателя на void имеют вид:
тип (*имя) (список_типов_аргументов);
тип *имя;
Примечание (!):
Указателю на void можно присвоить значение указателя любого типа, сравнивать его с любыми указателями, но перед выполнением действий с областью памяти, на которую он ссылается, требуется преобразовать его к конкретному типу явным образом.
Примеры объявления указателей:
1) int i ; // целая переменная
2) const int ci=1 ; // целая константа
3) int *pi ; // указатель на целую переменную
4) const int *pci ; // указатель на целую константу
5) int *const cp=&i ; // указатель-константа на целую
// переменную
6) const int *const cpc=&ci ; // указатель константа на
// целую константу
В представленных примерах:
1) символ & — команда взятия адреса переменной;
2) модификатор const — запрещает изменение значения указателя;
const — указывает на то, что в ячейке памяти хранится
константа.
3.4.2. Инициализация указателей
Указатели чаще всего используют при работе с динамической памятью (кучей).
Динамическая память — свободная память, в которой можно во время выполнения программы выделять место под данные в соответствии с потребностями.
Доступ к выделенным участкам динамической памяти, называемым динамическими переменными, производится только через указатели.
Время «жизни» динамических переменных — от момента объявления, до конца выполнения программы или до явного освобождения динамической памяти.
В С/С++ используют два способа работы с динамической памятью:
— используя семейство функций malloc;
— используя операции new и delete.
Инициализатор записывается после имени указателя либо в круглых скобках, либо после знака равенства.
Способы инициализации указателей:
— присваивание указателю адреса уже существующего объекта;
— присваивание указателю адреса области памяти в явном виде;
— присваивание пустого значения;
— выделение (и освобождение) участка динамической памяти и присваивание её адреса указателя.
1. Присвоение указателю адреса существующего объекта:
— с помощью операции получения адреса:
int a=5 ; // целая переменная
int *p=&a ; // в указатель записывается адрес
// переменной “а”
int *p (&a) ; // в указатель записывается адрес
// переменной “а” другим способом
— с помощью значения другого инициализированного указателя:
int *r=p ; //p — указатель, унициализированный ранее
— с помощью имени массива или функции, которые трактуются как адрес:
int b[10] ; // объявление массив
int *t=b ; // присваивание адреса начала массива
…
void f(int a) { … } // определение функции
void (*pf)(int) ; // объявление указателя на функцию
pf=f // присваивание указателю адреса
// функции
2. Присваивание указателю адреса области памяти в явном виде:
char *vp=(char*) 0xB8000000 ;
Здесь 0xB8000000 — шестнадцатеричная константа (адрес области памяти);
(char*) — операция приведения типа: константа преобразуется к типу «указатель на char».
3. Присваивание пустого значения:
int *a=NULL ;
int *b=0 ; // рекомендуется использовать этот вариант
Здесь NULL — нулевая константа.
Так как объектов с нулевым адресом нет, то пустой указатель можно использовать для проверки, ссылается ли проверяемый указатель на какой-либо объект или нет.
Рекомендуется использовать второй вариант инициализации.
4. Выделение участка динамической памяти и присваивание её адреса указателю:
Пример:
— с помощью new:
int *n=new int ; // 1
int *m=new int (10) ; // 2
int *q=new int [10] ; // 3
— с помощью функции malloc (библиотека <malloc.h>):
int *u=(int*) malloc(sizeof(int)) ; // 4 .
В представленных примерах инструкции могут быть описаны следующим образом:
//1 — операция new выполняет выделение достаточного для размещения величины типа int участка динамической памяти и записывает адрес начала этого участка в переменную n.
Память под саму переменную n (размера, достаточного для размещения указателя) выделяется на этапе компиляции.
//2 — выполняются действия, описанные выше, а также производится инициализация выделенной динамической памяти значением 10.
//3 — операция new выполняет выделение памяти под 10 величин типа int (т.е. под массив из 10-ти элементов) и записывает адрес начала этого участка в переменную q , которая может трактоваться как имя массива, через которое можно обращаться к любому элементу массива.
//4 — выполняется тоже самое, что в //1, но с помощью функции malloc . В функцию передаётся один параметр — количество выделяемой памяти в байтах.
(int*) — приведение типа указателя, возвращаемого функцией, к требуемому типу. Функция возвращает 0, если выделить память не удалось.
Примечание (!):
Предпочтительнее использовать операцию new, чем функцию malloc, особенно при работе с объектами.
5. Освобождение памяти:
— выделение new — освобождение delete;
— выделение malloc — освобождение free.
Пример освобождения памяти (соответствует примеру выделения памяти): delete n ; // 1
delete m ; // 2
delete []q ; // 3
free(u) ; // 4
Примечания:
Если выделение осуществлялось для массива, то необходимо указывать, что освобождается массив, поставив перед именем указателя пустые квадратные скобки (для освобождения требуется []delete). Размерность массива при этом не указывается.
Если нет скобок [], то освобождается только первый элемент массива, а остальные окажутся недоступными для дальнейших операций. Т.е. появляется «мусор» в памяти.
«Мусор» также может появиться, когда переменная-указатель выходит из области своего действия (и становиться недоступной), или когда инициализированному указателю присваивается значение другого указателя (старое значение теряется).