Динамический массив в структуру

AsNik
Offline
Зарегистрирован: 24.10.2020

Доброго всем! Подскажите как реализовать такое:

struct TMenu {
  char ItemName[];
  byte ItemCount;
  byte SelectItem;
  byte LastActiveItem, LastTopItem;
};

const TMenu Menu1 {
{
  "Item1",
  "Item2",
  "Item3",
  "Item4",
},
4, 0, 0, 0};

const TMenu Menu2 {
{
  "Item1",
  "Item2",
  "Item3",
  "Item4",
  "Item5",
  "Item6",
},
6, 0, 0, 0};

Мне нужны константные Menu1, Menu2, Menu3...

Но компилятор выдает:

exit status 1
too many initializers for 'char [0]'
 
Может как-то по другому можно создать константы Menu1, Menu2... без TMenu?
sadman41
Offline
Зарегистрирован: 19.10.2016

Какое-то сплошное противоречие вижу здесь.

По-русски опишите, что вы пытаетесь сотворить.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Это же очевидно. Он хочет сюда - char ItemName[], запихнуть вот это - "Item1",  "Item2",  "Item3",  "Item4"

Только вот при таком подходе я даже и не знаю с чего начать, коротко то не получится :)

AsNik
Offline
Зарегистрирован: 24.10.2020

brokly пишет:

хочет сюда - char ItemName[], запихнуть вот это - "Item1",  "Item2",  "Item3",  "Item4"

Верно. Я если правильно понял, так просто это сделать не получится.

Хотелось бы структуру заполнить на этапе компиляции. Ладно, буду искать другие варианты.

Можно конечно в TMenu указать максимально возможное кол-во Item'ов, но это как-то не очень...

AsNik
Offline
Зарегистрирован: 24.10.2020

brokly пишет:

Только вот при таком подходе я даже и не знаю с чего начать, коротко то не получится :)

Подход можно изменить, если я соображу как :)

sadman41
Offline
Зарегистрирован: 19.10.2016

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

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Значит в структуру запихивайте указатель на список.

AsNik
Offline
Зарегистрирован: 24.10.2020

Хм.... правильно я сделал:


const char *ItemName[] {
  "Item1",
  "Item2",
  "Item3",
  "Item4",
};

struct TMenu {
  char *Items;
  byte ItemCount;
  byte SelectItem;
  byte LastActiveItem, LastTopItem;
};

const TMenu Menu1 {
*ItemName,
4, 0, 0, 0};

?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, почему не получится?

Замените char ItemName[]; на  const char * ItemName[]; и поставьте его последним элементом структуры - всего делов.

struct TMenu {
  byte ItemCount;
  byte SelectItem;
  byte LastActiveItem, LastTopItem;
  const char *ItemName[];
};

const TMenu Menu1 {
  4, 0, 0, 0,
  {
    "Item1",
    "Item2",
    "Item3",
    "Item4",
  }
};

const TMenu Menu2 {
  6, 0, 0, 0,
  {
    "Item1",
    "Item2",
    "Item3",
    "Item4",
    "Item5",
    "Item6",
  }
};

Или Вы их менять в процессе работы собираетесь?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AsNik пишет:

Хм.... правильно я сделал:

