- •1.1.Указатели
- •1.1.1.Объявление указателей и работа с адресами
- •1.1.2.Адресная арифметика
- •1.1.3.Указатели как формальные параметры функции
- •1.1.4.Связь указателей и массивов
- •1.1.5.Константные указатели и указатели на константы
- •1.1.6.Связь указателей и строк
- •1.1.7.Преобразование указателей
- •1.1.8.Бестиповые указатели
- •1.1.9.Массив указателей
- •1.1.10.Указатели на указатели
- •1.1.11.Резервирование и освобождение памяти (операторы new и delete)
- •1.2.Типы данных, определяемые пользователем
- •1.2.1.Переопределяемые типы данных
- •1.2.2.Структуры
- •1.2.2.1.Массивы структур
- •1.2.2.2.Использование указателей на структуры
- •1.2.2.4.Динамические структуры и массивы структур
- •1.2.3.Классы
- •1.2.3.1.Введение в ооп
- •2.1.Потоки
- •2.2.Стандартные потоки
- •2.4.Файловые потоки
- •2.4.1.Общие принципы работы с файлами
- •2.4.2.Режимы открытия файлов
- •2.4.3.Текстовые и бинарные файлы и файловые потоки
- •2.4.4.Проверка состояния файла и потока
- •2.4.5.Функции (методы) ввода-вывода
- •2.4.5.1.Методы get и put
- •2.4.5.2.Метод getline
- •2.4.5.3.Методы read и write
- •2.4.6.Особенности работы с бинарными файлами
- •2.4.7.Использование текущей позиции файла
1.1.3.Указатели как формальные параметры функции
В языке C, предшественнике языка C++, был реализован всего один способ передачи параметров – по значению. Передача параметров по адресу (посредством механизма ссылок) была добавлена только в языке C++. Однако и в языке C проблем с изменением в функции значения передаваемого параметра не возникало, поскольку для этих целей в качестве параметров можно было использовать адреса. Когда в качестве формального параметра функции используется указатель, а фактическим параметром является адрес переменной, все изменения значения, адресуемого формальным параметром – это одновременно и изменения значения фактического параметра. При такой передаче параметров передается, конечно же, значение, но поскольку это значение – адрес, обеспечивается полный доступ к фактическому параметру, характерный для передачи параметров по адресу.
Пример использования указателей для организации обмена значениями двух переменных:
void swap1 (int* x, int* y)
{
int z=*y;
*y = *x;
*x = z;
}
int main ()
{
int a=0, b=1;
swap1 (&a, &b);
. . .
return 0;
}
Понятно, что вызов функции swap1 приведет к обмену значениями переменных a и b.
1.1.4.Связь указателей и массивов
Между указателями и массивами существует прямая связь. Объявление массива, например,
int a[5];
в действительности, помимо резервирования памяти для пяти элементов типа int, определяет также указатель с именем a, значение которого – адрес начального элемента этого массива (&a[0]):
Для доступа к элементам массива используются индексные или адресные выражения, содержащие указатель на данный массив, например, непосредственно указатель a:
*(a+1) = *(a+4)+1; // это то же, что и a[1] = a[4]+1;
Понятно, что, скажем, a+1 указывает на второй по счету элемент этого массива, а a+4 – на последний его элемент.
Так как имя массива означает адрес начала массива, то в следующем фрагменте программы
int a[5];
int *ptr = a;
указатель ptr устанавливается на адрес начального элемента массива a. После этого ptr становится указателем на массив a и его можно использовать для ссылки на элементы этого массива. Поскольку элементы массива расположены в памяти последовательно, увеличение указателя ptr на единицу означает смещение к следующему элементу массива a. Например, следующие два присваивания эквивалентны:
a[1] = 1;
*(ptr+1) = 1;
1.1.5.Константные указатели и указатели на константы
Указатели могут быть объявлены как неизменяемые (константные) или указывающие на неизменяемые (константные) значения. Для этого при объявлении указателя в качестве модификатора используется ключевое слово const, например:
int a, b;
...
const int *xPtr; // указатель на константное значение
int* const iPtr = &a; // константный указатель на значение
const int * const dcPtr = &b; //константный указатель на константное значение
(константные указатели обязательно должны инициализироваться при объявлении, отсутствие инициализирующего адресного значения приведет к ошибке компиляции).
Идентификатор массива является константным указателем на начальный элемент массива, поэтому его значение не может быть изменено.
Для такого рода действий следует использовать переменную-указатель на данные того же типа, что и массив:
int a[25], *p;
p = a;
p++; // это правильно
a++; // а это – нет
