Урок 75. Массивы. Часть 2

   ⁄ 

 Обновлено 17 Авг 2017

  ⁄   

Этот урок является продолжением первой части о массивах в C++.

Инициализация фиксированных массивов

Элементы массива обрабатываются так же, как и обычные переменные, поэтому они не инициализируются при создании.

Одним из способов инициализации массива является присваивание значений каждому элементу поочередно:

Однако это не совсем удобно, особенно когда массив большой.

К счастью, C++ поддерживает более удобный способ инициализации целых массивов с помощью списка инициализаторов. Следующий пример эквивалентен примеру выше:

Если в этом списке инициализаторов больше, чем может содержать массив, то компилятор выдаст ошибку.

Однако, если в списке инициализаторов меньше, чем может содержать массив, то остальные элементы будут инициализированы значением 0. Например:

Результат:

5
7
9
0
0

Следовательно, чтобы инициализировать все элементы массива значением 0, нужно:

В C++ 11 вместо этого может использоваться синтаксис uniform инициализации:

Длина массива

Если вы инициализируете фиксированный массив с помощью списка инициализаторов, то компилятор может определить длину массива вместо вас, и вам уже не потребуется её объявлять.

Следующие две строки эквивалентны:

Это не только сэкономит время, но также вам не придется обновлять длину массива, если вы захотите добавить или удалить элементы позже.

Массивы и перечисления

Одна из основных проблем с документацией в массивах состоит в том, что целочисленные индексы не предоставляют никакой информации программисту об их значении. Рассмотрим класс из 5 учеников:

Кто представлен элементом testScores[3]? Не ясно.

Это можно решить, используя перечисление, в котором перечислители сопоставляются каждому из возможных индексов массива:

Теперь-то ясно, что представляет собой каждый из элементов массива. Обратите внимание, добавлен дополнительный перечислитель с именем MAX_STUDENTS. Он используется во время объявления массива для гарантирования того, что массив имеет корректную длину (она должна быть на единицу больше самого большого индекса). Это полезно как в целях документации, так и в том, что массив будет автоматически изменен, если добавить еще один перечислитель:

Обратите внимание, этот «трюк» работает только в том случае, если вы не изменяете значения перечислителей вручную!

Массивы и классы enum

Классы enum не имеют неявного преобразования в целочисленный тип, поэтому, если вы попробуете сделать следующее:

То получите ошибку компилятора. Это можно решить, используя static_cast для конвертации перечислителя в целое число:

Однако это также не очень удобно, поэтому лучше использовать стандартное перечисление внутри пространства имен:

Передача массивов в функции

Хотя передача массива в функцию на первый взгляд выглядит так же, как передача обычной переменной, но под капотом C++ обрабатывает массивы несколько иначе.

Когда обычная переменная передается по значению, C++ копирует значение аргумента в параметр функции. Поскольку параметр является копией, то изменение значения параметра не изменяет значение исходного аргумента.

Однако, поскольку копирование больших массивов — дело трудоемкое, то C++ не копирует массив при его передаче в функцию. Вместо этого передается фактический массив. И здесь мы получаем побочный эффект, позволяющий функциям напрямую изменять значение элементов массива!

Следующий пример хорошо иллюстрирует эту концепцию:

Результат:

before passValue: 1
after passValue: 1
before passArray: 1 4 6 8 10
after passArray: 10 8 6 4 1

В примере выше значение переменной value не изменяется в функции main(), так как параметр value в функции passValue() был лишь копией фактической переменной value. Однако, поскольку массив в параметре функции passArray() является фактическим массивом, то passArray() напрямую изменяет значения элементов!

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

Sizeof и массивы

Оператор sizeof можно использовать и с массивами, он вернет общий размер массива (длина массива умножена на размер одного элемента) в байтах. Обратите внимание, из-за того, как C++ передает массивы в функции, эта операция не будет корректно выполнена с массивами, переданными в функции!

Результат:

32
4

(У вас может получиться немного другой результат, если размер типов данных на вашем компьютере отличается от размеров на моем – у меня тип int и указатель занимают 4 байта).

По этой причине будьте осторожны с использованием sizeof() с массивами!

Определение длины фиксированного массива

Трюк: Чтобы определить длину фиксированного массива — разделите размер всего массива на размер одного элемента массива:

Получим:

The array has 8 elements

Как это работает? Во-первых, размер всего массива равен длине массива, умноженной на размер одного элемента. Формула: размер массива = длина массива * размер одного элемента.

Используя алгебру, мы можем изменить это уравнение: длина массива = размер массива / размер одного элемента. sizeof(array) — это размер массива, а sizeof(array [0]) — это размер одного элемента массива, исходя из этого: длина массива = sizeof(array) / sizeof(array[0]). Обычно используется нулевой элемент в качестве элемента массива в уравнении, так как только он является единственным элементом, который гарантированно существует в массиве, независимо от его длины.

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

Термины «размер массива» и «длина массива» чаще всего используются для обозначения длины массива (размер массива в большинстве случаев не очень полезен, разве что в трюке, который мы показали выше). Поэтому в следующих уроках мы будем использовать термин «длина», когда говорим о количестве элементов в массиве, и «размер», когда речь идет о байтах.

Индексирование массива вне диапазона

Помните, что массив длины N содержит элементы массива от 0 до N-1. Итак, что произойдет, если мы попытаемся получить доступ к индексу массиву за пределами этого диапазона?

Рассмотрим следующую программу:

Здесь наш массив имеет длину 5, но мы пытаемся записать значение в 6-й элемент (индекс 5).

C++ не делает никаких проверок, чтобы убедиться, что ваши индексы корректны в соответствии с длиной вашего массива. Таким образом, в примере выше значение 14 будет помещено в ячейку памяти, где 6-й элемент существовал бы, если бы был. Но как вы уже догадались – это будет иметь свои последствия. Например, произойдет перезапись значения другой переменной или вообще сбой программы.

Хотя это происходит реже, но C++ также позволяет использовать отрицательный индекс, что тоже приведет к нежелательным результатам.

Правило: При использовании массивов убедитесь, что ваши индексы корректны в соответствии с диапазоном вашего массива.

Тест

1. Объявите массив для хранения высокой температуры (число с десятыми) каждого дня года (предполагая, что в году 365 дней). Инициализируйте массив значением 0.0 для каждого дня.

2. Создайте перечисление со следующими перечислителями: chicken, lion, giraffe, elephant, duck и snake. Поместите перечисление в пространство имен. Объявите массив, где элементами будут эти перечислители и, используя список инициализаторов, инициализируйте каждый элемент с количеством лап (ног) определенного животного. В основной функции выведите количество ног слона, используя перечислитель.

Ответы

Ответ 1

Примечание: Если размер не является ограничением, то вместо float лучше использовать double.

Ответ 2

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (6 оценок, среднее: 5,00 из 5)
Загрузка...
Поделиться в:
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *