Чтение онлайн

на главную - закладки

Жанры

Шрифт:

void f // f не возвращает значение void* pv; // указатель на объект неизвестного типа

Переменной типа указатель на void (void *), можно присваивать указатель любого типа. На первый взгляд это может показаться не особенно полезным, поскольку void* нельзя разименовать, но именно это ограничение и делает тип void* полезным. Главным образом, он применяется для передачи указателей функциям, которые не позволяют сделать предположение о типе объекта, и для возврата из функций нетипизированных объектов. Чтобы использовать такой объект, необходимо применить

явное преобразование типа. Подобные функции обычно находятся на самом нижнем уровне системы, там, где осуществляется работа с основными аппаратными ресурсами. Например:

void* allocate(int size); // выделить void deallocate(void*); // освободить

f (* int* pi = (int*)allocate(10*sizeof(int)); char* pc = (char*)allocate(10); //... deallocate(pi); deallocate(pc); *)

2.3.5 Указатели

Для большинства типов T T* является типом арифметический указатель на T. То есть, в переменной типа T* может храниться адрес объекта типа T. Для указателей на вектора и указателей на функции вам, к сожалению, придется пользоваться более сложной записью:

int* pi; char** cpp; // указатель на указатель на char int (*vp)[10]; // указатель на вектор из 10 int'ов int (*fp)(char, char*); // указатель на функцию //получающую параметры(char, char*) // и возвращающую int

Основная операция над указателем – разыменование, то есть ссылка на объект, на который указывает указатель. Эта операция также называется косвенным обращением. Операция разыменования – это унарное * (префиксное). Например:

char c1 = 'a'; char* p = amp;c1; // в p хранится адрес c1 char c2 = *p; // c2 = 'a'

Переменная, на которую указывает p,– это c1, а значение, которое хранится в c1, это 'a', поэтому присваиваемое c2 значение *p есть 'a'.

Над указателями можно осуществлять некоторые арифметические действия. Вот, например, функция, подсчитывающая число символов в строке (не считая завершающего 0):

int strlen(char* p) (* int i = 0; while (*p++) i++; return i; *)

Другой способ найти длину состоит в том, чтобы сначала найти конец строки, а затем вычесть адрес начала строки из адреса ее конца:

int strlen(char* p) (* char* q = p; while (*q++) ; return q-p-1; *)

Очень полезными могут оказаться указатели на функции. Они обсуждаются в #4.6.7.

2.3.6 Вектора

Для типа T T[size] является типом «вектор из size элементов типа T». Элементы индексируются (нумеруются) от 0 до size-1. Например:

float v[3]; // вектор из трех float: v[0], v[1], v[2] int a[2][5]; // два вектора из пяти int char* vpc; // вектор из 32 указателей на символ

Цикл для печати целых значений букв нижнего регистра можно было бы написать так:

extern int strlen(char*);

char alpha[] = «abcdefghijklmnoprstuvwxyz»;

main

(* int sz = strlen(alpha);

for (int i=0; i«sz; i++) (* char ch = alpha[i]; cout „„ "'" „« chr(ch) «« "'" «« " = " «« ch «« « = 0“ «« oct(ch)

«« « = 0x“ «« hex(ch) «« «\n“; *) *)

Функция chr возвращает представление небольшого целого в виде строки; например, chr(80) это "P" на машине, на которой используется набор символов ASCII. Функция oct строит восьмеричное представление своего целого аргумента, а hex строит шестнадцатеричное представление своего целого аргумента; chr oct и hex описаны в «stream.h». Функция strlen использовалась для подсчета числа символов в alpha; вместо этого можно было использовать значение размера alpha (#2.4.4). Если применяется набор символов ASCII, то выдача выглядит так:

'a' = 97 = 0141 = 0x61 'b' = 98 = 0142 = 0x62 'c' = 99 = 0143 = 0x63 ...

Заметим, что задавать размер вектора alpha необязательно. Компилятор считает число символов в символьной строке, указанной в качестве инициализатора. Использование строки как инициализатора для вектора символов – удобное, но к сожалению и единственное применение строк. Аналогичное этому присваивание строки вектору отсутствует. Например:

char v[9]; v = «строка»; // ошибка

ошибочно, поскольку присваивание не определено для векторов.

Конечно, для инициализации символьных массивов подходят не только строки. Для остальных типов нужно применять более сложную запись. Эту запись можно использовать и для символьных векторов. Например:

int v1[] = (* 1, 2, 3, 4 *); int v2[] = (* 'a', 'b', 'c', 'd' *);

char v3[] = (* 1, 2, 3, 4 *); char v4[] = (* 'a', 'b', 'c', 'd' *);

Заметьте, что v4 – вектор из четырех (а не пяти) символов; он не оканчивается нулем, как того требуют соглашение и библиотечные подпрограммы. Обычно применение такой записи ограничивается статическими объектами.

Многомерные массивы представляются как вектора векторов, и применение записи через запятую, как это делается в некоторых других языках, дает ошибку при компиляции, так как запятая (,) является операцией следования (см. #3.2.2). Попробуйте, например, сделать так:

int bad[5,2]; // ошибка

и так:

int v[5][2];

int bad = v[4,1]; // ошибка int good = v[4][1]; // ошибка

Описание

char v[2][5];

описывает вектор из двух элементов, каждый из которых является вектором типа char[5]. В следующем примере первый из этих векторов инициализируется первыми пятью буквами, а второй – первыми пятью цифрами.

char v[2][5] = (* 'a', 'b', 'c', 'd', 'e', '0', '1', '2', '3', '4' *)

main (* for (int i = 0; i«2; i++) (* for (int j = 0; j„5; j++) cout „„ „v[“ «« i «« «][“ «« j «« «]=“ «« chr(v[i][j]) «« " "; cout «« «\n“; *) *)

это дает в результате

v[0][0]=a v[0][1]=b v[0][2]=c v[0][3]=d v[0][4]=e v[1][0]=0 v[1][1]=1 v[1][2]=2 v[1][3]=3 v[1][4]=4

2.3.7 Указатели и вектора

Указатели и вектора в С++ связаны очень тесно. Имя вектора можно использовать как указатель на его первый элемент, поэтому пример с алфавитом можно было написать так:

Поделиться:
Популярные книги

Войны Наследников

Тарс Элиан
9. Десять Принцев Российской Империи
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Войны Наследников

Я снова граф. Книга XI

Дрейк Сириус
11. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я снова граф. Книга XI

Сколько стоит любовь

Завгородняя Анна Александровна
Любовные романы:
любовно-фантастические романы
6.22
рейтинг книги
Сколько стоит любовь

Кодекс Охотника. Книга X

Винокуров Юрий
10. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
6.25
рейтинг книги
Кодекс Охотника. Книга X

Толян и его команда

Иванов Дмитрий
6. Девяностые
Фантастика:
попаданцы
альтернативная история
7.17
рейтинг книги
Толян и его команда

Идеальный мир для Лекаря 5

Сапфир Олег
5. Лекарь
Фантастика:
фэнтези
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 5

Возвышение Меркурия. Книга 3

Кронос Александр
3. Меркурий
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 3

Офицер империи

Земляной Андрей Борисович
2. Страж [Земляной]
Фантастика:
боевая фантастика
попаданцы
альтернативная история
6.50
рейтинг книги
Офицер империи

Черный маг императора 3

Герда Александр
3. Черный маг императора
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Черный маг императора 3

Измена. Право на сына

Арская Арина
4. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Право на сына

Краш-тест для майора

Рам Янка
3. Серьёзные мальчики в форме
Любовные романы:
современные любовные романы
эро литература
6.25
рейтинг книги
Краш-тест для майора

Небо в огне. Штурмовик из будущего

Политов Дмитрий Валерьевич
Военно-историческая фантастика
Фантастика:
боевая фантастика
7.42
рейтинг книги
Небо в огне. Штурмовик из будущего

Кодекс Крови. Книга VI

Борзых М.
6. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга VI

Неудержимый. Книга XIII

Боярский Андрей
13. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга XIII