Декларация массивов
В Visual Basic различают два вида переменных — простые переменные и переменные структурного типа. Простые переменные служат для идентификации и резервирования памяти под одну единицу данных. Переменные структурного вида предназначены для идентификации и резервирования памяти для нескольких данных. Частным случаем переменной структурного вида является массив. Массив представляет собой структуру, все элементы которой имеют одинаковый тип. Например, это могут быть данные, определяющие вектор или матрицу. Массивы могут быть одномерными и многомерными. Так, для отображения вектора может быть использован одномерный массив, а для отображения матрицы — многомерный.
Декларация массива имеет следующий вид
[Public/ Private] Dim Имя_Массива(индексы) As Тип_Данных
где Dim — ключевое слово, указывающее, что объявляется переменная;
Имя_Массива — идентификатор, определяющий имя массива;
Индексы — значение индекса (номера) последнего элемента в массиве, считая с нулевого;
As — ключевое слово, предваряющее указание типа элементов массива;
Тип_Данных — любой, действительный для Visual Basic тип данных — базовый или созданный пользователем.
Например, декларация одномерного массива из восьми элементов выглядит следующим образом:
Dim MyArray(7) As Integer ‘ Одномерный массив из 8 элементов При декларации многомерного массива в ноле индекса указывается несколько индексов в соответствии с размерностью массива. Например, двумерный массив из шести столбцов и пяти строк декларируется следующим образом:
Dim strMyArray(4,5) As String ‘ Двумерный массив _ из 5 строк и 6 столбцов
По умолчанию значение нижней границы массива при таком объявлении равно нулю. В этом случае говорят, что 0 — базовый индекс массива. При необходимости базовый индекс можно изменить путем использования ключевого слова То при объявлении массива: Dim MyArray (3 То 10) As String
В этом примере базовому индексу массива установлено значение 3. Подобным образом можно устанавливать как положительные, так и отрицательные базовые индексы:
Dim MyArray (—3 То 4) As String
Иногда в процессе выполнения программы размер массива требуется изменить. В этом случае первоначально массив декларируют как динамический. Для этого в декларации не указывается размерность, например:
Dim MyArray () As String
Количество элементов в динамическом массиве и его размерность в процессе выполнения программы можно переопределить с помощью ключевого слова ReDim. Синтаксическая конструкция переопределения массива имеет вид
ReDim [Preserve] ИмяМассива(индексы) [As ТипДанных],
где ReDim — ключевое слово, указывающее, что переопределяются размеры массива;
Preserve — необязательное ключевое слово, с помощью которого дается указание, чтобы все элементы переопределяемого массива сохранили свое значение;
индексы — размерности массива (до 60).
Dim MyArray () As String ‘Декларация динамического массива
Dim ValArray As Integer ‘Декларация переменной, _
для хранения размерности массива
ValArray=9 ‘Инициализация значения
ReDim strMyArray (intValArray) ‘Одномерный массив _
из 10 элементов (базовый индекс равен 0)
ReDim MyArray (3 То ValArray, 1 То ValArray) ‘ Двумерный _ массив с базовыми индексами, отличными от нуля
Объявление массива
Массивы должны быть объявлены до их использования в программе.
Dim | Public | Private Имя_Массива (Размерность_Массива) As Тип_Данных
Dim | Public | Private – ключевые слова, декларирующие массив
и область его видимости;
Имя_Массива – идентификатор, определяющий имя массива;
Размерность_Массива – значение нижней и верхней границы значения
индекса (номера) соответствующей размерности.
Допускается описание до 60 размерностей.
As – ключевое слово, предваряющее указание типа
Тип_Данных – любой, действительный для VBA тип данных
(базовый или созданный пользователем).
Dim A (7) As Integer
Объявляется одномерный массив (вектор) А из 8 целых чисел, причем по умолчанию первый элемент массива будет А(0), а последний А(7).
При объявлении многомерного массива в поле индекса указывается несколько индексов в соответствии с размерностью массива.
Dim B (4, 5) As Single
Объявляется двумерный массив В 4 х 5 (матрица), состоящая из 5 строк и 6 столбцов действительных чисел.
По умолчанию значение нижнее границы массива при таком объявлении равно нулю. В этом случае говорят, что 0 – базовый индекс массива. Можно изменить базовый индекс, написав в области описания модуля (General Declarations) инструкцию Option Base 1. После этого индексы массивов А и В будут нумероваться с единицы.
Другим способом изменения базового индекса является использование ключевого слова To при объявлении массива.
Dim A (1 To 7) As Integer
Dim B (1 To 4, 1 To 5) As Single
В этом примере базовому индексу массива установлено значение 1.
Подобным образом моно устанавливать как положительные, так и отрицательные базовые индексы
Dim Z (-3 To 7) As Single.
Динамические массивы
Иногда в процессе выполнения программы требуется изменять размер массива. В этом случае первоначально массив объявляют как динамический. Для этого при объявлении массива не надо указывать его размерность.
Dim R () As Single.
Затем в программе следует вычислить необходимое количество элементов массива и сохранить его в некоторой переменной, например n, а затем изменить размер динамического массива с помощью оператора ReDim.
Синтаксическая конструкция переопределения массива:
ReDim [Preserve] Имя_Массива (Размерность_Массива) As Тип_Данных
ReDim – ключевое слово, указывающее, что переопределяются размеры массива;
Preserve – необязательное ключевое слово, используемое для сохранения данных в существующем массиве при изменении значения последней размерности. Если оно не используется, то данные в массиве при изменении размерности не сохраняются.
Имя_Массива – имя массива, удовлетворяющее стандартным правилам именования переменных;
Размерность_Массива — значение нижней и верхней границы значения индекса (номера) соответствующей размерности (до 60). Если отсутствует инструкция Option Base, нижняя граница индекса по умолчанию равна 0.
Тип_Данных – тип данных массива.
Dim A () As Integer ‘Объявление динамического массива
Dim n As Integer ‘Объявление переменной, для хранения размерности
N = 9 ‘Инициализация значения
ReDim A (n) ‘Одномерный массив из 10 элементов
ReDim A (3 To n, 1 To n) ‘Двумерный массив с базовыми индексами
Примечание. Оператор ReDim изменяет размерность массива, но не тип его элементов.
Как декларируются и формируются массивы
Массивом на языках программирования называют совокупность однотипных элементов данных, к которым можно получить доступ по имени массива и индексу (или индексам, если массив многомерный). Индекс это по сути номер элемента в массиве. Самый простой массив — одномерный, его можно рассматривать как список, двумерный массив похож на таблицу. Язык C не накладывает никаких ограничений на размерность массивов, хотя тут может вмешиваться специфика платформы и соответствующего компилятора.
Век живи, век учись — язык программирования C постоянно преподносит разные сюрпризы. Встретился с необычным для меня способом декларации инициализированного массива.
Для меня такой способ создания массива был в диковинку, не сразу понял что тут происходит. Загрузил код в отладчике и выяснил, что это определение массива совершенно эквивалентно следующему определению:
Покопался в Интернете, и нашел интересное для себя описание декларации массивов [1]. Оказывается, при декларации инициализированного массива можно присваивать элементы по индексу в квадратных скобках, причем в таком случае инициализации можно записывать в любом порядке. Пропущенные элементы будут при этом автоматически заполняться нулями. Например:
Эта декларация создаст следующий массив, в нем пропущенный элемент с индексом 1 будет заполнен нулем:
В некоторых источниках для массивов придумывают специфичные названия. Например, одномерные массивы называют векторами, двумерные массивы матрицами, и называют массивы просто массивами, когда размерность массива больше 2, или не определена, или не имеет принципиального значения.
[Декларация массива]
Массив переменных декларируется идентично переменной — точно так же указывается тип данных перед именем. Отличие в том, что за именем идут квадратные скобки — по паре скобок для каждого измерения массива (одна пара для одномерного массива, две пары для двумерного, и т. д.). Не инициализированные массивы обязательно должны указывать внутри этих пар квадратных скобок величину размерности. Т. е. эта величина для одномерного массива указывает, сколько в векторе строк, для двумерного массива — сколько в матрице столбцов и строк, и т. д. Величина размерности должна быть положительным целым числом, не равным нулю, и обычно это константа, доступная на время компиляции (обрабатываемая препроцессором).
В стандарте C99 величина размерности все еще должна быть положительным целым значением. Но тут уже можно использовать переменные, пока переменная имеет положительное значение в момент декларации массива. Память под массив при этом выделяется только один раз, в момент декларации массива (т. е. статически), и такие массивы не могут менять свои размеры позже, даже если если переменная, используемая для декларации массива, во время выполнения поменяла свое значение.
Примеры только для C99:
[Инициализация массивов]
Массивы могут быть инициализированы в момент своей декларации точно так же, как могут быть инициализированы обычные переменные. Помещайте данные инициализации внутри фигурных скобок <>, которые идут за знаком равенства = после имени массива. Обратите внимание на запятые в примерах ниже.
Массивы могут быть также инициализированы частично, если предоставлено меньше значений для инициализации, чем размер массива. Остальные элементы в таком случае будут автоматически проинициализированы нулем.
Если массив инициализируется полностью, то величину размерности внутри квадратных скобок указывать не обязательно. Компилятор автоматически определит размер массива, чтобы в нем поместились все инициализированные данные (могут быть вариации для многомерных массивов, о чем далее).
Назначенные инициализаторы. В C99 есть альтернативный механизм, который позволяет инициализировать определенные элементы массива — по индексу в квадратных скобках. Причем не обязательно инициализированные элементы должны идти первыми, и необязательно даже соблюдать порядок следования инициализированных элементов. Этот метод можно смешивать с традиционной инициализацией. Например:
В этом примере первые три элемента инициализированы значениями 1, 2 и 3 соответственно, как обычно. Затем элемент 10 (11-й элемент массива) инициализирован значением 15, все промежуточные элементы — от 3 до 9 включительно — при этом автоматически инициализируются нулями. Следующие 2 элемента (12-й и 13-й) инициализируются значениями 11 и 12 соответственно. Элемент 60 (61-й) инициализируется значением 50, и элемент 42 (43-й) значением 420. Обратите внимание, что назначенные инициализаторы не требуют, чтобы они следовали друг за другом по индексам в порядке увеличения).
Как и в традиционных методах инициализации, все не инициализированные элементы (инициализаторы которых опущены) автоматически получают нулевое инициализированное значение. Если размер массива не указан, то его размер определяется по самой большой по индексу инициализированной позиции.
[Использование массивов]
В этом первом примере программа использует циклы и массивы для вычисления первых двадцати чисел Фибоначчи. Числа Фибоначчи используются для определения точек выборки в определенных методах оптимизации.
[Многомерные массивы]
Многомерные массивы декларируются предоставлением большего количества пар квадратных скобок после имени переменой.
Одномерный массив не требует указания величины размерности, если он полностью инициализирован. По аналогии многомерный массив не требует указания значения первой величины размерности, если массив полностью инициализирован. Все остальные значения размерности после первой должны присутствовать в любом случае.
Для двумерных массивов первая величина размерности обычно используется для количества строк, и вторая для количества столбцов. Мы будем использовать это соглашение при обсуждении двумерных массивов.
Двумерные массивы рассматриваются в C/C++ как массив одномерных массивов. Например, int numbers[5][6] обозначает одномерный массив из 5 элементов, где каждый элемент — одномерный массив из 6 целых чисел. Если идти дальше, то int numbers[12][5][6] это массив из 12 элементов, каждый из которых двумерный массив, и так далее.
Другой способ представить себе организацию многомерных массивов — язык C сохраняет в памяти двумерные массивы по строкам, где все элементы одной строки сохраняются вместе как единая информационная единица. Если это четко представлять себе, то это позволит иногда писать более эффективные программы.
Многомерные массивы могут быть полностью инициализированными путем перечисления всех элементов данных внутри одиночной пары фигурных скобок <>, как это делается с одномерными массивами. Самая лучшая практика программирования — закрывать каждую строку в фигурные скобки как отдельное подмножество элементов, чтобы делать программу более понятной и читаемой. Это необходимо для частичной инициализации каждой строки, которая не является последней. При использовании подмножеств элементов внутри фигурных скобок за последним подмножеством не обязательно указывать запятую, но сами подмножества разделяются запятыми.
Многомерные массивы могут быть частично инициализированы, если данные инициализации предоставлены не полностью. Отдельные строки многомерных массивов могут быть инициализированы частично при условии, что используются фигурные скобки для подмножества.
К отдельным элементам данных в многомерных массивах получают доступ путем полного указания всех индексов для элемента. Альтернативно к массиву меньшей размерности может быть доступен путем частичного разрешения имени массива. Например, если «data» был декларирован как трехмерный массив чисел float, то data[1][2][5] означает одно число float, data[1][2] означает одномерный массив чисел float, и data[1] будет относится к двумерному массиву чисел float. Причина такого принципа реализации связана с проблемами управления памятью, которые не входят в область рассмотрения этой статьи.
Пример программы, где используются двумерные (2D) массивы (написана в мае 1995 года, автор George P. Burdell):
Дальнейший материал до последнего времени не соответствует области действия стандарта CS 107.
[Передача массивов в функции (на C++)]
Существует 2 метода передачи обычных данных в функции:
Pass-by-Value (передача по значению). Функция получает копию данных, и все изменения над ними производится в функции локально, без передачи за пределы тела функции.
Pass-by-Reference (передача по ссылке). Функция получает значение переменных по указателю (псевдониму), так что все изменения переменной внутри функции отразятся в данных кода, который вызвал функцию.
Если в функцию передается отдельный элемент массива, то это происходит в соответствии с базовым типом данных. Таким образом, если nums был декларирован как одномерный массив чисел int, то передача nums[i] в функцию произойдет точно так же, как если бы передавалось обычное значение int — либо pass-by-value, либо pass-by-reference, в зависимости от того, как написана функция.
Однако когда массив передается в функцию целиком, он всегда передается по ссылке. На самом деле массив передается по указателю/адресу, и тонкости терминологии здесь не рассматриваются, но функционально это работает как передача pass-by-reference. В результате происходит следующее: все изменения над данными переданного в функцию массива повлияют на данные массива вне функции, т. е. в коде, который вызвал эту функцию.
Поскольку массивы передаются в функцию по ссылке, то в сущности функции не нужно «возвращать» массив. Она просто должна заполнить массив, предоставленный вызывающим кодом. Однако функции могут возвращать массив, но это требует использования указателей и адресов, также часто требует использования динамического выделения памяти, и все это выходит за рамки рассмотрения этой статьи.
Чтобы не допустить функции менять значения переданного массива, то он в параметре должен быть передан с ключевым словом const.
Когда в функцию передается массив целиком, то размер массива обычно передается в отдельном аргументе функции.
Для одномерного массива в списке формальных параметров функции нет необходимости указывать размерность массива. Если такая размерность предоставляется, компилятор игнорирует его. Для многомерного массива все измерения, кроме первого, должны присутствовать в списке формальных параметров функции. Первая размерность опциональна, и будет игнорироваться компилятором.
В функцию может быть передан частично определенный многомерный массив, и он будет обрабатываться как массив меньшей размерности. Например, одна строка двумерного массива может быть передана в функцию, которая ожидает передачи одномерного массива. Понятно, что по причинам организации данных в памяти может быть передана только строка, но не столбец двумерного массива.
Обратите внимание, как используются массивы в примерах ниже. В вычислении max4, передается двумерный массив, содержащий 2 строки из 3 элементов, как если бы это был одномерный массив из 6 элементов. Это читерство, но однако работает из-за способа организации данных в памяти многомерных массивов.
Результат вывода программы:
[Строки символов как массивы символов]
Класс «string» это новый тип, добавленный в C++, который не существовал в традиционном C. Традиционный метод обработки строк символов подразумевал использование массива символов. В качестве маркера конца строки использовался нулевой байт (символьная константа ‘\0’), это называется ASCIIZ-строка, или null-terminated array. Строки, обозначенные двойными кавычками («Please enter a number > «) сохраняются в памяти null-terminated массивы.
Библиотека cstring содержит несколько функций для взаимодействия с традиционными массивами символов. Объекты C++ string могут быть инициализированы традиционными массивами стиля C:
Как декларируются и формируются массивы
7.1.5 Области видимости переменных и констант
Переменная может быть доступна для всей программы или только для одной или нескольких ее частей. Область программы, в которой может быть использована переменная, называется областью видимости переменной. Переменные могут быть видимы в одной процедуре, в любой процедуре какой – либо формы или во всей программе. Если переменная видима, то она доступна и, следовательно, существует. Переменная может существовать и быть доступной для некоторых частей программы и при этом быть недоступной (“невидимой”) для других частей программы. Пример:
Dim strФамилия As String * 18 ‘Глобальная переменная
Dim strИмя As String * 10 ‘Глобальная переменная
Private Sub UserForm_Initialize()
Dim str Адрес As String * 30 ‘ Локальная переменная
strАдрес = “Москва, Кронштадская, дом 37”
Вывод str Адрес
Sub Вывод (strD As String)
Dim strФамилия As String * 18 ‘Локальная переменная
strФамилия = “Это уже не Петров!”
В результате выполнения этой программы в окнах вывода будет следующий текст:
Это уже не Петров!
Москва, Кронштадская, дом 37.
Приведем пояснения: strФамилия и strИмя объявлены как глобальные переменные и существуют пока программа выполняется. StrАдрес и strD являются локальными переменными и существуют лишь тогда, когда выполняется процедура Вывод, в которой они объявлены. В момент вызова этой процедуры глобальная переменная strФамилия существует, но является недоступной, так как ее область видимости перекрыта одноименной локальной переменной, поэтому в окно вывода будет выдано значение той переменной strФамилия, которая объявлена в процедуре Вывод. Переменная strИмя также является глобальной, но она доступна для процедуры Вывод. Переменная strАдрес объявлена в процедуре UserForm _ Initialize , но она доносит значение до окна вывода, так как передается в процедуру Вывод в качестве параметра.
Область видимости переменной задается при ее декларации одним из ключевых слов:
Dim – объявляет локальные переменные, существующие только во время вызова процедур или функций, в которых они объявлены. Если переменная объявляется в разделе глобальных объявлений модуля или формы, то она доступна для всех процедур и функций этого модуля. Для других модулей она будет не видна.
Private — не может объявлять переменную внутри процедуры или функции, при объявлении в разделе глобальных объявлений модуля Dim и Private равнозначны.
Public- объявленная таким образом переменная является глобальной на уровне приложения и доступна из всех его модулей.
Различают динамические и статические переменные. Статические переменные объявляются внутри процедуры или функции и вне их недоступны. В отличие от обычных локальных переменных они не инициализируются при входе в процедуру или функцию, где они объявлены. Для создания статической переменной необходимо при ее объявлении вместо ключевого слова Dim указать слово Static:
Static intNumber As Integer
7.1.6 Декларация массивов
В Visual Basic различают два вида переменных – простые переменные и переменные структурного типа. Простые переменные служат для идентификации и резервирования памяти под одно данное. Переменные структурного вида предназначены для идентификации и резервирования памяти для нескольких данных. Частным случаем переменной структурного вида является массив. Массив представляет собой структуру, все элементы которой имеют одинаковый тип. Например, это могут быть данные, определяющие вектор или матрицу. Массивы могут быть одномерными и многомерными. Так, для отображения вектора может быть использован одномерный массив, а для отображения матрицы – многомерный.
Декларация массива имеет следующий вид:
[Public/ Private] Dim Имя_Массива(индексы) As Тип_Данных
где Dim– ключевое слово, указывающее, что объявляется переменная;
Имя_Массива – идентификатор, определяющий имя массива;
Индексы – значение индекса (номера) последнего элемента в массиве, считая с нулевого;
As – ключевое слово, предваряющее указание типа элементов массива;
Тип_Данных – любой, действительный для Visual Basic тип данных – базовый, или созданный пользователем.
Например, декларация одномерного массива из восьми элементов выглядит следующим образом:
Dim MyArray(7) As Integer ‘ Одномерный массив из 8 _
При декларации многомерного массива в поле индекса указывается несколько индексов, в соответствии с размерностью массива. Например, двумерный массив из шести столбцов и пяти строк декларируется следующим образом:
Dim strMyArray(4,5) As String ‘ Двумерный массив _
из 5 строк и 6 столбцов
По умолчанию значение нижней границы массива при таком объявлении равно нулю. В этом случае говорят, что 0 – базовый индекс массива. При необходимости базовый индекс можно изменить путем использования ключевого слова To при объявлении массива:
Dim MyArray (3 To 10) As String
В этом примере базовому индексу массива установлено значение 3. Подобным образом можно устанавливать как положительные, так и отрицательные базовые индексы:
Dim MyArray (-3 To 4) As String
Иногда в процессе выполнения программы размер массива требуется изменить. В этом случае первоначально массив декларируют как динамический. Для этого в декларации не указывается размерность, например:
Dim MyArray () As String
Количество элементов в динамическом массиве и его размерность в процессе выполнения программы можно переопределить с помощью ключевого слова ReDim. Синтаксическая конструкция переопределения массива имеет вид:
ReDim [Preserve] ИмяМассива(индексы) [As ТипДанных],
где ReDim – ключевое слово, указывающее, что переопределяются размеры массива;
Preserve – необязательное ключевое слово, с помощью которого дается указание, чтобы все элементы переопределяемого массива сохранили свое значение;
индексы – размерности массива (до 60).
Dim MyArray () As String ‘Декларация динамического _
Dim ValArray As Integer ‘Декларация переменной, _
для хранения размерности массива
ValArray=9 ‘Инициализация значения
ReDim strMyArray (intValArray) ‘Одномерный массив _
из 10 элементов (базовый индекс равен 0)
ReDim MyArray (3 To ValArray, 1 To ValArray) ‘ Двумерный _ массив с базовыми индексами, отличными от нуля