Нет, конечно. Кратность указателей нарушена. Как делать правильно я Вам написал в прошлом посте.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Я так не могу... Про последнее место у меня даже мысля не шевельнулась :(

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

AsNik пишет:

Хм.... правильно я сделал:

Нет, конечно. 

Угу, хотя скомпилировать то скомпилировалось, но при обращении:

Serial.print(Menu1.ItemName[2]);

Выдал:

exit status 1
'const struct TMenu' has no member named 'ItemName'
 
AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

Ну, почему не получится?

Замените char ItemName[]; на  const char * ItemName[]; и поставьте его последним элементом структуры - всего делов.

struct TMenu {
  byte ItemCount;
  byte SelectItem;
  byte LastActiveItem, LastTopItem;
  const char *ItemName[];
};

const TMenu Menu1 {
  4, 0, 0, 0,
  {
    "Item1",
    "Item2",
    "Item3",
    "Item4",
  }
};

const TMenu Menu2 {
  6, 0, 0, 0,
  {
    "Item1",
    "Item2",
    "Item3",
    "Item4",
    "Item5",
    "Item6",
  }
};

Или Вы их менять в процессе работы собираетесь?

Ну ведь они же константы, их уже по определению менять нельзя. Ок. Спасибо, сейчас буду пробовать вашу идею.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

brokly пишет:

Про последнее место у меня даже мысля не шевельнулась :(

А поставьте себя на место компилятора. ХЗ ж сколько ему места надо, как остальное размещать? Получится, что у разных экземпляров структуры одно и тоже поле находится на разном расстоянии от начала! А так, если переменное поле последнее, то все поля во всех структурах начинаются с одних и тех же смещений - всё разместил, а этот - как получится.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AsNik пишет:

Ну ведь они же константы, их уже по определению менять нельзя. 

Точно? Это Вам так кажется, никакие они не константы :-)

AsNik
Offline
Зарегистрирован: 24.10.2020
struct TMenu {
  byte ItemCount;
  byte SelectItem;
  byte LastActiveItem, LastTopItem;
  const char *ItemName[];
};

const TMenu Menu1 {4, 0, 0, 0,
  {
    "Item1",
    "Item2",
    "Item3",
    "Item4",
  }
};

const TMenu Menu2 {6, 0, 0, 0,
  {
    "Item1",
    "Item2",
    "Item3",
    "Item4",
    "Item5",
    "Item6",
  }
};

Выдает:

exit status 1
too many initializers for 'const char* [0]'
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Код приводите полностью. Потому, что никто не знает что у Вас там ещё написано, а судя по посту #11 Вы совсем не понимаете что пишете.

И да, кстати, чем компилируете, название, версия.

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

Код приводите полностью


struct TMenu {
  byte ItemCount;
  byte SelectItem;
  byte LastActiveItem, LastTopItem;
  const char *ItemName[];
};

const TMenu Menu1 {4, 0, 0, 0,
  {
    "Item1",
    "Item2",
    "Item3",
    "Item4",
  }
};

const TMenu Menu2 {6, 0, 0, 0,
  {
    "Item1",
    "Item2",
    "Item3",
    "Item4",
    "Item5",
    "Item6",
  }
};

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}

