Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Шрифт:
Интервал:
Закладка:
int square(int); // объявление функции square
double sqrt(double); // объявление функции sqrt
Обратите внимание на завершающие точку с запятой. Они используются в объявлении функции вместо ее тела, заданного в определении.
int square(int x) // определение функции square
{
return x*x;
}
Итак, если мы хотим просто использовать функцию, то достаточно написать ее объявление, а чаще — выполнить директиву #include. Определение функции может быть в любом другом месте. Это “любое другое место” мы укажем в разделах 8.3 и 8.7. В более крупных программах разница между объявлениями и определениями становится существеннее. В этих программах определения позволяют сосредоточиться на локальном фрагменте программы (см. раздел 4.2), не обращая внимания на остальную часть кода.
4.6. Вектор
Для того чтобы программа делала полезную работу, необходимо хранить коллекцию данных. Например, нам может понадобиться список телефонных номеров, список игроков футбольной команды, список книг, прочитанных в прошлом году, список курсов, график платежей за автомобиль, список прогнозов погоды на следующую неделю, список цен на фотокамеру в интернет-магазине и т.д. Этот перечень можно продолжать до бесконечности, а потому и в программах эти списки встречаются очень часто. В дальнейшем мы рассмотрим множество способов хранения коллекций данных (контейнерные классы, описанные в главах 20 и 21). Пока начнем с простейшего и, вероятно, наиболее полезного способа хранения данных: типа vector (вектор).
Вектор — это последовательность элементов, к которым можно обращаться по индексу. Например, рассмотрим объект типа vector с именем v.
Иначе говоря, индекс первого элемента равен 0, индекс второго элемента — 1 и т.д. Мы ссылаемся на элемент, указывая имя вектора и индекс элемента в квадратных скобках, так что значение v[0] равно 5, значение v[1] равно 7 и т.д. Индексы вектора всегда начинаются с нуля и увеличиваются на единицу. Это вам должно быть знакомым: вектор из стандартной библиотеки С++ — это просто новый вариант старой и хорошо известной идеи. Я нарисовал вектор так, как показано на рисунке, чтобы подчеркнуть, что вектор “знает свой размер”, т.е. всегда хранит его в одной из ячеек.
Такой вектор можно создать, например, так:
vector<int> v(6); // вектор из 6 целых чисел
v[0] = 5;
v[1] = 7;
v[2] = 9;
v[3] = 4;
v[4] = 6;
v[5] = 8;
Как видим, для того чтобы создать вектор, необходимо указать тип его элементов и их начальные значения. Тип элементов вектора указывается после слова vector в угловых скобках (<>). Здесь использован тип <int>, а количество элементов указано после имени в круглых скобках ((6)). Рассмотрим еще один пример.
vector<string> philosopher(4); // вектор из 4 строк
philosopher [0] = "Kant";
philosopher [1] = "Plato";
philosopher [2] = "Hume";
philosopher [3] = "Kierkegaard";
Естественно, в векторе можно хранить элементы только одного типа.
philosopher[2] = 99; // ошибка: попытка присвоить целое число строке
v[2] = "Hume"; // ошибка: попытка присвоить строку целому числу
Когда мы объявляем объект типа vector с заданным размером, его элементы принимают значения, заданные по умолчанию для указанного типа. Рассмотрим пример.
vector<int> v(6); // вектор из 6 целых чисел инициализируется нулями
vector<string> philosopher(4); // вектор из 4 строк инициализируется
// значениями ""
Если вам не подходят значения, заданные по умолчанию, можете указать другие. Рассмотрим пример.
vector<double> vd(1000,–1.2); // вектор из 1000 действительных
// чисел, инициализированных как –1.2
Пожалуйста, обратите внимание на то, что мы не можем просто сослаться на несуществующий элемент вектора.
vd[20000] = 4.7; // ошибка во время выполнения программы
Ошибки, возникающие во время выполнения программы, и работа с индексами описаны в следующей главе.
4.6.1. Увеличение вектора
Часто мы начинаем работу с пустым вектором и увеличиваем его размер по мере считывания или вычисления данных. Для этого используется функция push_back(), добавляющая в вектор новый элемент. Новый элемент становится последним элементом вектора. Рассмотрим пример.
vector<double> v; // начинаем с пустого вектора,
// т.е. объект v не содержит ни одного элемента
v.push_back(2.7); // добавляем в конец вектора v элемент
// со значением 2.7
// теперь вектор v содержит один элемент
// и v[0]==2.7
v.push_back(5.6); // добавляем в конец вектора v элемент
// со значением 5.6
// теперь вектор v содержит два элемента
// и v[1]==5.6
v.push_back(7.9); // добавляем в конец вектора v элемент
// со значением 7.9
// теперь вектор v содержит три элемента
// и v[2]==7.9
Обратите внимание на синтаксис вызова функции push_back(). Он называется вызовом функции-члена; функция push_back() является функцией-членом объекта типа vector, и поэтому для ее вызова используется особая форма вызова.
вызов функции-члена:
имя_объекта.имя_функции_члена(список_аргументов)
Размер вектора можно определить, вызвав другую функцию-член объекта типа vector: size(). В начальный момент значение v.size() равно 0, а после третьего вызова функции push_back() значение v.size() равно 3. Зная размер вектора, легко выполнить цикл по всем элементам вектора. Рассмотрим пример.
for(int i=0; i<v.size(); ++i)
cout << "v[" << i << "]==" << v[i] << 'n';
Этот цикл выводит на экран следующие строки:
v[0]==2.7
v[1]==5.6
v[2]==7.9
Если вы имеете опыт программирования, то можете заметить, что тип vector похож на массив в языке С и других языках. Однако вам нет необходимости заранее указывать размер (длину) вектора, и вы можете добавлять в него элементы по мере необходимости. В дальнейшем мы убедимся, что тип vector из