Некоторые переменные не сохраняют свои значения при выходе из цикла while?
Извините, если я задаю слишком много глупых вопросов, но я действительно в тупике. Я понимаю, что если я задам переменную внутри цикла, то эта переменная не будет в области видимости снаружи цикла.
Обычно я обнаруживаю, что переменные, объявленные вне цикла, будут доступны внутри цикла, могут быть изменены внутри цикла и сохранят свое значение при выходе из цикла, но в этом случае этого, похоже, не происходит.
На SD-карте есть книги. Я сохраняю название каждой книги в массиве из цикла while. При выходе из цикла while массив по-прежнему остается пустым.
Как мне решить эту проблему? Спасибо
int amtBooks = 5; //это устанавливается ранее, но я не буду показывать весь код
// создаем массив размером с количество книг
char* book[amtBooks] = { NULL };
// присваиваем имя каждой книги массиву
int bookNum = 0;
while (true) {
File entry = root.openNextFile();
if (! entry) {
break; // больше нет файлов
}
book[bookNum] = entry.name();
Serial.println(book[bookNum]); // <--------ЗДЕСЬ ПЕЧАТАЕТСЯ ПРАВИЛЬНО
bookNum ++;
}
root.close(); // закрыть поток
Serial.println(book[0]); <---ONCE OUT OF THE WHILE LOOP NOTHING DISPLAYS?
Serial.println(book[1]);
@Kara, 👍1
Обсуждение3 ответа
Полезно знать, где находятся переменные.
Локальные переменные располагаются в стеке. Они создаются при входе в функцию и исчезают при выходе из функции. Они могут даже находиться локально внутри if
, for
, while
или другого оператора, если они объявлены внутри этого оператора.
Глобальные переменные имеют фиксированное расположение в памяти. Их можно использовать из любой функции.
Когда указатель создан и он никуда не указывает, вы не можете записывать данные туда, куда указывает этот указатель.
Вы создаете массив указателей, но вам нужна память, которую вы можете использовать для хранения данных. Например: char booknames[5][20]
. Массив текста часто копируется с помощью strcpy().
Весь этот фрагмент кода находится внутри основного цикла do. Происходит что-то странное, потому что даже если я объявляю массив глобально в самом верху, установка значений массива из цикла while не сохраняется. Если я уберу цикл while, я смогу установить значения массива. Внутри цикла while значения массива присутствуют, но теряются после выхода из цикла while., @Kara
Вот что я пытался объяснить. Помогает, если вы знаете, где находятся переменные. Фактический текст в вашем коде нигде не хранится, так как вы используете указатели. Вам нужно создать ячейку памяти для хранения этих текстов. Не указатель на что-то или ничто, а вам нужна ячейка памяти для символов текста., @Jot
Вы сохраняете указатель на массив символов name
в переменной entry
File
. entry
выходит из области видимости (удаляется из стека), и ваш сохраненный указатель никуда не указывает.
Вам понадобится char book[amtBooks][13] = {{0}};
и strcpy(book[bookNum], entry.name());
переменные, объявленные вне цикла, будут доступны внутри цикл, изменяемый внутри цикла, и сохраняющий свое значение при выходе петля
Это правильно.
в данном случае этого, похоже, не происходит.
Это происходит. Причина, по которой кажется, что этого не происходит, заключается в том, что
book[bookNum]
— это указатель: адрес некоторых данных в памяти. Вы
можно проверить, что указатель сохраняет свое значение, выведя его на печать:
Serial.println((uintptr_t) book[bookNum]);
Однако, утверждение, которое вы использовали:
Serial.println(book[bookNum]);
имеет другое значение. Он не выводит значение переменной (т.е. указатель): он печатает символы, которые хранятся в указанный адрес, вплоть до первого NUL и исключая его.
Ваша проблема возникает из-за того, что когда вы заявляете
File entry = root.openNextFile();
У вас есть переменная, которая является локальной для цикла. Затем, при вызове метод
entry.name()
Вы получаете указатель на массив символов, принадлежащий записи
объект. Этот указатель действителен только до тех пор, пока объект находится в области видимости. Как
как только он выходит из области видимости (в конце каждой итерации цикла),
Объект entry
уничтожается, и вся принадлежащая ему память освобождается.
На этом этапе сохраненный вами указатель является «висячим» указателем: он указывает
в область памяти, которая уже была освобождена.
Правильным решением будет выделить себе память, необходимую для хранения массивы символов, например:
for (int bookNum = 0; bookNum < amtBooks; bookNum++) {
File entry = root.openNextFile();
if (!entry) break;
const char *name = entry.name();
book[bookNum] = (char *) malloc(strlen(name) + 1);
strcpy(book[bookNum], name);
Serial.println(book[bookNum]);
}
Если вы заранее знаете максимальную длину названия книги, вы можете следуйте совету Йота и Юрая и статически выделите максимум пространство, которое вам может понадобиться. Это было бы безопаснее с точки зрения управления памятью.
- Использование переменной для индексации массива
- Присвоение переменных массива переменным int
- Условное присвоение массива
- Как объявить массив переменного размера (глобально)
- Как получить тип данных переменной?
- Преобразование long в массив символов и обратно
- Возможно ли иметь массив массивов int?
- Замена нескольких выводов pinMode() и digitalWrite() на массив
примечание: в вашем коде непоследовательные отступы... первая строка и последние две строки должны иметь отступ в 2 пробела... они находятся на том же уровне, что и строка
while (true) {
... три строки блокаif
должны иметь отступ на 2 пробела меньше......... неправильный отступ вносит путаницу в отладку, @jsotolaэто не про Arduino. это про C, @Juraj