
- •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.6.Связь указателей и строк
Поскольку строка – разновидность массива, между строками и указателями существует та же взаимосвязь: имя строки – это константный указатель на значение типа char. При инициализации указателей на тип char часто используются строковые константы. Все строковые константы, используемые в программе, размещаются компиляторами C/C++ в так называемой таблице строк, являющейся частью исполнимого файла программы.
Строковая константа – это массив неизменяемых символов (байтов) необходимого размера. Для нее, как и для любого массива, неявно определен указатель (для строковой константы – на тип char), содержащий адрес начального элемента этого массива (строки). Обращение к строковой константе – это обращение к значению этого указателя.
Строковая константа может быть "присвоена" указателю на тип char:
char* s1 = "The string";
В приведенном объявлении указатель на константные символьные данные s1 инициализируется адресом строковой константы "The string".
Следует отметить отличие данного объявления от объявления
char s2[] = "The string";
Первое из приведенных объявлений формирует указатель s1 размером в четыре байта, содержащий адрес строковой константы "The string", второе – массив символов s2 размером в 11 байтов (длина строки "The string" плюс нулевой символ) с соответствующими начальными символьными значениями. Соответственно, различаются и способы работы с объявленными данными: элементы массива s2 можно изменять, а данные, на которые указывает s1, вообще говоря, нет.
Второе объявление можно рассматривать как краткую форму записи объявления
char s2[] = {'T','h','e',' ','s','t','r','i','n','g','\0'};
Стандартная библиотека включает большое количество специальных функций, облегчающих работу со строками и символами.
Символьные функции работают с отдельными символами и требуют включения в программу директивы
#include <ctype.h>
Строковые функции оперируют массивами символов, завершающихся нуль-символом, и в большинстве своём в качестве параметров принимают указатели на тип char. Для использования этих функций в программе нужно подключить их описания с помощью директивы препроцессора
#include <string.h>
1.1.7.Преобразование указателей
Указатель на данные одного типа может быть преобразован в указатель на данные другого типа. Однако при этом следует учитывать, что данные, адресуемые преобразованным указателем, будут интерпретироваться по-новому (может измениться их размер, а, следовательно, и значение). Преобразование указателей выполняется операцией приведения типа:
( тип *) указатель
Например, операторы:
short int i = 0x1010; // Это десятичное 1*4096+ 1*16 = 4112
short *ptr = &i;
short int j = *ptr;
short int k = *(char*)ptr;
приведут к созданию переменной j с начальным значением 0x1010 и переменной k с начальным значением 0x10.
1.1.8.Бестиповые указатели
Бестиповый указатель (указатель на неопределенный тип) позволяет отсрочить определение типа, на который ссылается указатель, или использовать один указатель для обращения к данным разных типов. При объявлении такого указателя вместо типа адресуемых им данных указывается ключевое слово void:
void * имя_указателя ;
Переменная, объявленная как указатель на тип void, может быть использована для работы с данными любого типа. Но для того, чтобы оперировать бестиповым указателем или данными, которые он адресует, необходимо явно указать требуемый тип в каждой операции с таким указателем. Это можно сделать с помощью операции приведения типа:
int a = 125;
double d = 10.3975;
short b[4] = {0, 1, 2, 3};
void *vp;
. . .
vp = &a;
cout << *(int*)vp << endl; // Вывод значения переменной a
vp = &d;
cout << *(double*)vp << endl; // Вывод значения переменной d
vp = b;
cout << *((short*)vp+1) << endl; // Вывод значения b[1]
vp = (short*)vp+2; // Изменение значения vp
cout << *(short*)vp << endl; // Вывод значения b[2]
Переменная vp объявлена как бестиповый указатель, поэтому ей можно присвоить адрес переменной любого типа. Однако ни одна операция не может быть выполнена над бестиповым указателем до тех пор, пока не будет явно задан тип данных, на который он указывает. В примере указатель vp с помощью операции приведения типа преобразуется к типам int*, double* и short*.