Добавить char с интервалами в строку
Я пытаюсь создать функцию, которая будет принимать строку в качестве входных данных и через каждые 20 символов будет вставлять "\n" чтобы строка не уходила за пределы моего экрана (я использую oled с библиотекой SSD1306Ascii).
Пока это мой код, но когда я запускаю его, на экране ничего не появляется (у меня есть другая часть кода, которая передает строку в функцию):
String message = "";
String newMessage = "";
void printMessage(String message) {
oled.clear();
if(message.length() > 20) {
current = 20;
while(current < message.length()) {
newMessage = message.substring(current-20, current) + "\n";
newMessage = newMessage + message.substring(current+1);
current+20;
}
oled.println(newMessage);
}
else {
oled.println(message);
}
}
@, 👍0
Обсуждение2 ответа
Лучший ответ:
Я думаю, что ваша реализация в корне ошибочна. В цикле while, когда вы назначаете newMessage
элементу message.substring
, вы отбрасываете всю работу, проделанную в предыдущих итерациях.
Также я бы рекомендовал разделять разделение и печать. Здесь также очень удобен operator +=
. Этот код (непроверенный) должен правильно реализовать вашу первоначальную идею
String splitMessage( const String & message, const unsigned limit) {
String newMessage = "";
unsigned i = 0;
while ( i+limit < message.length() ) {
newMessage += message.substring(i, i+limit);
newMessage += '\n';
i += limit;
}
newMessage += message.substring(i);
return newMessage;
}
Тогда вы можете сделать следующее:
whatever.println(splitMessage(myMessage, 20));
Обратите внимание, что я сохранил использование String
из вашей исходной реализации, хотя, находясь во встроенной среде, вероятно, лучше избегать его в пользу C-строк, выделенных в стеке.
Я нашел много полезной информации в различных ответах на этот вопрос: Является ли использование malloc() и free() действительно плохой идеей в Arduino?
Объект String создает блок памяти в куче с помощью malloc()
, динамически создает объект String newMessage
и возвращает объект String из функции, что не является хорошей практикой, поскольку это может привести к утечке памяти в долгосрочной перспективе, потому что память кучи для newMessage
никогда не освободится. Для каждого вызова splitMessage()
в куче создается новый блок памяти...., @hcheung
@hcheung Я понял тебя. Я программист на С++, все еще знакомлюсь с недостатками «языка» Arduino. Было бы лучше вернуть результат через *неконстантный* ссылочный аргумент? Как void splitMessage (String & out, const String & in, const unsigned limit)
?, @DarioP
Как программист на С++, вы должны хорошо знать ловушку malloc()
и использования кучи. Строковый объект за сценой использует malloc()
для создания переменной, когда вы делаете что-то вроде String newMessage = "";
, и каждая итерация конкатенации также вызывает фрагментацию кучи. Общая идея состоит в том, чтобы не использовать String в Arduino (только с 2 КБ ОЗУ), если вы действительно хотите его использовать, в этом конкретном случае я бы объявил его глобальным, чтобы вы могли его потом освободить, но опять же, если вы делаете это таким образом, это не сильно отличается от простого использования массива c вместо объекта String., @hcheung
@hcheung как программист на C ++, я всегда применяю RAII, чтобы выделенная память автоматически освобождалась, когда переменная выходит за пределы области видимости, и меня больше не беспокоит куча., @DarioP
Одна проблема как с неудачной реализацией, так и с предыдущим ответом
заключается в том, что они выполняют множество динамических распределений и копий. Каждый раз, когда ты
используйте операторы String +
или +=
, которые вы выделяете в куче памяти
для новой строки, скопировав исходные данные символов в
вновь выделенное пространство и, в конечном итоге, уничтожение исходных строк
когда они вам больше не нужны.
Самый простой способ избежать всех этих копий и распределений — не
создайте строку, которую вы хотите. Вместо этого просто write()
куски один за другим
другой на дисплее. Вот нулевое копирование, нулевое динамическое распределение
решение:
void printMessage(const char *message) {
size_t length = strlen(message);
while (length > 20) {
oled.write(message, 20);
oled.write('\n');
message += 20; // указываем на остальную часть сообщения
length -= 20; // оставшаяся длина
}
oled.write(message);
}
Обратите внимание, что здесь используется метод Print::write(const char *, size_t)
.
чтобы напечатать фрагмент сообщения, даже не создавая его в виде строки в
память.
На этих устройствах с ограниченным объемом памяти всегда предпочтительнее избегать
выделение кучи и, следовательно, объекты String
. Впрочем, если для чего
причина, по которой вам действительно нужно напечатать объект String
, вы можете использовать
следующая перегрузка для печати внутреннего буфера без каких-либо действий
дополнительная копия:
void printMessage(const String &message) {
printMessage(message.c_str());
}
- Как сравнить строку
- Использование строки вместо строки C, еще одна попытка затронуть загруженную проблему
- Как реализовать обратное перечисление?
- Смешанная структура с int и string
- Не удается скомпилировать макрос F() с помощью R "string"
- Как отправить данные ads1115 через spi на master arduino
- Как разделить входящую строку?
- Как вывести несколько переменных в строке?
Одна проблема, которая поражает меня, заключается в том, что если длина переданного сообщения составляет 20 или меньше,
newMessage
останется пустым., @DarioP