Arduino - Функция -> возвращает Cstr вместо строки
У меня есть следующая функция для моего Arduino:
String readLine() {
String received = "";
char ch;
while (myFile.available()) {
ch = myFile.read();
if (ch == '\n' or ch == '\r') {
if (ch == '\r')
{
//get rid of the \n
myFile.read();
}
return String(received);
} else {
received += ch;
}
}
myFile.close();
hasFile = false;
return received;
}
Эта функция используется для возврата строки из текстового файла на SD-карте. Поскольку мне действительно нужно кое-что сделать с возвращаемой строкой, я хотел бы использовать ее как cstr вместо строки для повышения производительности. Но я не могу преобразовать эту функцию в функцию, которая возвращает Cstr. Я попробовал это, но это не работает:
char* readLine() {
char* received = "";
char ch;
while (myFile.available()) {
ch = myFile.read();
if (ch == '\n' or ch == '\r') {
if (ch == '\r')
{
//get rid of the \n
myFile.read();
}
return received;
} else {
received += ch;
}
}
return received;
}
В настоящее время я конвертирую его после того, как функция вернет его, с помощью c_str()
. Это работает, но мне это не нравится, и я хотел бы вернуть Cstr в первую очередь.
Как это можно сделать?
Спасибо!
@sharkyenergy, 👍1
2 ответа
Лучший ответ:
Вы не можете работать со строками c, как со строками
. Вам необходимо использовать стандартные функции c-строки (такие как sprintf()
, strcpy()
и братья и сестры) или напрямую обращаться к массиву символов.
Это приводит к следующим проблемам с вашим кодом:
Смотрите эту строку:
char* received = "";
Здесь вы создаете указатель на постоянную пустую строку. Но это НЕ создаст буфер, в который вы можете поместить данные. Если вы хотите определить буфер для размещения данных, вам необходимо определить массив:
char received[30] = "";
где
30
-размер массива, и, следовательно, в буфере есть место для 29 символов (30 минус один символ, необходимый для завершающего нулевого символа). Теперь вы можете использовать переменную счетчика для сохранения текущей позиции в буфере и установки элементов массива в полученный символ:int position = 0; ... received[position] = ch; position++;
Затем, когда вы дойдете до конца буфера или получите конец строки, вы завершите данные в буфере нулевым символом:
if (ch == '\n' || ch == '\r' || position == 29) { if (ch == '\r') { //get rid of the \n myFile.read(); } received[position] = '\0';
Теперь у вас есть вторая проблема: при определении переменной внутри функции она станет недействительной при выходе из функции. Вы пытаетесь вернуть указатель на
символ
, который будет указывать на недопустимую ячейку памяти. Таким образом, вы не можете просто вернуть массив, созданный внутри функции (вне динамического выделения). Здесь обычно внешний буфер предоставляется функции ссылкой в качестве указателя. Затем функция будет записывать данные в этот буфер, и ей не нужно будет его возвращать.//определение массива вне функции, например, в глобальной области #define BUFFER_SIZE 30 char received[BUFFER_SIZE] = ""; ... void readLine(char *buffer, int size) { ... // Здесь вы можете использовать буфер в качестве простого массива символов buffer[position] = ch; }
Здесь я также указываю размер массива в качестве параметра, чтобы функция могла не превышать его (потому что это приведет к плохим и трудным для устранения неполадкам). Затем, когда функция запущена, считанные данные теперь находятся в
полученном
символьном массиве. Таким образом, вам не нужно использовать несколько буферов, а также не нужно копировать данные между буферами.
Одним из способов является передача внешнего буфера в readLine() для заполнения:
size_t readLine(char * buff, size_t maxChars) {
size_t pos = 0; // текущая позиция в буфере
while (file.myFileAvalable()) {
buff[pos] = file.read();
if (buff[pos] == '\n' || buff[pos] == '\r') {
buff[pos] = '\0'; // завершающая строка
break; // завершить цикл
}
if (++pos == maxChars-1) { // не забывайте о нулевом терминальном символе
buff[pos] = '\0';
break; // завершить цикл
}
}
return pos; // возвращает количество прочитанных символов (0 ничего не было прочитано)
}
/// ...
char ssid[25] = {0}; // создайте буфер для хранения не более 24 символов + \0
char pass[25] = {0}; // он также заполнит буферы нулями
readLine(ssid, sizeof(ssid)-1); // было бы лучше проверить, сколько символов было прочитано
readLine(pass, sizeof(pass)-1); // то же самое здесь
WiFi.begin(ssid, pass);
/// ... Но это выглядит намного хуже, чем строка, однако это гораздо эффективнее, так как использование += для строк довольно недружелюбно
Большое "НЕТ-НЕТ" делает что-то вроде:
char* readLine() {
char buff[50] = {0};
// ... fill ...
return buff; // НЕТ!!!! буфер не существует после возврата - у вас болтается указательdangling pointer
}
// ...
char * ssid = readLine(); // после этого болтается указатель...
char * pass = readLine(); // теперь местоположение ssid было наверняка перезаписано
Еще одно НЕТ-НЕТ:
char* readLine() {
static char buff[50] = {0}; // один буфер для всех вызовов, он не будет уничтожен после завершения... но
// ... заполнять...
return buff; // хорошо, буфер существует после возврата,...
}
// ...
char * ssid = readLine(); //
char * pass = readLine(); // но сюрприз сюрприз, ssid и точки передачи в один и тот же буфер и, следовательно, одни и те же данные...
- форматирование строк в Arduino для вывода
- Проблемы с преобразованием byte[] в String
- Чтение строки, разделенной запятыми
- Использование строки вместо строки C, еще одна попытка затронуть загруженную проблему
- Разделение Serial.readString на массив строк
- Преобразование JSON в строку для MQTT
- strcmp, похоже, не работает
- Как заменить объекты String массивами символов, продолжая использовать строковые методы