Весь код. Просто хотел попробовать идею...(

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

И да, кстати, чем компилируете, название, версия.

Ардуино IDE 1.8.10

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

ЕвгенийП пишет:

А поставьте себя на место компилятора. ХЗ ж сколько ему места надо, как остальное размещать? Получится, что у разных экземпляров структуры одно и тоже поле находится на разном расстоянии от начала! А так, если переменное поле последнее, то все поля во всех структурах начинаются с одних и тех же смещений - всё разместил, а этот - как получится.

Это как раз очевидно. Поэтому других вариантов и не придумл.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AsNik пишет:

Весь код. Просто хотел попробовать идею...(

Странно, потому, что у меня всё отлично компилируется, любуйтесь

Вы точно ничего от нас не скрываете? :-)

AsNik
Offline
Зарегистрирован: 24.10.2020

Хм, ну и я вроде как не вру:

AsNik
Offline
Зарегистрирован: 24.10.2020

Как вставить картинку? (

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Более того, не только компилируется, но и работает.

Вот такой код

struct TMenu {
  byte ItemCount;
  byte SelectItem;
  byte LastActiveItem, LastTopItem;
  const char *ItemName[];
};

const TMenu Menu1 {4, 0, 0, 0,
  {
    "Item1",
    "Item2",
    "Item3",
    "Item4"
  }
};

const TMenu Menu2 {6, 0, 0, 0,
  {
    "Item1",
    "Item2",
    "Item3",
    "Item4",
    "Item5",
    "Item6"
  }
};

void setup(void) {
	Serial.begin(57600);
	Serial.println("Start!!!");
	Serial.println(Menu2.ItemName[0]);
	Serial.println(Menu2.ItemName[1]);
	Serial.println(Menu2.ItemName[2]);
	Serial.println(Menu2.ItemName[3]);
}

void loop(void) {}

выдаёт в монитор порта вот это

Start!!!
Item1
Item2
Item3
Item4

Как видите, всё правильно.

Правда у меня IDE 1.8.12. Попробуйте апгрейдироваться, чем чёрт не шутит.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Для ESPшек не компилируется.

struct TMenu {
  byte ItemCount;
  byte SelectItem;
  byte LastActiveItem;
  byte LastTopItem;
  const char **ItemName;
};

const char *forMenu1[]={
    "Item1",
    "Item2",
    "Item3",
    "Item4"};
    
const char *forMenu2[]={
    "Item1",
    "Item2",
    "Item3",
    "Item4",
    "Item5",
    "Item6"};

const TMenu Menu1 {4, 0, 0, 0, forMenu1};
const TMenu Menu2 {6, 0, 0, 0, forMenu2};

void setup() {
  // put your setup code here, to run once:
}

void loop() {
  // put your main code here, to run repeatedly:
}

IDE 1.8.9

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

Вы точно ничего от нас не скрываете? :-)

Нет, просто не могу (не умею) вставить картинку сюда :(

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

Более того, не только компилируется, но и работает.

Как видите, всё правильно.

Правда у меня IDE 1.8.12. Попробуйте апгрейдироваться, чем чёрт не шутит.

Ну фик его знает.... может попробовать обновить IDE. Вон выше тоже не компилится, но версия ИДЕ еще меньше чем у меня....

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

brokly пишет:

Для ESPшек не компилируется.

struct TMenu {
  byte ItemCount;
  byte SelectItem;
  byte LastActiveItem;
  byte LastTopItem;
  const char **ItemName;
};

const char *forMenu1[]={
    "Item1",
    "Item2",
    "Item3",
    "Item4"};
    
const char *forMenu2[]={
    "Item1",
    "Item2",
    "Item3",
    "Item4",
    "Item5",
    "Item6"};

const TMenu Menu1 {4, 0, 0, 0, forMenu1};
const TMenu Menu2 {6, 0, 0, 0, forMenu2};

void setup() {
  // put your setup code here, to run once:
}

void loop() {
  // put your main code here, to run repeatedly:
}

IDE 1.8.9

Не вижу проблемы. В IDE нормально всё. А чего говорит?

AsNik
Offline
Зарегистрирован: 24.10.2020

А вот вариант из #25 скомпилировался и работает.

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

Не вижу проблемы. В IDE нормально всё. А чего говорит?

Скорее всего было сказано про Ваш вариант кода

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AsNik, так я и говорю, попробуйте апгрейдироваться.

У меня же и компилируется и работает нормально, сами видите.

Только,, не советовал бы я Вам такие извращения использовать. Прикиньте, что там, например, sizeof будет выдавать.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

ЕвгенийП пишет:

AsNik, так я и говорю, попробуйте апгрейдироваться.

У меня же и компилируется и работает нормально, сами видите.

Только,, не советовал бы я Вам такие извращения использовать. Прикиньте, что там, например, sizeof будет выдавать.

:)))) Но работает же :)

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

Только,, не советовал бы я Вам такие извращения использовать. 

Вот. А я хотел бы чтоб без сюрпризов. Так как Вы уже поняли, что программист я не очень. Это мое хобби...

Поэтому много тонкостей не знаю.

А что с вариантом из 25? Те-же вроде грабли могут быть, верно же? Если нет ничего более менее стабильного варианта, буду наверное пока 25 пробовать.... Спасибо.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

sizeof , при всей простоте требует аккуратного обращения. Часто вы его используете ?  Есть правильные операторы для этого, честные - - strlen например.

Я вот, поему то не боюсь указатель на массив указателей :)

AsNik
Offline
Зарегистрирован: 24.10.2020

AsNik пишет:

А что с вариантом из 25? Те-же вроде грабли могут быть, верно же?

Хотя там подставляются константы через указатель на указатель.... И вроде должно на этапе компиляции все размеры быть известны...

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Вроде нормально все.

void setup() {
  Serial.begin(115200);
  Serial.println("Start!!!");
  Serial.println(Menu1.ItemName[0]);
  Serial.println(sizeof(forMenu1[0]));
  Serial.println(sizeof(Menu1.ItemName[0]));
  Serial.println(strlen(forMenu1[0]));
  Serial.println(strlen(Menu1.ItemName[0]));
}
Start!!!
Item1
4
4
5
5
 
AsNik
Offline
Зарегистрирован: 24.10.2020

Скажите еще вот что. Если переделать немного так:

const TMenu Menu1 {sizeof(forMenu1)/sizeof(forMenu1[0]), 0, 0, 0, forMenu1};
const TMenu Menu2 {sizeof(forMenu2)/sizeof(forMenu2[0]), 0, 0, 0, forMenu2};
 
на сколько это правильно или нет? С одной стороны теперь не нужно следить за ItemCount.
sadman41
Offline
Зарегистрирован: 19.10.2016

Это пока все строки в массиве одного размера.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Это не правильно ни разу.

