Язык C++ имеет много фундаментальных типов и типов, составленных из фундаментальных типов с помощью модификаторов.
Здесь
T
означает “некий тип”, поэтому существуют варианты
long unsigned int
,
long double
,
unsigned char
и
const char*
(указатель на константный
символ
char
). Однако эта система не совсем полная; например, в ней нет типа
short double
(его роль играет тип
float
); типа
signed bool
(совершенно бессмысленного); типа
short long int
(это было бы лишним) и типа
long long long long int
. Некоторые компиляторы в ожидании стандарта C++0x допускают тип
long long int
(читается как “очень длинный целый тип ”). Гарантируется, что тип
long long
содержит не менее 64 бит.
Типы с плавающей точкой (floating-point types) — это типы
float
,
double
и
long double
. Они являются приближением действительных чисел в языке С++.
Целочисленные типы (integer types), иногда называемые интегральными (integral), — это типы
bool
,
char
,
short
,
int
,
long
и (в языке C++0x)
long long
, а также их варианты без знака. Обратите внимание на то, что тип или значения перечислений часто можно использовать вместо целочисленного типа или значения.
Размеры встроенных типов обсуждались в разделах 3.8, 17.3.1 и 25.5.1; указатели и массивы — в главах 17 и 18; ссылки — в разделах 8.5.4–8.5.6.
A.8.1. Указатели
Указатель (pointer) — это адрес объекта или функции. Указатели хранятся в переменных указательных типов. Корректный указатель на объект содержит адрес этого объекта.
int x = 7;
int* pi = &x; // указатель pi ссылается на объект x
int xx = *pi; // *pi — это значение объекта,
// на который ссылается указатель pi, т.е. 7
Некорректный указатель — это указатель, не содержащий указателя ни на один объект.
int* pi2; // неинициализированный
*pi2 = 7; // неопределенное поведение
pi2 = 0; // нулевой указатель (указатель pi2 остается некорректным)
*pi2 = 7; // неопределенное поведение
pi2 = new int(7); // теперь указатель pi2 становится корректным
int xxx = *pi2; // отлично: переменная xxx становится равной 7
Мы хотим, чтобы все некорректные указатели были нулевыми (
0
), поэтому можем провести проверку.
if (p2 == 0) { // "если указатель некорректный"
// не используйте значение *p2
}
Или
еще проще:
if (p2) { // "если указатель корректный"
// используйте значение *p2
}
См. разделы 17.4 и 18.5.4.
Перечислим операции над указателями на объекты (не
void
). Операции сравнения
<
,
<=
,
>
,
>+
можно применять только к указателям одного и того же типа внутри одного и того же объекта или массива.
Подчеркнем, что операции арифметики указателей (например,
++p
и
p+=7
) могут применяться только к указателям, ссылающимся на элементы массива, а эффект разыменования указателя, ссылающегося на область памяти за пределами массива, не определен (и, скорее всего, не сможет быть проверен компилятором или системой выполнения программ).
Только операции над указателем типа
void*
являются копированием (присваиванием или инициализацией) и приведением (преобразованием типа).
Указатель на функцию (см. раздел 27.2.5) можно только копировать и вызывать. Рассмотрим пример.
typedef void (*Handle_type)(int);
void my_handler(int);
Handle_type handle = my_handler;
handle(10); // эквивалент my_handler(10)
A.8.2. Массивы
Массив (array) — это неразрывная последовательность объектов (элементов) одинакового типа, имеющая фиксированную длину.
int a[10]; // 10 целых чисел
Если массив является глобальным, то его элементы могут быть инициализированы соответствующим значением, принятым для данного типа по умолчанию. Например, значение
a[7]
равно
0
. Если массив является локальным (переменная объявлена в функции) или создан с помощью оператора
new
, то элементы встроенных типов останутся неинициализированными, а элементы, имеющие пользовательский тип, будут инициализированы его конструкторами.
Имя массива неявно преобразуется в указатель на его первый элемент. Рассмотрим пример.
int* p = a; // указатель p ссылается на элемент a[0]
Массив или указатель на элемент массива может индексироваться с помощью оператора
[]
. Рассмотрим пример.
a[7] = 9;
int xx = p[6];
Элементы массива нумеруются начиная с нуля (разделы 18.5).
Диапазон индексов массива не проверяется. Кроме того, поскольку они часто передаются с помощью указателей, информация, необходимая для проверки диапазона, передается пользователям ненадежным способом. Рекомендуем использовать класс
vector
. Размер массива — это сумма размеров его элементов. Рассмотрим пример.