Программирование >>  Унарные и бинарные операторы 

1 ... 3 4 5 [ 6 ] 7 8 9 ... 37


Листинг 4.5 {продолжение)

String s[2]={ Здравствуй. . Мана) };

cout s[0] s[l] endl;

cout s[0][9] endl; Вывод й

Массив строк состоит всего из двух элементов: s[0] и s[l]. Начальные значения строк задаются в фигурных скобках. Заметим, что s[0] - обычное имя строки. А раз так, к нему применим оператор [], выделяющий отдельную букву. В последней строке программы на экран выводится девятый символ нулевой строки (s[0][9]). Легко подсчитать, что это буква й .

Отметим напоследок важную роль завершающего символа ЛО. Не будь его, оператор вывода не имел бы понятия, где кончается последовате.;ьность, и был бы вынужден показать на экране всю оставшуюся память компьютера байт за байтом, начиная с буквы, стоящей в начале массива.

Контейнеры

Массивы, о которых мы говорили в предыдуп1ем разделе, представляют собой простейшую упаковку для однотипных объектов. По своей сути .это идущие подряд ячейки памяти, в которых располагаются объекты - один за другим.

Массивы HHipoKO и с незапамятных времен применяются в С++, многие стандартные объекты С++ работают именно с ними. Одно из основных достоинств массива - в простоте задания начальных значений (они записываются внутри фигурных скобок). Основной его недостаток - в отсутствии у массива свойств стандартных объектов С++. Правильный объект С++ имеет собственные функции (методгл), он управляется ими, и только через них мы узнаем о его состоянии. Ника-

ких собственных функций у массива нет, поэтому пользоваться им довольно опасно. Можно, например, задать индекс, прсвышаюп1ий размер массива. Компи- лятор этого не заметит, но программа после попытки записи в неположенное место памяти, скорее всего, аварийно завершится.

Вот поэтому в С++ введены новые структуры данных, называемые контейнерами. В этом ра.зделе мы познакомимся с векторюм - контейнерюм, очень похожим на массив. Простейшие действия с KOHTciniepOM иллюстрирует листинг 4.6.

Листинг 4.6

#include <iostream> #include <vector> #1nc1ude <algor1thm> using namespace std: int mainO {

vector<int> s; forCint i=0:i<10:i++)

s.push back(i): vector<:int>::iterator at.ini.end; 1ni=s.begin();end=s.end(); random shuffle(ini.end); for(at=ini;at < end:at++)

cout *at endl; cout endl; sortCini.end);

forCint i-0;i < s.size():i++) cout s[i] endl;

Любой контейнер нужно сггачала объявить. В нашей программе инструкция vector<int> s объявляет контейнер s типа vector, содержащий целочисленные переменные. Естественно, в контейнере могут храниться и другие объекты: строки, переменные типа double и т. д.

После объявления контейнер пуст. Чтобы заполнить его, применяется собственная функция вектора



Контейнеры 65

s.push back(). В нашем случае цикл forCint i=0;i<10:i++) заталкивает в контейнер десять последовательных чисел от О до 9.

Далее в программе присутствуют очень важные и непривычные нам объявления, обеспечивающие доступ к объектам, входящим в контейнер. Это итераторы at, ini и end.

Итераторы нужны потому, что далеко не каждый контейнер позволяет использовать оператор [ ] для доступа к определенному объекту. Есть контейнеры, разрешающие только последовательный доступ к составляющим их объектам. Чтобы, например, прочитать шестой элемент, нужно прочитать предыдущие пять. Вот в таких контейнерах передвижение от объекта к объекту возможно только с помощью итераторов.

Итераторы - особые объекты. Их смысл в том, что они указывают на объекты, хранящиеся в контейнере. Когда итератору ini присваивается значение, возвращенное функцией s.beginO, он указывает на нулевой элемент контейнера. Слово указывает означает, что итератор знает , где расположен объект с нулевым номером, и в любой момент может получить к нему доступ. Делается это с помощью оператора *. Записав *i ni, мы получаем значение нулевого объекта контейнера, после выполнения инструкций push back() там должен храниться ноль.

Если итератор ini в пашей программе указывает на нулевой элемент контейнера, то итератор end, равный s.endO, указывает на элемент, стоящий сразу за последним элементом контейнера. Двух этих итераторов достаточно для того, чтобы проделать множество сложных действий над элементами контейнера. В нашем примере элементы контейнера сначала подвергаются случайной перетасовке, после которой они гфоизволь-ным образом меняют свои места в контейнере. Перво-

