array
Массив объединяет несколько переменных одного типа под одним именем — обращайтесь к элементам по индексу и удобно обрабатывайте их в цикле for.
Полная статья
Описание
Массив объединяет несколько переменных одного типа под одним именем. Вместо того чтобы заводить отдельные переменные sensor1, sensor2, sensor3 и так далее, вы объявляете один массив и обращаетесь к его элементам по индексу. Это особенно удобно, когда нужно обрабатывать серию однотипных данных: показания датчиков, яркость светодиодов, ноты мелодии.
В Arduino используется C++, поэтому массивы здесь работают по правилам этого языка — строго типизированы, фиксированного размера и без автоматической проверки границ.
Создание (объявление) массива
Существует несколько равнозначных способов объявить массив:
// Объявление массива заданной длины без инициализации значений:
int myInts[6];
// Объявление массива без явного указания размера (компилятор
// подсчитывает элементы и создаёт массив подходящего размера):
int myPins[] = {2, 4, 8, 3, 6, 4};
// Объявление массива заданной длины с инициализацией значений:
int mySensVals[5] = {2, 4, -8, 3, 2};
// При объявлении массива типа char его нужно сделать на один элемент длиннее,
// чтобы вместить обязательный нулевой символ завершения строки:
char message[6] = "hello";
Можно задать только размер — тогда элементы будут содержать случайные значения из памяти, пока вы их не инициализируете. Можно сразу перечислить значения — компилятор сам посчитает размер. Можно указать и размер, и начальные значения одновременно.
Доступ к элементам массива
Индексация в C++ начинается с нуля. Это значит, что первый элемент массива имеет индекс 0, второй — 1, и так далее:
mySensVals[0] == 2, mySensVals[1] == 4, и так далее.
Если массив объявлен на десять элементов, последний из них имеет индекс 9, а не 10:
int myArray[10]={9, 3, 2, 4, 3, 2, 7, 8, 9, 11};
// myArray[9] содержит 11
// myArray[10] недопустимый индекс, содержит случайные данные (другой адрес памяти)
Это одна из самых распространённых ошибок в работе с массивами. Обращение по индексу, равному размеру массива или большему, — это выход за пределы выделенной памяти. Компилятор C++ такую ошибку не поймает: программа скомпилируется, но при запуске начнёт читать или перезаписывать чужую память. Последствия непредсказуемы: неверные данные, зависание скетча, перезапуск платы. Отлаживать такие ошибки особенно неприятно, потому что симптомы могут проявляться совсем не там, где находится ошибка.
В отличие от Java или Python, C++ не генерирует исключение при выходе за границы массива — он просто обращается к произвольной ячейке памяти.
Запись значения в массив:
mySensVals[0] = 10;
Чтение значения из массива:
x = mySensVals[4];
Массивы и циклы for
Массивы особенно удобны в паре с циклом for: счётчик цикла выступает индексом, и вы можете последовательно обработать все элементы без дублирования кода. Например, чтобы вывести весь массив в Serial Monitor:
for (byte i = 0; i < 5; i = i + 1) {
Serial.println(myPins[i]);
}
Тот же подход используется для заполнения массива, поиска минимума и максимума, усреднения показаний датчиков и любой другой обработки серии значений.
Где применяется
- Хранение показаний датчиков — записать несколько измерений подряд и затем усреднить их, чтобы сгладить шум.
- Управление группой светодиодов — хранить номера пинов или уровни яркости в массиве и в цикле применять их к каждому светодиоду.
- Воспроизведение мелодии — держать частоты нот и их длительности в двух массивах и перебирать их в цикле.
- Буфер для приёма данных — накапливать байты из Serial в массив символов перед разбором команды.
Практические замечания
- Размер массива задаётся на этапе компиляции и не может измениться во время выполнения программы. Если нужна динамическая коллекция, это уже другая тема (динамическое выделение памяти), и для Arduino-новичков она не рекомендуется.
- Всегда проверяйте, что индекс в цикле не превышает
размер - 1. Безопаснее всего использовать конструкциюfor (int i = 0; i < размер; i++). - Если вы объявляете массив без инициализации, его элементы содержат «мусор» — случайные значения, оставшиеся в памяти. Инициализируйте явно или заполняйте в
setup(). - Глобальные массивы занимают статическую RAM всё время работы программы. На платах с малым объёмом памяти (например, Arduino Uno с 2 КБ RAM) большие массивы могут вытеснить стек и вызвать трудноуловимые сбои.
- Чтобы узнать количество элементов массива в коде, используйте выражение
sizeof(arr) / sizeof(arr[0])— это безопаснее, чем хранить размер в отдельной переменной и рисковать рассинхронизацией.
Пример кода
Полную программу с демонстрацией массивов можно посмотреть во встроенном примере Arduino: Arrays.