Динамический массив из String
- Войдите на сайт для отправки комментариев
Вс, 21/10/2018 - 21:10
Доброго времени суток и плодотворгого творчества!
Подскажите как создавать динамически массив элементов из типа String. Ниже я привел упрощенный код, где попытался показать суть проблему нежели реализацию самой задачи.
Значит с помощью malloc я пытаюсь создать массив sname из n элементов, потом получая значения в переменной name_buf записать в созданный массив sname. После всего этого получить результат на мониторе. Укажите мне на ошибки и как это исправить
...
String *sname;
byte n;
array_name_key(sname,n);
...
void array_name_key(String *sname, byte n)
{
// получаю заранее неизвестное количество элементов массива n
n=(какое-то тут количество);
sname = (String*) malloc(n * sizeof(String[28]));
String name_buf; // Для составления строки
byte size_s; // Для длины каждой строки
size_s=(длина от 2 до 28);
for(byte z=0;z<n;z++)
{
for(byte i=0;i<28;i++)
{
if(size_s>i)name_buf+=char((символ)[i]);
}
sname[z]=name_buf;
}
//Проверка работы
for(int i=0; i<n; i++)
{
Serial.print(sname[i]);
Serial.println(" ");
}
}
Если требуется все же углубиться в нормальный код, то он ниже
void setup()
{
...
String *sname;
byte *key[8];
byte n;
byte *addr;
array_name_key(sname,key,n,addr);
...
}
void array_name_key(String *sname, byte **key, byte n, byte *addr)
{
n=0;
byte *k;
bool a=true;
for(int m=0;m<511;)
{
a=EEPROM.read(m);
if(a==true){m=m+38;}
else
{
n++;
m=m+38;
}
}
//Выше отработалось нормально
/* for(byte x = 0; x < 14; x++)
sname[x] = (String*) malloc(n * sizeof(String));*/
sname = (String*) malloc(n * sizeof(String[28]));
String name_buf;
for(byte x = 0; x < 8; x++)
key[x] = (byte*) malloc(n * sizeof(byte));
addr = (byte*) malloc(n * sizeof(byte));
byte z=0;
byte size_s=0;
for(int m=0;m<511;)
{
name_buf="";
a=EEPROM.read(m);
if(a==true){m=m+38;}
else
{
m++;
size_s=EEPROM.read(m);
m=m+2;
addr[z]=m;
for(byte i=0;i<28;i++)
{
if(size_s>i)name_buf+=char(EEPROM.read(i+m));
}
sname[z]=name_buf;
Serial.println(sname[z]);
m=m+27;
m++;
for (byte x = 0; x < 8; x++)
{
EEPROM.get(m,key[x][z]);
m=m+1;
}
z++;
}
}
//Serial.println(n);
//Проверка работы
for(int i=0; i<n; i++)
{
Serial.print(sname[i]);
Serial.println(" ");
for(int j=0; j<8; j++){Serial.print(key[j][i], HEX);Serial.print(":");}
Serial.println("");
}
}
Вы бы еще русскими словами написали - просто тренируетесь или какую-то полезную задачу пытаетесь решить? В этих ваших a, m, x, z сам черт ногу сломит. Зачем вот вам String, если фактически делаете char[29]?
String* s = new String(); *s = F("bla bla bla"); delete s;Я тренируюсь на полезной задаче.
К данными переменными у меня нет вопросов и проблема не в них.
Со String(ом) просто удобнее, но cделать я патаюсь String[i] (размер каждого стринга по 28), либо если char, то char[28][i]
*s = F("bla bla bla"); delete s;Не понимаю как это можно применить в данной задаче... Понятно что String* s = new String(); создает элемент, но я не понимаю как тогда к нему обращаться, если мне нужно будет более чем 1 элемент. Если есть пример какой-нибудь, хотя бы из любой задачи, скиньте кусок кода, плиз
*s = F("bla bla bla"); delete s;Не понимаю как это можно применить в данной задаче... Понятно что String* s = new String(); создает элемент, но я не понимаю как тогда к нему обращаться, если мне нужно будет более чем 1 элемент. Если есть пример какой-нибудь, хотя бы из любой задачи, скиньте кусок кода, плиз
В примере выше - массив из 20 элементов, созданных динамически. Если надо динамически менять размерность массива, то:
Ну и не забывать чистить всё правильно.
К данными переменными у меня нет вопросов и проблема не в них.
Так код вы нам предлагаете читать. Прочитать, разобраться в вашей идее, потом еще показать, где вы допустили ошибку. Не пытались никогда с закрытыми глазами незнакомый фотоаппарат разбирать и собирать? Ощущения примерно такие же - хер его знает, должен этот винтик тут стоять или его надо с соседним поменять.
a - булевый тип. При чении из памяти EEPROM, если получаю true, то блок памяти занят, false блок памяти свободно. Это условные обозначения, чтобы считать тот блок помяти, который заполнен полезными данными.
m - адрес ячейки памяти EEPROM
x - переменная для цикла чтобы перебрать массив
z - счетчик, показывающий сколько раз мы прошли цикл
Из всех переменных что спрашивались, важен только счетчик z.
Код что я выложил 2й, это просто более полный, а сама проблема отображена в 1м коде
... String *sname[28]; byte n; array_name_key(sname,n); ... void array_name_key(String *sname, byte n) { // получаю заранее неизвестное количество элементов массива n n=(какое-то тут количество); String name_buf; // Для составления строки byte size_s; // Для длины каждой строки size_s=(длина от 2 до 28); for(byte z=0;z<n;z++) { for(byte i=0;i<28;i++) { if(size_s>i)name_buf+=char((символ)[i]); else name_buf+='\0'; } for (byte x = 0; x < 28; x++) { sname[x] = new String(); sname[x][z]=name_buf[x]; } //Проверка работы for (byte x = 0; x < 28; x++) { Serial.print(sname[x][z]); } Serial.println(""); } }Что я не так сделал?
Как применить delete тоже не понимаю
Что я не так сделал?
Как применить delete тоже не понимаю
1. Всё не так сделали;
2. Без обид, но - почитайте основы С++ - там как раз написано и про new/delete. Пересказ учебника - такое себе занятие.
Вам что надо? Прочитать из EEPROM сохранённые там строки в массив строк? Это делается сильно проще, чем у вас написано. Однако - всегда есть нюансы, например - может быть заранее неизвестно кол-во сохранённых строк. В общем случае это делается алгоритмически примерно так:
String** array = NULL; int arraySize = 0; int eepromAddress = ...; while(true) { byte b = EEPROM.read(eepromAddress++); if(b == 1) //запись существует { String** newArray = new String*[++arraySize]; for(int i=0;i<arraySize-1;i++) { newArray[i] = array[i]; } newArray[arraySize-1] = new String(); delete[] array; array = newArray; while(true) { char ch = (char) EEPROM.read(eepromAddress++); if(!ch) // хранящаяся строка заканчивается нулевым символом break; *(newArray[arraySize-1]) += ch; } } else break; } // чистим за собой for(int i=0;i<arraySize;i++) delete array[i]; delete[] array;Код - навскидку писан, без претензий.
Сделал по той схеме что скинули, но что-то не понятно. Мне нужно вытащить за приделы функции полученный массив со всеми элементами. Может опять что не так?
void array_name_key() { String** array=NULL; int arraySize=28; //Длина строки 28 символов byte sizeStr=0; n=0; //Количество полученных записей //Пробегаемся по всей памяти, за исключением ех участков, которые //не умещают в себе 38 байт for(int eepromAddress=0;eepromAddress+38<EEPROM.length();) { //Считываем первый байт блока данных из памятиб //в котором хранится метка о существовании записи //(true-свободно/false-занято). Вывести надо занятые области bool b=EEPROM.read(eepromAddress); if(b==false) { //Второй байт блока данных, это размер считываемой сроки eepromAddress++; //Длина строки sizeStr=EEPROM.read(eepromAddress); eepromAddress += 2; //С 4 байта блока данных начинается строка, //которую необходимо извлечь String** newArray=new String*[++arraySize]; for(int i=0; i<arraySize-1;i++) newArray[i]=array[i]; newArray[arraySize-1]=new String(); delete[] array; array=newArray; //Максимальный объем строки из русских букв - 28 байт int addr_sizeStr=eepromAddress+28; while(eepromAddress<addr_sizeStr) { char ch=(char)EEPROM.read(eepromAddress++); if(!ch) //Если строка заканчивается нулем { //В блоке данных у нас строка фиксированного размера, т.е. 28 байт, //поэтому сразу переходим в конец адреса строки eepromAddress=addr_sizeStr; break; } *(newArray[arraySize-1]) += ch; } //Последние данные блока, это ключи //Код записи ключа в массив я пока отпущу eepromAddress+=8; } else eepromAddress+=38; } //Чистим память for(int i=0;i<arraySize;i++) delete array[i]; delete array; }Я пока удалил входные параметры функции для тього, чтобы разобраться в логике и в работе того алгоритмя, что скинули выше.
Не понятно почему в переменной array NULL+ch? NULL+ch != ch, уже проверял. Как вообще работать с delete мне понятно, мне не понятно как потом после удаления работать с полученными значениями. Мне та надо в функции создать массив и заполнить этот массив значениями, а потом за пределами функции с ними работать.
Пока что должным образом у меня не работает....
Мне та надо в функции создать массив и заполнить этот массив значениями, а потом за пределами функции с ними работать.
Почитайте, что такое "область видимости" в языке Си. Любая переменная или структура, например массив, созданная внутри функции - только внутри этой функции и видна. Более того, если переменная не обьявлена static. то при каждом выходе из функции она уничтожается, а при следующем входе в функцию создается вновь.
Чтобы работать с массивом снаружи - его нужно и создавать "снаружи", например обьявить глобальным.
Как вообще работать с delete мне понятно
Нет, непонятно. У вас утечка памяти в строке 55. Читайте основы языка, как минимум. Иначе это - разговор немого с глухим.
Чтобы работать с массивом снаружи - его нужно и создавать "снаружи", например обьявить глобальным.
С областью видимости все понятно, но вот как быть тогда с динамическим массивом?
Извращаться надо. Ардуина - это вам не Big PC, тут подобные вещи только через .... аккуратное программирование. Будете со своим динамическим массивом в push/pop играть - всю память мигом растеряете. Сборщика памяти тут нет, устранять дырки в куче никто не станет.
С областью видимости все понятно, но вот как быть тогда с динамическим массивом?
Правильно создавать/освобождать. Примеры - вам не помогут: вы начинаете бездумно оттуда копировать, в надежде, что оно само по себе заработает. С++ - это даже не пистолет, это - берданка, и выстрелить из такой берданки себе в ногу - как два пальца. Чем вы сейчас героически и занимаетесь вместо того, чтобы взять учебник по С++ - и почитать про динамическое выделение и освобождение памяти.
Сколько бы вам примеров ни давали - без понимания основ всё сведётся к тупой копипасте. С заведомо известным плачевным результатом на выходе.
Извращаться надо. Ардуина - это вам не Big PC, тут подобные вещи только через .... аккуратное программирование. Будете со своим динамическим массивом в push/pop играть - всю память мигом растеряете. Сборщика памяти тут нет, устранять дырки в куче никто не станет.
Я так понимаю, что полноценно динамических массивов тут быть вообще не может. Бездумных, в смысле. Потому как некое максимальное значение мы должны заранее предусмотреть. Ну, по крайней мере, я это так для себя понял, когда разбирался. Ибо тоже избалован Big PC. :(
Я так понимаю, что полноценно динамических массивов тут быть вообще не может. Бездумных, в смысле. Потому как некое максимальное значение мы должны заранее предусмотреть. Ну, по крайней мере, я это так для себя понял, когда разбирался. Ибо тоже избалован Big PC. :(
Чой-то? Всё есть в соответствии со стандартом С++. Можно выделять память, сколько заблагорассудится, пока менеджер памяти - может выделить запрошенный кусок. Когда не сможет - вернёт NULL, эту ситуацию, ессно, надо отрабатывать в программе.
Конечно, оперативки не вагон, но жить можно. Постоянно юзаю динамические массивы (да тот же String - внутри держит динамический массив) - и не вижу в этом никаких недостатков. Кроме, конечно, ограниченного размера оперативки.
Чой-то? Всё есть в соответствии со стандартом С++. Можно выделять память, сколько заблагорассудится, пока менеджер памяти - может выделить запрошенный кусок. Когда не сможет - вернёт NULL, эту ситуацию, ессно, надо отрабатывать в программе.
Я о том и говорю, что бездумно не получится. Надо все контролировать. Некоторые вещи, на которые закрывают глаза большие машины и мощные компиляторы, тут неприемлимы. Как в старые, добрые времена. :)
А что там будет, если типа такого устраивать:
Дырки же в куче понаделаются?
А что там будет, если типа такого устраивать:
Дырки же в куче понаделаются?
Могут и наделаться, конечно - всё зависит "от". Бейсбольной битой если вломить - сломается вообще всё :)
Мда... жаль толкогого ответа, кроме критики, так и не получил... Надеюсь на последний мой вопрос получу хотя бы толковый ответ.
Вопрос вот в чем, то что я получил вызывая функцию read_upd_struct мне нужно использовать все время работы устройства. При вызове данную функцию повторно, хочу как бы обновить массив данных. Для этого я сначала удаляю весь созданный массив динамически, а потом его снова создаю. Вроде утечек памяти я пока не наблюдаю. Вот мне бы хотелось спросить у знающих людей позволительно ли использования такого способа или же подход неграммотный, по хорошему надо как-то по другому?
struct Memory { ... }; Memory *arr; int n_arr=0 void setup() { ... read_upd_struct(arr,n_arr); } void read_upd_struct(Memory *&arr, int &n_arr) { n_arr=0; ... free(arr); arr=(Memory*)malloc(n_arr*sizeof(Memory)); ... };Мда... жаль толкогого ответа, кроме критики, так и не получил...
Если вы считаете совет "читать учебник" критикой - тогда вообще никаких ответов не будет.