16.05.11 02:02
Массивы в С++ объявляются с указанием количества элементов массива в квадратных скобках после имени переменной массива. Допускаются двумерные массивы, т.е. массив массивов. Ниже приводится определение одномерного массива, содержащего 10 элементов типа int:
Доступ к элементам осуществляется с помощью следующей записи: fibonacci[0], fibonacci[1], … fibonacci[9]. Часто требуется инициализировать массив при его определении:
В таких случаях можно не указывать размер массива, поскольку компилятор может его рассчитать по количеству элементов в списке инициализации:
Статическая инициализация также работает для сложных типов, например для Point2D:
Если не предполагается в дальнейшем изменять массив, его можно сделать константным:
Для нахождения количества элементов в массиве можно использовать оператор sizeof():
Оператор sizeof() возвращает размер аргумента в байтах. Количество элементов массива равно его размеру в байтах, поделенному на размер одного его элемента. Поскольку это долго вводить, распространенной альтернативой является объявление константы и ее использование при определении массива:
Есть соблазн объявить константу как переменную типа const int. К сожалению, некоторые компиляторы имеют проблемы при использовании константных переменных для представления размера массива. Ключевое слово enum будет объяснено далее в этом приложении.
Проход в цикле по массиву обычно выполняется с использованием переменной целого типа. Например:
Массив можно также проходить с помощью указателя:
Мы инициализируем указатель адресом первого элемента и проходим его в цикле, пока не достигнем элемента «после последнего элемента» («одиннадцатого» элемента, fibonacci[10]). На каждом шаге цикла оператор ++ продвигает указатель к следующему элементу.
Вместо &fibonacci[0] можно было бы также написать fibonacci. Это объясняется тем, что указанное без элементов имя массива автоматически преобразуется в указатель на первый элемент массива. Аналогично можно было бы подставить fibonacci + 10 вместо &fibonacci[10]. Эти приемы работают и в других местах: мы можем получить содержимое текущего элемента, используя запись *ptr или ptr[0], а получить доступ к следующему элементу могли бы, используя *(ptr + 1) или ptr[1]. Это свойство иногда называют «эквивалентностью указателей и массивов».
Чтобы не допустить того, что считается необоснованной неэффективностью, С++ не позволяет передавать массивы функциям по значению. Вместо этого передается адрес массива. Например:
Ирония в том, что, хотя С++ не позволяет выбирать между передачей массива по ссылке и передачей по значению, он предоставляет некоторую свободу синтаксиса при объявлении типа параметра. Вместо const int *table можно было бы также написать const int table[] для объявления в качестве параметра указателя на константный тип int. Аналогично параметр argv функции main() можно объявлять как char *argv[] или как char **argv.
Для копирования одного массива в другой можно пройти в цикле по элементам массива:
Для базовых типов, таких как int, можно также использовать функцию std::memcpy(), которая копирует блок памяти. Например:
При объявлении массива С++ его размер должен быть константой[10]. Если необходимо создать массив переменного размера, это можно сделать несколькими способами:
• Выделять память под массив можно динамически:
Оператор new [] выделяет последовательные участки памяти под определенное количество элементов и возвращает указатель на первый элемент. Благодаря принципу «эквивалентности указателей и массивов» обращаться к элементам можно с помощью указателей: fibonacci[0], fibonacci[1], … fibonacci[n — 1]. После завершения работы с массивом необходимо освободить занимаемую им память, используя оператор delete []:
• Можно использовать стандартный класс std::vector<T>:
Обращаться к элементам можно с помощью оператора [], как это делается для обычного массива С++. При использовании вектора std::vector<T> (где T — тип элемента, хранимого в векторе) можно изменить его размер в любой момент с помощью функции resize(), и его можно копировать, применяя оператор присваивания. Классы, содержащие угловые скобки в имени, называются шаблонными классами.
• Можно использовать класс Qt QVector<T>:
Программный интерфейс вектора QVector<T> очень похож на интерфейс вектора std::vector<T>, кроме того, он поддерживает возможность прохода по его элементам с помощью ключевого слова Qt foreach и использует неявное совмещение данных («копирование при записи») как метод оптимизации расхода памяти и повышения быстродействия. В главе 11 представлены классы—контейнеры Qt и объясняется их связь со стандартными контейнерами С++.
Может возникнуть соблазн применения везде векторов std::vector<T> или QVector<T> вместо встроенных массивов. Тем не менее полезно иметь представление о работе встроенных массивов, потому что рано или поздно вам может потребоваться очень быстрый программный код или придется использовать существующие библиотеки С.