- •Конспект лекций Часть 2 Оглавление
- •Часть 2 1
- •8. Указатели
- •8.1. Указатели Понятие указателя
- •Работа с указателями
- •Арифметика указателей
- •Ошибки при работе с указателями
- •If (p1) // Если указатель не равен 0, то все в порядке
- •8.2. Указатели и массивы
- •9. Функции и структура программы
- •9.1. Создание и использование функций Процедурный подход к разработке программ
- •Int Максимум_строки (int Строка)
- •Int Минимум_строки (int Строка)
- •Int Максимум_столбца (int Столбец)
- •Int Минимум_столбца (int Столбец)
- •Определение функций в программе
- •Завершение работы функции (инструкция return)
- •If ( Ошибка )
- •Список параметров функций
- •Обращение к функциям в программе
- •Передача данных по значению
- •Передача данных с помощью указателей
- •Передача данных по ссылке
- •Перегружаемые функции
- •Параметры по умолчанию
- •Функции с переменным числом параметров
- •Рекурсивное использование функций
- •Передача функций в качестве параметров
- •Встраиваемые функции (inline - функции)
- •Прототипы функций
- •9.2. Структура программы. Глобальные и локальные данные (области видимости и время жизни) Структура программы
- •Глобальные и локальные данные
- •Классы памяти
- •Многофайловые проекты
- •10. Структуры, объединения, перечисления
- •10.1. Структуры Определение структур
- •Доступ к полям структур
- •Указатели на структуры
- •Структурные параметры функций
- •Битовые поля структур
- •10.2. Объединения Обычные объединения
- •Анонимные объединения
- •10.3. Перечисления
- •Void WriteColor (тип_Спектр c )
- •11. Организация работы с файлами
- •11.1. Потоки для работы с файлами Общие сведения
- •Пример работы с файлом
- •11.2. Работа с файлами Создание потока, открытие и закрытие файла
- •Запись и чтение данных в текстовых файлах
- •Запись и чтение данных в двоичном режиме
- •If ( !File ) // Проверили удалось ли открыть файл
- •Как обнаружить конец файла?
- •Прямой доступ при работе с файлами
- •If ( !File ) // Проверили удалось ли открыть файл
- •Статус потоков ввода-вывода
- •Некоторые другие функции управления потоками ввода-вывода
- •Примеры по работе с файлами
- •12. Работа с динамической памятью Распределение памяти при работе программы
- •Динамическое выделение и освобождение памяти в стиле c
- •Возможные ошибки при работе с динамической памятью
- •Динамические массивы
- •Одномерные однонаправленные списки
- •Одномерные двунаправленные списки
- •Многомерные списки
Классы памяти
Модификаторы (спецификаторы) классов памяти используются для управления временем жизни и областью видимости программных объектов. Чаще всего они применяются к переменным. Например, формат определения переменной включает в себя возможность указания класса памяти переменной:
[< класс памяти >] < тип данных > < идентификатор > [< инициализация >]
В языке C++ определены 4 основные класса памяти:
auto
register
static
extern
Спецификатор autoиспользуется при определении локальных объектов (переменных внутри функций или блоков). Указание класса памятиautoиспользуется крайне редко, поскольку по умолчанию (когда класс памяти не указывается) все локальные переменные являются автоматическими, т.е. принадлежат классу памятиauto. Объекты, имена которых объявляются со спецификаторомauto, размещаются в динамически распределяемой памяти (в стеке) непосредственно перед началом выполнения функции или блока операторов. При выходе из блока или при возвращении из функции, соответствующая область памяти освобождается и все ранее размещённые в ней объекты уничтожаются. Таким образом, спецификатор влияет на время жизни объекта (это время локально). Например:
void F ( int i )
{
int j = 20;
if ( i == 10 )
{
double Pi = 3.14;
……..
}
}
В этой функции все переменные (i, j, Pi) являются локальными автоматическими объектами. Переменныеiи jсоздаются в памяти в начале выполнения функции и уничтожаются при выходе из функции. Время жизни и область видимости этих переменных одинаковы и соответствуют всему телу функции. ПеременнаяPiсоздается в памяти, когда начинает выполняться соответствующий блок инструкцииif, и уничтожаются при выходе из этого блока.
Спецификатор registerиспользуется довольно часто для увеличения быстродействия программы. Этот спецификатор “просит” компилятор поместить соответствующую переменную в памяти так, чтобы доступ к ней осуществлялся как можно быстрее. Регистровые переменные размещаются либо в регистрах процессора, либо в кэш-памяти компьютера. Поскольку объем такой памяти ограничен, компилятор эту “просьбу” может и не выполнить. В этом случае регистровые переменные создаются как обычные автоматические переменные. Пример определения регистровой переменной:
register double d = 1.23;
С помощью спецификатора класса памяти externосуществляется обращение к глобальным переменным, определенным либо в других файлах проекта, либо далее в этом же файле. Например:
void F ()
{
extern int ArrSize;
……..
}
………
int ArrSize = 100;
………
Когда компилятор встречает спецификатор extern, он не создает в памяти новую переменную, а пытается найти переменнуюArrSizeдалее в этом файле, а затем в других файлах проекта. Если такая глобальная переменная находится, то она и используется в функцииF. Говорят, что строкаextern int ArrSize; является объявлением переменной (переменная только объявляется, но не создается в памяти), а строкаint ArrSize = 100; - определением переменной, при котором создается сама переменная.
Спецификатор static позволяет определять переменные, имеющие глобальное время жизни (они существуют до конца работы программы), но ограниченную область видимости. С точки зрения области видимостиstatic-переменные делятся на два вида:
локальные static-переменные, определяемые внутри функций;
внешние static-переменные, определяемые вне функций.
Локальные static-переменные определяются внутри функций и после своего определения существуют до конца работы программы, сохраняя свои значения. После завершения функции они не уничтожаются и сохраняют свои значения до следующего вызова этой функции. Область видимости таких переменных ограничена только блоком функции, в которой они определены, и в других функциях они не видны. Хорошей иллюстрацией использования локальных статических переменных является функция для получения текущего среднего значения числовой последовательности, вычисляемого в процессе ввода элементов этой последовательности:
double Srednee ( int n );
int main ()
{
setlocale (0, "");
int n;
do
{
cin >> n;
if ( n >= 0 )
cout << "Среднее значение: " << Srednee ( n );
cout << endl;
}
while ( n >= 0 );
return 0;
}
double Srednee ( int n )
{
static int Sum = 0, Count = 0;
++ Count;
Sum += n;
return double ( Sum ) / Count;
}
Локальные static-переменныеSum иCountинициализируются значениями0один раз при первом вызове функцииSrednee. Затем их значения изменяются, и эти измененные значения после завершения работы функции сохраняются до ее следующего вызова.
Альтернативным решением этой задачи является использование глобальных переменных. Однако использование глобальных переменных чревато нежелательными побочными эффектами, связанными с возможными скрытыми изменениями их значений в других функциях программы.
Внешние static-переменные определяются вне функций. Они, так же как и локальныеstatic-переменные имеют глобальное время жизни. Но их область видимости ограничена файлом проекта, в котором они определены (они могут быть доступны только в функциях, расположенных в этом же файле и не видны из других файлов проекта). Таким образом, их можно рассматривать как глобальные переменные с областью видимости, ограниченной файлом, в котором они определены.
Спецификатор staticможно применять и к функциям.