
- •Часть 1. Основы создания программ в Си Лекция.1.Язык Си
- •Технология разработки программ
- •Базовые элементы языка Си
- •Представление данных в Си
- •Встроенные типы данных
- •Переменные
- •Операции и выражения
- •Функции
- •Лекция.2.Язык Си Обзор элементов языка Си Типизированные константы
- •Область действия переменных
- •Управляющие конструкции с
- •Массивы и указатели
- •Типы, определяемые пользователем
- •Лекция.3.Препроцессор и отладка программ
- •Макроопределения
- •Условная компиляция
- •1. Предотвращение включения файлов
- •Отладка программ
- •Элементы отладки
- •Лекция.1.Объектно-ориентированное программирование
- •Что такое объектно-ориентированное программирование
- •Пример определений классов
- •Конструктор и деструктор
- •Элементы класса
- •Элементы-функции
- •Элементы данных
- •Класс как область действия
- •Указатель this
- •Лекция.3.Элементы класса Статические элементы класса
- •Статические элементы-функции
- •Специальные элементы-функции класса
- •Конструктор
- •Список инициализации элементов
- •Конструктор копии
- •Операция присваивания
- •Деструктор
- •Операции класса new и delete
- •Функции преобразования
- •Ключевое слово explicit
- •Операции приведения
- •Доступ к базовым классам
- •Простое наследование
- •Конструкторы, деструкторы и наследование
- •Сложное наследование
- •Неоднозначности при сложном наследовании
- •Виртуальные базовые классы
- •Виртуальные функции
- •Чисто виртуальные функции и абстрактные классы
- •Реализация виртуального механизма
- •Лекция.5.Семинар 1-2: Обработка исключений
- •Объекты-исключения
- •Повторное возбуждение исключения
- •Перехват всех исключений
Массивы и указатели
Массивы и указатели довольно тесно связаны между собой. Имя массива можно разыменовывать, как указатель. В свою очередь, указатель можно индексировать, как массив, если это имеет смысл.
Массивы
Массив по существу является совокупностью однотипных переменных (элементов массива), объединенных под одним именем и различающихся своими индексами. Массив объявляется подобно простой переменной, но после имени массива указывается число его элементов в квадратных скобках:
int myArray[8];
Массив, как и переменную, можно инициализировать при объявлении. Значения для последовательных элементов массива отделяются друг от друга запятыми и заключаются в фигурные скобки:
int iArray[8] = {7, 4, 3, 5, 0, 1, 2, 6};
Обращение к отдельным элементам массива производится путем указания индекса элемента в квадратных скобках, например:
myArray[3] = 11;
myArray[i] = iArray[7-i];
Индекс должен быть целым выражением, значение которого не выходит за пределы допустимого диапазона. Поскольку индексация массивов начинается в С всегда с нуля (т.е. первый элемент имеет индекс 0), то, если массив состоит из N элементов, индекс может принимать значения от 0 до N—1.
Указатели
Указатель — это переменная, которая содержит адрес другого объекта. Этим объектом может быть некоторая переменная, динамический объект или функция. Говорят, что указатель ссылается на соответствующий объект. Адрес объекта, это 32-битное целое число, определяющее положение объекта в виртуальной памяти программы, указатель является не просто целым числом, а специальным типом данных. Он «помнит», на какого рода данные ссылается. Объявление указателя выглядит так:
тип_указываемого_объекта *имя_указателя [= значение];
Вот примеры объявлений:
int *pIntVar; // Указатель на целое.
double doubleVar = 3.14159265;
double *pDouble = &doubleVar; // Инициализация указателя на double.
Чтобы получить доступ к объекту, на который указатель ссылается, последний разыменовывают, применяя операцию-звездочку. Например, *pDouble будет представлять значение переменной, на которую ссылается pDouble:
printf("значение указателя (адрес): %р", pDouble);
printf("число, на которое он ссылается: %f", *pDouble);
Указатели используются при обработке строк, а также для передачи функциям параметров, значения которых могут ими изменяться (передача по ссылке).
Указатели позволяют создавать и обрабатывать динамические структуры данных. В языке С можно выделить память под некоторый объект не только с помощью оператора объявления, но и динамически, во время исполнения программы.
Объект создается в свободной области виртуальной памяти функцией malloc (). Вот пример (предполагается, что переменные объявлены так, как выше):
pDouble = malloc(sizeof(double)); //Динамическое выделение памяти.
*pDouble = doubleVar; //Присвоение значения
//динамическому объекту.
printf("Значение динамического объекта: %f", *pDouble);
free(pDouble); //Освобождение памяти.
Аргументом malloc () является размер области памяти, которую нужно выделить; для этого можно применить операцию sizeof, которая возвращает размер (в байтах) переменной или типа, указанного в качестве операнда.
Различия двух последних примеров - В первом из них указателю pDouble присваивается адрес переменной doubleVar. Во втором указателю присваивается адрес динамически созданного объекта типа double; после этого объекту, на который ссылается pDouble, присваивается значение переменной doubleVar. Т.о. создается новая динамическая копия значения переменной.
Функция malloc () возвращает значение типа void* — «пустой указатель». Это указатель, который может указывать на данные любого типа. Такой указатель нельзя разыменовывать, поскольку неизвестно, на что он указывает — сколько байтов занимает его объект и как их нужно интерпретировать. В данном случае операция присваивания автоматически приводит значение malloc () к типу double*. Можно было бы написать в явном виде:
pDouble = (double*)malloc(sizeof(double));
Если выделение памяти по какой-то причине невозможно, malloc () возвращает NULL, нулевой указатель. NULL определяется в Windows как символьная константа в stdlib.h
#define NULL OL // long double constant
Указатель на функцию
Можно объявить, инициализировать и использовать указатель на функцию. В вызовах API Windows часто применяют, например, «возвратно-вызываемые функции» - callback функции. В вызове API в качестве аргумента в этом случае употребляется указатель на соответствующую функцию.
/* некоторая функция */
void showString(char *s)
{
printf(s);
}
/*Главная функция*/
int main(void)
{
void (*pFunc)(char*); // Объявление указателя на функцию.
pFunc = showString; // Инициализация указателя адресом функции.
(*pFunc)("Calling a pointer to function!\n");
return 0;
}
Соотношение между указателями и функциями примерно такое же, как между указателями и массивами, о чем говорится в следующем разделе.
Отношения указателей и массивов
Между указателями и массивами в С существует тесная связь. Имя массива без индекса эквивалентно указателю на его первый элемент.
int iArray[4];
int *piArr;
piArr = iArray; // piArr указывает на начальный элемент iArray.
Последнее эквивалентно
piArr = &iArray[0];
Наоборот, указатель можно использовать подобно имени массива, т.е. индексировать его. Например, piArr [3] представляет четвертый элемент массива iArray[ ].
Следует только помнить, что объявление массива выделяет память под соответствующее число элементов, а объявление указателя никакой памяти не выделяет, вернее, выделяет память для хранения значения указателя — некоторого адреса.