class="code">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. Размер массива — это сумма размеров его элементов. Рассмотрим пример.
int a[max]; // sizeof(a) == sizeof(int)*max
Можно определить и использовать массив массивов (двумерный массив), массив массивов массивов (многомерный массив) и т.д. Рассмотрим пример.
double da[100][200][300]; // 300 элементов типа, состоящего из
da[7][9][11] = 0;
Нетривиальное использование многомерных массивов — тонкое и уязвимое для ошибок дело (см. раздел 24.4). Если у вас есть выбор, следует предпочесть класс Matrix (как в главе 24).
A.8.3. Ссылки
Ссылка (reference) — это синоним (alias), т.е. альтернативное имя объекта.
int a = 7;
int& r = a;
r = 8; // переменная a становится равной 8
Ссылки часто используются в качестве параметров функций, чтобы предотвратить копирование.
void f(const string& s);
// ...
f("эту строку слишком дорого копировать, \
поэтому используется ссылка");
См. разделы 8.5.4–8.5.6.
A.9. Функции
Функция (function) — это именованный фрагмент кода, получающий (возможно, пустой) набор аргументов и (необязательно) возвращающий значение. Функция объявляется с помощью указания типа возвращаемого значения, за которым следует ее имя и список параметров.
char f(string, int);
Итак, f — это функция, принимающая объекты типа string и int и возвращающая объект типа char. Если функция должна быть просто объявлена, но не определена, то ее объявление завершается точкой с запятой. Если функция должна быть определена, то за объявлением аргументов следует тело функции.
char f(string s, int i) { return s[i]; }
Телом функции должен быть блок (см. раздел 8.2) или блок try (см. раздел 5.6.3).
Функция, в объявлении которой указано, что она возвращает какое-то значение, должна его возвращать (используя оператор return).
char f(string s, int i) { char c = s[i]; } // ошибка: ничего
// не возвращается
Функция main() представляет собой странное исключение из этого правила (см. раздел A.1.2). За исключением функции main(), если не хотите возвращать значение, то поставьте перед именем функции ключевое слово void. Другими словами, используйте слово void как тип возвращаемого значения.
void increment(int& x) { ++x; } // OK: возвращать значение
// не требуется
Функция вызывается с помощью оператора вызова () с соответствующим списком аргументов.