Строки используются для хранения текста. Их можно использовать для отображения текста на ЖК-дисплее или в окне Монитор порта Arduino IDE.
Строки также полезны для хранения пользовательского ввода — например, символов, которые пользователь вводит на клавиатуре, подключенной к Arduino.
В программировании Arduino есть два типа строк:
1) Массивы символов, которые совпадают со строками, используемыми в программировании на C
2) Arduino string, которая позволяет нам использовать строковый объект в скетче.
Строки, объекты и то, как использовать строки в скетчах Arduino, полностью объясняются в этой статье. На вопрос, какой тип строки использовать в скетче, дан ответ в конце статьи.
Строковые массивы символов
Первый тип строки, которую мы рассмотрим, — это строка, представляющая собой серию символов типа char. В предыдущей статье было показано, что массив — последовательная серия переменных одного и того же типа, хранящихся в памяти. Строка — это массив переменных типа char.
Строка — это специальный массив, который имеет один дополнительный элемент в конце строки, который всегда имеет значение 0 (ноль). Она известно как «строка с завершающим нулем».
Скетч примера массива строковых символов
Этот пример покажет, как сделать строку и показать ее в окне Монитор порта:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void setup() { char my_str[6]; // массив, достаточно большой для строки из 5 символов Serial.begin(9600); my_str[0] = 'H'; // строка состоит из 5 символо my_str[1] = 'e'; my_str[2] = 'l'; my_str[3] = 'l'; my_str[4] = 'o'; my_str[5] = 0; // 6-й элемент массива - нулевое значение Serial.println(my_str); } void loop() { } |
В скетче показано, из чего состоит строка — она состоит из массива символов с печатаемыми символами и 0 (нулем) в последнем элементе массива, чтобы показать, что здесь заканчивается строка.
Строку можно посмотреть в окне Монитор порта Arduino IDE, используя Serial.println () и передав ему имя строки.
Этот же скетч удобнее записать так:
1 2 3 4 5 6 7 8 9 10 |
void setup() { char my_str[] = "Hello"; Serial.begin(9600); Serial.println(my_str); } void loop() { } |
В этом скетче компилятор вычисляет размер массива строк, а также автоматически завершает строку нулем. Массив из шести элементов, состоящий из пяти символов, за которыми следует ноль, создается точно так же, как и в предыдущем скетче.
Строки и символы
Символы пишутся в одинарных кавычках следующим образом:
1 |
'w' |
Строки заключаются в двойные кавычки следующим образом:
1 |
"Это строка" |
Управление массивами строк
Мы можем изменить массив строк в скетче, как показано в следующем скетче.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
void setup() { char like[] = "I like coffee"; // создаем строку Serial.begin(9600); // (1) выводим строку Serial.println(like); // (2) удаляем часть строки like[13] = 0; Serial.println(like); // (3) подставляем слово в строку like[13] = ' '; // заменяем нулевое значение пробелом like[18] = 't'; // вставляем новое слово like[19] = 'e'; like[20] = 'a'; like[21] = 0; // завершаем строку Serial.println(like); } void loop() { } |
Создание и печать строки
В этом скетче создается новая строка, которая затем выводится в окне Монитор порта (1).
Укорочение строки
Строка укорачивается, заменяя 14-й символ в строке нулевым завершающим нулем (2). Это элемент номер 13 в массиве строк, отсчитываемый от 0 (нуля).
Когда строка готова, печатаются все символы до нового нуля, заканчивающегося нулем. Остальные символы не исчезают — они все еще существуют в памяти, и массив строк остается того же размера. Единственное отличие состоит в том, что любая функция, которая работает со строками, будет видеть только строку до первого нулевого значения.
Изменение слова в строке
Наконец, в скетче слово «cake» заменяется словом «tea» (3). Сначала он должен заменить нулевой ограничитель в like [13] пробелом, чтобы строка была восстановлена в том виде, в котором она была изначально создана.
Новые стмволы заменяют «cak» работы «cake» словом «tea». Это делается путем перезаписи отдельных символов. Буква «e» слова «cake» заменяется новым завершающим символом NULL. В результате строка фактически заканчивается двумя нулевыми символами — исходным в конце строки и новым, заменяющим букву «e» в «cake». Это уже не имеет значения, когда выводится новая строка, потому что функция, которая выводит строку, прекращает печать строковых символов, когда встречает первый нулевой ограничитель.
Функции для управления массивами строк
Предыдущий скетч управлял строкой обращаясь к отдельным символам в строке. Чтобы упростить управление строковыми массивами, вы можете написать для этого свои собственные функции или использовать некоторые строковые функции из библиотеки языка C.
В следующем скетче используются некоторые строковые функции C.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
void setup() { char str[] = "This is my string"; // создаем строку char out_str[40]; // вывод из строковых функций, помещенных сюда int num; // целое число общего назначения Serial.begin(9600); // (1) выводим строку Serial.println(str); // (2) получить длину строки (без нулевого значения) num = strlen(str); Serial.print("String length is: "); Serial.println(num); // (3) получить длину массива (включая нулевое значение) num = sizeof(str); // sizeof () не является строковой функцией C Serial.print("Size of the array: "); Serial.println(num); // (4) копируем строку strcpy(out_str, str); Serial.println(out_str); // (5) добавить строку в конец строки (добавить) strcat(out_str, " sketch."); Serial.println(out_str); num = strlen(out_str); Serial.print("String length is: "); Serial.println(num); num = sizeof(out_str); Serial.print("Size of the array out_str[]: "); Serial.println(num); } void loop() { } |
Скетч работает следующим образом:
(1) Распечатайте строку
Вновь созданная строка печатается в окне Монитор порта, как это было сделано на предыдущих скетчах.
(2) Получите длину строки
Функция strlen () используется для получения длины строки. Длина строки предназначена только для печатаемых символов и не включает нулевой ограничитель.
Строка содержит 17 символов, поэтому мы видим 17, напечатанных в окне Монитор порта.
(3) Получить длину массива
Оператор sizeof () используется для получения длины массива, содержащего строку. Длина включает нулевой огоаничитель, поэтому длина на единицу больше, чем длина строки.
sizeof () выглядит как функция, но технически является оператором. Он не является частью библиотеки строк C, но использовался в скетче, чтобы показать разницу между размером массива и размером строки (или длиной строки).
(4) Копировать строку
Функция strcpy () используется для копирования str[] строку в out_num [] массива. Функция strcpy () копирует вторую переданную ей строку в первую строку. Копия строки теперь существует в массиве out_num [], но занимает только 18 элементов массива, поэтому у нас все еще есть 22 свободных элемента char в массиве. Эти свободные элементы находятся в памяти после строки.
Строка была скопирована в массив, чтобы у нас было дополнительное пространство в массиве для использования в следующей части скетча, которая добавляет строку в конец строки.
(5) Добавить строку в строку (объединить)
Скетс соединяет одну строку с другой, что называется конкатенацией. Это делается с помощью функции strcat (). Функция strcat () помещает вторую переданную ей строку в конец первой переданной ей строки.
После объединения, длина строки печатается, чтобы показать новую длину строки. Затем печатается длина массива, чтобы показать, что у нас есть строка длиной 25 символов в массиве длиной 40 элементов.
Помните, что строка длиной 25 символов фактически занимает 26 символов массива из-за нулевого завершающего значения.
Границы массива
При работе со строками и массивами очень важно работать в рамках строки или массива. В примере скетча был создан массив длиной 40 символов, чтобы выделить память, которую можно было бы использовать для управления строками.
Если массив был сделан слишком маленьким, и мы попытались скопировать в него строку, которая больше, чем массив, строка будет скопирована через конец массива. Память за пределами массива может содержать другие важные данные, используемые в скетче, которые затем будут перезаписаны нашей строкой. Если память за концом строки переполнена, это может привести к сбою скетча или вызвать непредвиденное поведение.
Строковый объект Arduino
Второй тип строки, используемый в программировании Arduino, — это объект String.
Что такое объект?
Объект — это конструкция, которая содержит как данные, так и функции. Объект String можно создать так же, как переменную, и присвоить ему значение или строку. Объект String содержит функции (которые в объектно-ориентированном программировании (ООП) называются «методами»), которые работают со строковыми данными, содержащимися в объекте String.
Следующий скетч и пояснит, что такое объект и как используется объект String:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
void setup() { String my_str = "This is my string."; Serial.begin(9600); // (1) выводим строку Serial.println(my_str); // (2) переводим строку в верхний регистр my_str.toUpperCase(); Serial.println(my_str); // (3) перезаписываем строку my_str = "My new string."; Serial.println(my_str); // (4) заменить слово в строке my_str.replace("string", "Arduino sketch"); Serial.println(my_str); // (5) получаем длину строки Serial.print("String length is: "); Serial.println(my_str.length()); } void loop() { } |
Создается строковый объект, которому в верхней части скетча присваивается значение (или строка).
1 |
String my_str = "This is my string."; |
Это создает объект String с именем my_str и присваивает ему значение «This is my string.».
Это можно сравнить с созданием переменной и присвоением ей значения, например целого числа:
1 |
int my_var = 102; |
(1) Печать строки
Строку можно напечатать в окне Монитор порта так же, как строку символьного массива.
(2) Преобразование строки в верхний регистр
Созданный строковый объект my_str имеет ряд функций или методов, которые могут работать с ним. Эти методы вызываются с использованием имени объекта, за которым следует оператор точки (.), а затем имя используемой функции.
1 |
my_str.toUpperCase (); |
Функция toUpperCase () работает со строкой, содержащейся в объекте my_str, который имеет тип String, и преобразует строковые данные (или текст), содержащиеся в объекте, в символы верхнего регистра.
Список функций, которые содержит класс String, можно найти в справочнике Arduino String.
Технически String называется классом и используется для создания объектов String.
(3) Перезаписать строку
Оператор присваивания используется для присвоения новой строки объекту my_str, который заменяет старую строку.
1 |
my_str = "My new string."; |
Оператор присваивания не может использоваться для строк символьного массива, но работает только с объектами String.
(4) Замена слова в строке
Функция replace () используется для замены первой переданной ей строки второй переданной ей строкой. replace () — еще одна функция, которая встроена в класс String и поэтому доступна для использования в объекте String my_str.
(5) Получение длины строки
Получить длину строки легко, используя length (). В примере скетча результат, возвращаемый функцией length (), передается непосредственно в Serial.println () без использования промежуточной переменной.
Когда использовать строковый объект или массив строковых символов
Объект String намного проще в использовании, чем массив строковых символов. Объект имеет встроенные функции, которые могут выполнять ряд операций со строками, которые полностью задокументированы в справочном разделе на веб-сайте Arduino.
Основным недостатком использования объекта String является то, что он использует много памяти и может быстро использовать оперативную память Arduino, что может привести к зависанию, сбою или неожиданному поведению Arduino. Это особенно верно для небольших плат, таких как Arduino Uno.
Если скетч на Arduino небольшой и ограничивает использование объектов, то проблем возникнуть не должно.
Строки символьных массивов сложнее использовать, и вам может потребоваться написать свои собственные функции для работы с этими типами строк. Преимущество состоит в том, что у вас есть контроль над размером создаваемых массивов строк, поэтому вы можете сохранять массивы небольшими для экономии памяти.
Вам нужно убедиться, что вы не пишете через конец границ массива строковыми массивами. У объекта String нет этой проблемы, и он позаботится о границах строки за вас при условии, что у него достаточно памяти. Объект String может попытаться выполнить запись в несуществующую память, когда ему не хватает памяти, но никогда не будет записывать поверх конца строки, с которой он работает.
Вывод
В этой статье посвященной программированию Arduino было рассмотрено, что такое строки, как они выглядят в памяти, и некоторые операции, которые можно выполнять со строками.
Дальнейшее практическое использование строк будет рассмотрено в следующей статье, когда мы рассмотрим, как получить ввод пользователя из окна Монитор порта и сохранить ввод в строке.
С Уважением, МониторБанк