Массивы Arduino

Массивы Arduino – это элемент языка, активно используемый программистами для работы с наборами однотипных данных. Массивы есть практически во всех языках программирования, не исключением является и Arduino, синтаксис которого сильно похож на С++. Есть много примеров, когда без использования массивов практически невозможно написать работоспособную программу, поэтому обойти эту тему без внимания нельзя. К сожалению, незнание нюансов и особенностей работы с массивами в Ардуино часто приводит к скрытым или явным ошибкам работы скетча. В этой статье мы попробуем разобраться с самыми основами: узнаем, что такое одномерные и многомерные массивы, научимся создавать их и работать с данными, хранящимися в массивах.

Что такое массивы

Если вы уже не новичок в программировании и прекрасно знаете, что такое массивы и как они работают, то можете смело перейти к следующему разделу статьи. А для начинающих мы все-таки попробуем кратко и доступно пояснить концепцию массивов.

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

Так и в массивах Ардуино – вы создаете структуру данных, поделенных на равные ячейки. Чтобы найти выбрать нужную ячейку, достаточно знать только ее номер по порядку. Это очень удобно – не нужно придумывать адрес или название для каждой из них. По сути своей, массивы — это такой большой набор переменных, у которых есть общее имя, а для поиска каждой отдельной переменной используется просто ее порядковый номер.

Для чего все-таки нужны массивы? Почему нельзя обойтись обычными переменными? Ответ становится очевидным на следующем примере. Представьте, что вам нужно хранить вместе большое количество (например, 1000) символов текста. Без массива вам пришлось бы создать переменную для каждого символа – и так 1000 переменных. И при этом у вас не было бы возможности пробежать в цикле по всем символам и, скажем, изменить их регистр – пришлось бы вставлять 1000 строк кода для каждой такой операции. А если мы заранее не знаем, какой будет текст? Или нам нужно скопировать часть символов из одной строки в другую? В такой постановке задача без использования массивов становится невыполнимой.

Массивы Arduino

В Ардуино мы можем использовать те же инструменты для работы с массивами, что и в С++. Все основные операции с массивами можно разделить на следующие группы:

  • Создание и инициализация массива.
  • Операции с элементами массива (поиск, добавление, удаление).
  • Изменение длины массива.
  • Удаление массива.

В статье мы рассмотрим все эти операции более подробно.

Создание массива

При создании мы обязательно указываем тип массива, название массива и специальные символы “[“  и “]”. Также мы обязательно задаем размер массива явным или неявным образом. Вот пример создания массива из 5 элементов типа int.


int sensorValues[5]; // такое декларирование массива происходит без объявления его элементов, указывается только размерность.

В этом примере:

  • int – тип данных, которые будут содержаться в массиве (в данном случае int).
  • sensorValues – название массива (одновременно является указателем на него).
  • [5] – размер массива, компилятор заложит инструкции, которые выделят память под этот массив в рамзмере 5*2 = 10 байтов. 5 элементов по 2 байта.

При создании массива можно сразу инициализировать его содержимое, это делается с помощью символов {}:

  • int arrPins[] = {3, 6, 4, 3, 7}- в данном случае объявляются элементы, а размерность не декларируется. Размерность массива происходит компилятором автоматически (в приведеном примере определены 5 элементов, значит размер массива равняется 5).

Можно одновременно задать размер массива и проинициализировать элементы:

  • int arrValues[6] = {5, 654, 120, 982, 15}; — выделяется размер и выполняется инициализация некоторых элементов.

Пример массива, состоящего из символов (тип char), который мы сразу инициализируем символами из строки:

  • char message[5] = «hello»;

Разновидности массивов Ардуино

Массивы, размерность которых представлена одним символом являются одномерными. Массивы, в которых каждый элемент может сам являться массивом, называются многомерными. В многомерных массивах имеется несколько индексов, для каждого из «подмассивов». Вот примеры создания массивов разных размерностей:

  • int array1[10]; // одномерный массив из 10 элементов
  • int array2[10][2]; // двумерный массив из 10 элементов, каждый из которых является массивом из 2 элементов.
  • int array3[10][2][5]; // многомерный массив из 10 элементов, каждый из которых является массивом из 2 элементов, каждый из которых состоит из 5 элементов… в доме, которой построил Джек.

Массивы ArduinoМногомерные массивы полезны, если нам нужно хранить вложенные структуры данных. Например, текст состоит из массива абзацев, каждый из которых содержит массив строк, каждая из которых содержит массив элементов типа char.

Обращение к элементам массива

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

Внимание! Индексация массивов в Arduino, так же как в C++, начинается с 0. Первым элементом массива будет элемент с индексом 0


int values[10];

values[0] == 10; // Записываем цифру 10 в первый элемент массива

values[3] == 4; // Записываем цифру 4 в 4 элемент массива (индекс 3)

 

Работа с массивами всегда требует особой внимательности от программиста. Вы можете обратиться к несуществующему элементу массива, если неверно зададите индекс. Иллюстрация в следующем примере


int values[10];  // Определили массив с 10 элементами.

values[15] = 20; // Попросили дать значение элемента с индексом 15. Возникнет ошибка во время выполнения.

Компилятор Arduino здесь не является надежным помощником, потому что не сообщит вам об ошибке на этапе компиляции. Но во время исполнения ошибка приведет к краху программы с сообщением о том, что индекс вышел за пределы массива: Index Out Of Bound Exception.

Еще одной часто возникающей ошибкой является путаница с индексом и номером по порядку:


int values[] = {1,2,3};

x = values[0]; // Вернет число 1, первый элемент массива

x = values[2]; // Вернет число 3, последний элемент массива

x = values[3]; // Уже ничего не вернет, возникнет ошибка, т.к. мы обратимся к элементу с индексом 3, т.е. к четвертому элементу, хотя в массиве всего 3 элемента.

Длина массива в Ардуино

Для определения количества элементов в массиве нужно узнать весь объем памяти, выделенный под массив и поделить его на объем памяти каждого элемента. В Ардуино, как и в C++, размер памяти определяется с помощью оператора sizeof. Пример для массива из значений типа int выглядит следующим образом:

sizeof(myInts)/sizeof(int)

Для вычисления объема массива в памяти нужно перемножить количество элементов на размер в байтах одного элемента. Это же касается и двумерных массивов:

размер массива = число байт второго измерения * число байт первого измерения * sizeof (базовый тип)

Массивы и циклы Arduino

Циклы – удобный метод для работы с массивами, они применяются для повторения одинаковых действий, делая код программы компактным. Индексация каждого элемента в таком случае осуществляется при помощи переменной-счетчика цикла.

Например, для отображения на мониторе элементов массива можно использовать такой цикл for:


for (int i = 0; i < 5; i++) {
 Serial.println(values[i]); // печатаем каждый из 5 элементов массива
}

Массив строк

Лучшим примером двумерного массива является массив строк. Первое измерение (строки) этого массива состоят из списка элементов символов типа char. Статичная инициализация такого массива выглядит так:

char string_array[3][80] = {«String1», «String2», «String3»};

Для перебора элементов массива можно использовать тот же цикл for. В данном примере мы перебираем все элементы массива и выводим их в монитор порта. После завершения вывода строки мы просим ардуино перевести строку на экране.


  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 80; j++) {
      Serial.print(string_array[i][j]);
    }
    Serial.println("");
  }

 

Использование массивов в функциях

Мы можем передавать массивы функции, помещая название массива в качестве аргумента.

int values[] = {1,2,3};
printArray(values);

void printArray(int arr[]) {
  for(int i=0; i<sizeof(arr)/sizeof(int);i++){
    Serial.print("Элемент ");
    Serial.print(i);
    Serial.print(": ");
    Serial.println(arr[i]);
  }

}

Название массива является одновременно и указателем. В С++ указатель – это переменная, которая содержит адрес адреса данных. Таким образом, в имени массива уже содержится информация для того, чтобы найти начало массива.

Краткие выводы

С помощью массивов в Arduino можно оперировать с большими наборами данных, например, собирать информацию со многих подключенных данных или формировать сигналы для нескольких подключенных светодиодов. Массивы используют для хранения строк и достаточно сложно организованных структур данных. Использование массивов в Ардуино во многом похоже на C++ и требует понимания принципов адресной арифметики, постоянного контроля со стороны программиста за размерностью и типами. Но взамен массивы предоставляют гибкие возможности по хранению и динамическому изменению наборов данных. Без них написание достаточно сложных программ практически невозможно.

Ссылки

В статье использовались графические материалы следующих сайтов: http://www.yaklass.ru, http://www.youngcoder.net.

ПОДЕЛИТЬСЯ

ОСТАВЬТЕ ОТВЕТ

Please enter your comment!
Please enter your name here