А вот список это правильное решение, я его в самом начале предложил. 

Поищите linkedList

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AsNik пишет:

Скажите еще вот что. Если переделать немного так:

const TMenu Menu1 {sizeof(forMenu1)/sizeof(forMenu1[0]), 0, 0, 0, forMenu1};
const TMenu Menu2 {sizeof(forMenu2)/sizeof(forMenu2[0]), 0, 0, 0, forMenu2};
 
на сколько это правильно или нет? С одной стороны теперь не нужно следить за ItemCount.

Сам подход неправильный.

Меня делается списком. Тогда Вам не нужны эти извращения и ходить по нему удобнее.

Я как-то приводил рыбу как это делать и там же в теме вроде и какие-то вопросы были, я отвечал, посмотрите. Лучше сделайте списком по образу и подобию того примера.

AsNik
Offline
Зарегистрирован: 24.10.2020

sadman41 пишет:
Это пока все строки в массиве одного размера.

Не совсем понял, я в каждой константе использую свой массив...

Просто если добавить/убрать пункт в массиве, уже не нужно изменять это в const TMenu MenuN {..}

sadman41
Offline
Зарегистрирован: 19.10.2016

В Micromenu все эти извращения уже оформлены из идеи в работающий исходник.

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

Я как-то приводил рыбу как это делать и

Если честно, то я видел в интернете и такое меню и еще много подобных вариантов. Но с моим уровнем знаний, я не осилю пока это.... У меня немного не совсем то меню, какое вы думаете... Там будет и меню и экраны как бы одно целое. В общем это не рассказать словами. Хотя я уверен, что вы мою задачу сделали бы по другому, но я попробую пока так.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

AsNik пишет:

Скажите еще вот что. Если переделать немного так:

const TMenu Menu1 {sizeof(forMenu1)/sizeof(forMenu1[0]), 0, 0, 0, forMenu1};
const TMenu Menu2 {sizeof(forMenu2)/sizeof(forMenu2[0]), 0, 0, 0, forMenu2};
 
на сколько это правильно или нет? С одной стороны теперь не нужно следить за ItemCount.

brokly пишет:

Это не правильно ни разу.

Наврал. В данном случае, если код из #25, как раз все будет правильно. 

AsNik
Offline
Зарегистрирован: 24.10.2020

brokly пишет:

Наврал. Тут как раз все будет правильно. 

А я уж было поник)

 

Это по другим "стандартным меню" и linkedList. Вот к примеру если у меня будет такой список на экране:

Name    Enable   State

 Item1   <On>    <Off>

 Item2   <On>    <On>  

 Item3   <Off>

>Item4   <On>    <Off>

 Item5   <Off>

 Item6   <On>    <Off>

(ну соответственно будут видны только 4 строки на LCD2004)

Причем управляться будет все одним энкодером с кнопкой. Например короткое нажатие на пункте мы переходим на экран ItemN, а при удержании меняем последнее (State) значение в строке <On-Off-On> с учетом Enable. А вот Enable меняется в другом месте...

А у другого меню свои "заморочки".... Как то так.

AsNik
Offline
Зарегистрирован: 24.10.2020

Я сейчас внимательно почитал "рыбу" из #40 и думаю в методе show можно отрисовать строку как мне нужно, а обработать короткое или длинное нажатие кнопки на элементе тоже можно. Вообще теоретически я там разобрался в обоих примерах. Но использование некоторых "приемов" типа for (SMenuItem * ptr = children; ptr; ptr = ptr->next) { немного затрудняет в редактировании "под себя"

Вообще очень интересно было скомпилировать эту рыбу. Все прокомментировано. И даже с указателями, которых я не очень понимаю, в данных примерах я вроде разобрался. И вообще, помимо меню я там много другого узнал.... Спасибо от души!

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Читайте по теме двусвязные списки на Си, например: https://prog-cpp.ru/data-dls/

Kakmyc
Offline
Зарегистрирован: 15.01.2018

А разве подобный массив char'ов не двумерный ?
По мне так его нужно объявлять как:
char itemName[][];
с точным указанием размера хотя бы правого члена, если есть список инициализаторов.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

AsNik пишет:

В общем это не рассказать словами.

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AsNik пишет:
интересно было скомпилировать эту рыбу.
А кто мешает? Оба примера (#27 и #31) вполне рабочие, запускайте и смотрите в мониторе порта чего делают