начальный порядок чисел после серии инструкций push back() был таким: 0,1,2,3,4,5,6,7,8,9. После перетасовки порядок (но не сами числа) меняется: 8,1,9,2, 0,5,7,3,4,6. Увидеть этот новый порядок можно с помощью следующей инструкции, в которой для доступа к элемеьггам контейнера используется итератор at:

for(at=ini: at < end; at++) cout *at endl;

Сначала оператор at указывает на нулевой элемент контейнера (at=ini). Применив к этому элементу оператор *at, мы получаем сам этот нулевой элемент, который затем выводится на экран с помощью оператора . Далее наступает очень важный момент: в цикле значение итератора увеличивается (at++), после чего он уже указывает на следующий элемент контейнера. Я нарочно не сказал увеличивается на единицу , потому что итераторы - не числа, и смысл их увеличения иной: после прибавления единицы итератор указывает на следующий объект. Раньше мы говорили, что итератор end указывает на элемент, стоящий непосредственно за последним элементом контейнера. Вот почему в условии выполнения цикла стоит соотношение at < end, а не at <- end.

Наш подробный разбор листинга 4.6 подходит к концу. Осталось рассказать о функции sort О, вызываемой после перетасовки random shut Л еО. Функция sortO расставляет числа в порядке возрастания и тем самым приводит контейнер в первоначальное состояние. Как и функции randomshuffleO, функции sortO достаточно знать первый и последний итераторы сортируемого контейнера. Но, как и функция перетасовки, sortO работает не со всеми контейнерами, а только с теми, где возможен произвольный доступ к любому элементу, осуществляемый оператором []. Объект vector - как раз такой контейнер. Поэтому для вывода элементов мож-



Питание программ

До сих пор наши программы были па голодном пайке : все необходимые данныеони получали из собствен-

ного текста, хотя в 1)сальности они, конечно же, получают пшцу извне и в таких огромных количествах, что суперкомпьютеры, способные производить триллионы операции в секунду, иногда работают годы без передышки .

Пока нам был известен только один канал связи с внешним миром - вывод на экран компьютера с помощью оператора (cout ). Логично предположить, что существует объект, через который вводятся данные, и соответствуюпщй оператор . Этот объект называется с1п, и через него мож1К} вводить данные с клавиатуры компьютера. Программа, показа1Н1ая в листигпс 4.8, вводит с экрана целые числа, .затем складывает их с помощью функции accumulateC) и выводит сумму на экран.

Листинг 4.8

#1nclude <iostream> #include <vector> include <:numeric> using namespace std; int mainC) {

int buf; vector<int> t; whileCcin buf)

t.push backCbuf): cout endl endl: cout accumulateCt.beginO.t.endO.O) endl; }

Вводом чисел заведует цикл whi 1 eCcI n buf). Каждое число вводится с клавиатуры, после нажатия клавиши Enter значение cin buf оказывается равным true, и выполняется тело цикла whi 1еС), в которсм функция pushback засылает очередное число в контейнер. Если же вместо очередного числа ввести букву (то есть символ, не являющийся числом), то выражение ci п buf станет рав-

НО на секунду представить, что вектор - это обычпьп! массив, и записать простой цикл:

forCint i-0;i < s.sizeC):i++) cout s[i] endl:

TIo и тут видна разница между массивом и вектором: в нашем примере для определения размера контейнера используется функция sizeC), которой пет и не может быть у простого массива.

Заметим в заключение, что строку тоже можно считать простейнпш контейнером, ее элементы, как и элементы контейнера, можно сортировать, тасовать, применять к ним другие стандартные фупкщш. Как и у любых контейнеров, у строк есть итераторы, объявляемые так (листи1гг 4.7):

string::iterator at: /

Листинг 4.7

#include <:iostreanp-include <string> include <algorithni> using namespace std: int mainC){

string s= abracadabra : string::iterator at: sortCs.beginO.s.endO): forCat=s.beginC):at < s.endC):at++) cout *at;

Показаиная программа выводит на экран буквы aaaaabbcdrrs - пе меньшую абракадабру, чем первоначальная строка, но зато все буквы теперь расставлены по алфавиту.



1 ... 3 4 5 [ 6 ] 7 8 9 ... 37

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика