Добавление строк в массив

Vir
Offline
Зарегистрирован: 04.12.2012

День добрый. Есть массив строк:

char* strings[] = {}

Можно ли в него, динамически, добавлять строки? При попытке сделать так:

strings[0] = "test";

Ругается, что не может привести string к char*. Если же я воспользуюсь такой конструкцией:

char strings[2];

strings[1] = "test";

То всё ок.

San4eS
Offline
Зарегистрирован: 02.05.2011

Все просто:

String x[10];

void loop()
{
	x[0] = "abcd";
}

 

mixail844
Offline
Зарегистрирован: 30.04.2012

можно сделать как предложл San4es,но гораздо правильнее использовать динамические массивы 

во вторых он предлагает использовать класс String,что скажеться на памяти программы.

char* strings[] = {} // это обычное обьявление массива указателей типа char,если проще двумерный массив,при таком обьявлении он создаеться в статической области памяти

если же в ходе дейсвия нужно менять размер массива то такой способ вам не подойдет ,нужно изначьлно указывать компилятору что вы хотите массив в динамической области памяти  :

char* strings = (char*)malloc(sizeof(char)); // в данном случае в динамической памяти создался указатель на динамический одномерный массив типа char,что значит что в каждой ячейке данного массива может находиться одна буква/символ (вам же нужен двухмерный,так как каждая строчка сама по себе массив)  

для изменения резмера массива используеться   :

strings = (char*)realloc(strings ,sizeof(char) * 2 ) ); /* в данном случае мы укзаываем компилятору что указатель strings будет указывать на одномерный массив строк размером в две "ячейки" и результат релокации вернеться в тот же указатель strings */  

в случае с переменной типа char ,для присвоения можно пользоваться обычным '=' :

strings[1] = 'b';

для присвоения значений типа 'строк' используеться метод strcpy(); 

axill
Offline
Зарегистрирован: 05.09.2011

То что хочет автор это двухмерный массив, в одном измерении хранятся указатели на строки, во втором сами строки (массив символов). Т.е. Это массив указателей на массивы

организовать это проще статически. Статическое распределение контролируется на этапе компиляции, помогает избежать ошибок. К тому же динамическое выделение в итоге может потребовать больше места во флэш и немного больше в ram

Так ли уж нужна динамика? Почему бы не выделить статически нужное пространство? Многие задачи это позволяют

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Если автор расскажет больше, возможно и ответы будут более адекватные.
Часто бывает, что не факт, что автор понимает, как правильно реализовать задачу и ставит вопрос о своем, возможно, не совсем правильном решении задачи.

 

Vir
Offline
Зарегистрирован: 04.12.2012

День добрый.

Моя цель - разбить строку, по какому-нибудь разделителю (пусть это будет пробел), затем каждый кусок этой строки поместить в массив. А сам массив передать в другую функцию, где исходя из размера этого массива алгоритм может варьироваться.

Непосредственно я хочу получать с serial'а команду, передавать нужному обработчику, который будет выполнять те или иные действия.

В идеале, первым параметром в строке должно идти имя обработчика. Сам обработчик я хотел бы вызывать "магическим" методом. Т.е. использовать первый кусок строки, как имя функции. Можно ли так сделать? Т.е. если не привязываться к синтаксису какого-либо языка, попробую привести "асбтрактный" пример:

array = string.split(' ')

array[0](array);

Допустим на вход передана строка 'cam record move'. В результате разделения получаем массив:

0 => "cam",
1 => "record",
2 => "move"

В итоге мы вызываем функцию, куда параметром передаем массив:

cam({cam, record, move});

leshak
Offline
Зарегистрирован: 29.09.2011

mixail844 вообщем-то теорию изложил. только "на практике", без кровавого опыта (и даже с ним) от всей динамичности - лучше отказатся. Если есть хоть какая-то возможность.

Оно то и когда нормальные дебагер есть, ошибки с выделением/освобождением памяти - практически неизбежны и одни из самых трудно-уловимых, а уж тут-то, когда у нас только Serial.println можно будет головой рохнутся когда "память потечет".
Да еще нужно будет предусматривать "а что делать когда память закончится" (и надеятся что в этот же момент у нас стек/куча тоже не переполнятся).
Да еще "дефрагментация свободной памяти" и проч. прелести

Вообщем IMHO гораздо проще выделить массив с небольшим запасом. И просто завести какую-то переменную счетчик, в которую вы сами руками отмечаете "сколько ячеек в нем уже занято". Заняли ячейку - увеличили счетчик. Нужно освободить (последнюю) - уменьшили его на единицу.

Вы думаете почему, скажем старые мобилки в своих спецификаях имеют "телефонная книга на 200 номеров" (хотя памяти может быть и больше). Вот поэтому :)  Потому что "так проще в реализации и безопастней".

Лично я, на ардуине, использую динамическое выделение, только когда, в принципе на момент компиляции уже известно сколько памяти потребуется. Просто "известно это в другом месте" и "выделение происходит только один раз, при старте скетча" (вообщем практически не отличается от статического выделения).
Скажем пишу какой-нибудь класс "обработчик кнопок". И не хочу его заранее ограничивать сколько кнопок он умеет обрабатывать. Массив пинов - я передам ему в конструктор. Внутри мне требуется для обработки кнопок, еще несколько массивов "прошлое состояние кнопки, когда нажимали и т.п.". Вот эти массивы и я выделю динамически. Один раз. Но дефакто, когда я буду инициализировать класс "обработчик кнопок" я ему точно скажу "сколько нужно выделить", еще в момент компиляции я знаю "сколько же у меня кнопок", на ходу они появляться/исчезать - не будут.

leshak
Offline
Зарегистрирован: 29.09.2011

Я ошибся или вы хотите парсить json? Поищите - вообщем-то уже есть либы для этого.

string.split(' ') - неа  :)

гуглите фунцию strok()

leshak
Offline
Зарегистрирован: 29.09.2011

Vir пишет:

Т.е. использовать первый кусок строки, как имя функции. 

не получится. Похоже вы явно из javascript пришли к нам. В скомпилированной прошивке никаких именно фукнций нет. И, в отличие от java и C# никаких reflection тоже нет.
Так что запускать какую-то фукнцию, по текстовой строке, типа можно только примерно так:

if(strcmp(parsedName,"myFunc1")==0)myFunc(parsedArg1,parsedArg2,parsedArg3);

И если вы потом, захотите что-бы и какая-то myFunc2 запускалась, по команде, то "просто ее написать" - не получится. Опять нужно будет "в обработчке", для нее дописывать вызов

else if(strcmp(...,"myFunc2")==)myFunc2(...)

и д.т.

Можно это будет конечно, как-то свернуть с использованием структур-массивов, но все равно каждую функцию которую "можно вызывать", прийдется "ручками регистрировать".

P.S. А еще посмотрите на фунцию sscanf(), тоже при разборе может пригодится. Только нельзя тупо смотреть в справочник по C/C++ и пользвоать эти функции. Нужно перепроверять. В Arduino часть из них реализована в "урезанном варианте". Скажем sprint() по справочнику умеет и с целыми и с вещественными числами работать, а в ардуино-вариате только с целыми. Вещественные - выкинуты для экономии. 

mixail844
Offline
Зарегистрирован: 30.04.2012

Цитата:

Допустим на вход передана строка 'cam record move'. В результате разделения получаем массив:

0 => "cam",
1 => "record",
2 => "move"

В итоге мы вызываем функцию, куда параметром передаем массив:

cam({cam, record, move});

для этого нужно всего лишь такая конструкция  : 

допустим вы получили некий массив из Serial и разбили его при помощи strtok(); на масив   tempBuff[] = {"cam","record","move"};

далее вам просто нужно знать какая функция нужна для запуска  : 



if(!strcmp(tempBuff[0],"cam"){
    firstFunction(tempBuff[1],tempBuff[2]);
else if(!strcmp(tempBuff[0],"cam1"){
   secondFunction(tempBuff[1],tempBuff[2]);
...... и так далее 

поскольку функция сравнения строк ( strcmp(); ) может вернут 3 значения   : 0 - в случае если строки равны, 1 - если левая строка лексиграфически больше правой, и  -1 если наоборот. то в случае равенства строк,для "истины" в констукции if,необходимо использовать логическе НЕ

по той же причине ,возвращаемых значениях функсии strcmp() ,использовать оператор switch - case, вряд ли получиться.

axill
Offline
Зарегистрирован: 05.09.2011

Я бы так делал задачу. Во первых список функций у нас ограничен и известен на момент компиляции. Поэтому я бы сделал массив статических строк прямо во флэш (PROGMEM) и в этом массиве задал бы полный перечень поддерживаемых функций. 

Далее, при парсинге входящей строки я бы делал поиск строки по своему массиву во флэш. Найдя там команду получаю индекс комманды в моем массиве. Этот индекс дальше использую или в switch для вызова функции или делая выборку из другого массива во флэш где заданы адреса функций с тем же интекслм что и команды. 

Такое же преобразование параметров функции из текста в число(индекс) я бы сделал до вызова команды. Тогда от текста мы полностью избавляемся на момент парсинга и до вызова других функций

toc
Offline
Зарегистрирован: 09.02.2013

всю тему не читал, изв.

>> Найдя там команду получаю индекс комманды в моем массиве. Этот индекс дальше использую или в switch для вызова функции или делая выборку из другого массива во флэш где заданы адреса функций с тем же интекслм что и команды.

я делал примерно также:

1. с десяток функций (обработчиков сообщений) с одинаковым прототипом:

bool MSG_PING_REQ_handler()
{
...
  return true;
}

2. массив указателей на обработчики

bool (*handlers[]) () = { 0, MSG_PING_REQ_handler, MSG_ENH_PING_START_handler, MSG_ENH_PING_TEST_handler, MSG_ENH_PING_END_handler, MSG_ENH_PING_REQUEST_handler, MSG_GET_VCC_REQ_handler, MSG_GET_TEMP_REQ_handler, MSG_GET_FREE_RAM_REQ_handler};
 

3. из входящего сообщения получаю его тип (byte reqMsgType). Тип равен номеру обработчика в массиве.

4. вызываю обработчик, получаю результат

bool result = (*handlers[reqMsgType]) ();

5. плюс: отсутствуют лишние if-ы и case-s

прочитал тут: http://stackoverflow.com/questions/252748/how-can-i-use-an-array-of-func...