двумерный массив с разными типами данных

eldev
Offline
Зарегистрирован: 14.05.2012

Есть ли способ создать двумерный массив с разными типами данных?

на подобный ругается.

char* fan [2][5] = {
  {"auto","low","mid","high","fix"},{B101,B100,B010,B001,B000}
};

 

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

в javascript - да.
В cи вряд ли.

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

Вообщем-то можно... (приведение типов и т.п.), только "не нужно это".

Глядя на данный пример, тут явно просится stuct и массив уже структур. Структуры для того и придуманы. Что-бы и в коде потом не магию типа fun[0] [3] и f[1][3], писать, а осмысленно понятное типа  fun[3].name и fun[3].value

eldev
Offline
Зарегистрирован: 14.05.2012

Получается тогда как-то так

struct cond
{
    char* name[5];
    int value[5];
} type ;

struct cond fan = {{"auto","low","mid","high","fix"},{B101,B100,B010,B001,B000}};

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println(fan.name[2]);
delay(1000);
}

только вот уже на 15 значений данной структурой не воспользоваться... переинициализировать, видимо, надо будет

Вопрос. Если в 15 значные массивы кидать по 5 значений, переизбытка используемого места не будет?

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

>Вопрос. Если в 15 значные массивы кидать по 5 значений, переизбытка используемого места не будет?

Будет. Впустую расходуемое место.

Лучше объявлять name[] - пусть компилятор сам выясняет какой длины строку вы пихаете. Да и char*, в явном виде вы явно указали зря.

Заодно не ошибетесь и в другую сторону (длинную строку, в малый массив).

Нет. Все не так. Сами-то код пускали

>    int value[5];

При объявлении типа структура, мы описываем ОДИН элемент. Один вентилятор. int value[5] - вы, фактически сказали, что у вас КАЖДЫЙ вентилятор, будет иметь ПЯТЬ интовых значений. Это действительно так? То же и с именами. Вы сказали что каждый вентилятор будет иметь пять имен.

>struct cond fan = 

И где тут объявление МАССИВА структур? Объевления переменной типа cond, вижу, а массива.

Вообщем вам нужно при описании cond, описать ОДИН вентилятор.
А потом переменную fan объявить как МАССИВ элементов типа cond.

И работать с ним соотвественно (и инициализация, и доступ к элементам).  Я как писал? fun[3].name - имя четвертого вентилятора, а у вас? fan.name[2] - третье имя единственного вентилятора.

Если уж, так хочется иметь отдельно имена, отдельно значения, то собственно зачем их объединять?

Можно тогда и без структур.

Просто два массива:

char* names[5]={"auto","low","mid"...;
int values[5]={B101,B100,B010...;

И работать с ними names[0] -  имя первого, values[0] - значение первого.

eldev
Offline
Зарегистрирован: 14.05.2012

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

struct cond
{
    char* name[5];
    int value[5];
} type ;

где потом под type и подразумевается fan и другие состояния (mode и temp)

Вентилятор один, у него пять состояний (name), каждое из которых имеет значение (value).

Когда пытаюсь задать name[] - компилятор ругается (создает массив с 1 значением и соответсвено, когда даешь ему 5 - не лезет).

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

По поводу char* - задаю массив строк (прочитал тут же на сайте в справочнике)

То что было написано ранее компилятор вроде отрабатывает без ошибок.

Или я всё же чего-то не понимаю...

 

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

Еще раз. stuct - у вас описывает СОСТОЯНИЕ. А состояние имеет ОДНО имя. И ОДНО значение.

Поэтому "(создает массив с 1 значением и соответсвено, когда даешь ему 5 - не лезет)" - совершенно верно. Так и должно быть.

А после того, как вы описали структурой как выглядит ОДНО состояние, вы объявляете МАССИВ СТРУКТУР. Массив состояний.

Для кого писалось:

leshak пишет:

Вообщем вам нужно при описании cond, описать ОДИН вентилятор.

А потом переменную fan объявить как МАССИВ элементов типа cond.

???

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

Ну ок. Не вентяляторов у вас много, а состояний. Суть это не меняет. Кстати почему бы тогда структуру не назвать state, и массив состояний states[]?  Или что-бы если потом появятся состояние еще чего-нибудь не путстаться и сразу обозвать funState_t и funStates[]

 

 

eldev
Offline
Зарегистрирован: 14.05.2012

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

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

Неэ... так просто вы не отделаетесь. Если не получается "сразу понять", значит еще больше дробить задачу нужно.

Давайте отдельно разбиратся со структурами, отдельно с массивами.

Вначле со структурами. Забудте что у вас есть пять штук.

Опишите стуктуру описывающую ОДНО состояние. И объявите переменную этого типа.

Опиратся можете на этот туториал: Arduino Playground - Struct Resource

И показывайте что вышло.

eldev
Offline
Зарегистрирован: 14.05.2012
struct cond // объявляю структуру кондиционер
{
    char* name;
    int value;
} type ;
cond fan = {"low", B101}; //объявление переменной вентилятор

так?

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

Так. 

Ну если не считать, что у вас постоянно путаница в именах/терминах. То вы говорите что у вас "состояния", то в называете это "кондиционер", то "вентитялтор".

Главное что вы тут должны понять: слово struct - это описание ТИПА. Есть встроенные типы int,byte, boolean. Но нам их не хватило. Пришлось свой придумывать. И вот конструкцией struct мы описали "как он выглядит".

После того как компилятор узнал про этот тип, дальше мы можем пользоватся им так же как и встроенными типами.

Например объявили "cond fun" - объявили переменную "fun" имеющую тип "cond". То есть - заствили выделить память под одно char* и один name.

OK. Теперь давайте несколько штук попробуем (пока без массивов). Как мы объявим, несколько переменных типа cond? Скажем переменные fun1, fun2, fun3?  (подсказка: никаких отличий от встроенных типов. синтаксис - полностью аналогичный).

 

__Alexander
Offline
Зарегистрирован: 24.10.2012

eldev пишет:

Вопрос. Если в 15 значные массивы кидать по 5 значений, переизбытка используемого места не будет?

всмысле, если объявить [15] а в реале написать 5?

компилятор 5 и нарисует. остальные отбросит.

eldev
Offline
Зарегистрирован: 14.05.2012

Ну вроде про структуру состояние я не говорил...

Говорил про состояния работы этого cond (кондиционер - наверное надо было расписать чтобы не вводить в заблуждение) :) (аналоги переменной fan - вентилятор (режим работы вентилятора) (не fun - веселье), т.е. mode (режим работы) и temp (температура работы))

Т.е. fan - у меня получается как одно из состояний работы кондиционера.

 

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

Ну, так как мы объявим несколько переменных fun1, fun2, fun3?

eldev
Offline
Зарегистрирован: 14.05.2012
cond fan1 = {"low", B101}; //объявление переменной вентилятор1
cond fan2 = {"mid", B111}; //объявление переменной вентилятор2
cond fan3 = {"high", B110}; //объявление переменной вентилятор3

 

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

eldev пишет:

cond fan1 = {"low", B101}; //объявление переменной вентилятор1
cond fan2 = {"mid", B111}; //объявление переменной вентилятор2
cond fan3 = {"high", B110}; //объявление переменной вентилятор3

 

О... круто :)  Все верно.

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

Предположим у нас есть три штуки целочисленных переменных. В которых мы при инициализации ложим числа 10, 50, 125.

Вообщем объявлено у нас что-то такое:

int myVar1=10;
int myVar2=50;
int myVar3=125;

Задача: переписать это с использованием массива. Что-бы вместо трех переменных myVar1,myVar2,myVar3 была одна переменная-массив myVars.

Как вы это сделаете?

leshak
Offline
Зарегистрирован: 29.09.2011
eldev
Offline
Зарегистрирован: 14.05.2012
int myVars[3] = {10,50,125};

 

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

Супер. А теперЬ, вот точно так же, абсолютно аналогично, сверните в массив вот этот свой код:

cond fan1 = {"low", B101}; //объявление переменной вентилятор1
cond fan2 = {"mid", B111}; //объявление переменной вентилятор2
cond fan3 = {"high", B110}; //объявление переменной вентилятор3

 Что-бы вместо трех переменных fun1,fun2,fun3 была одна переменная-массив funs.

__Alexander
Offline
Зарегистрирован: 24.10.2012

чёт я не догоняю, а чем не устраивает собственно предложеный ТС вариант со структурами? Вполне удобный и рабочий вариант.

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

__Alexander пишет:

чёт я не догоняю, а чем не устраивает собственно предложеный ТС вариант со структурами? Вполне удобный и рабочий вариант.

Давайте чуть позже, ok? Cразу с двумя непонимающими - тяжко  ;)

eldev
Offline
Зарегистрирован: 14.05.2012

cond fans[3]={{"low", B101},{"mid", B111},{"high", B110}};

eldev
Offline
Зарегистрирован: 14.05.2012

массив структур...

так а структура массивов чем хуже?

__Alexander
Offline
Зарегистрирован: 24.10.2012

я тоже думаю ничем не хуже. тем более она у вас уже написана, берите и пользуйтесь. )

__Alexander
Offline
Зарегистрирован: 24.10.2012
можно еще по другому

typedef struct {
  unsigned char* name; 
  unsigned int value; 
} State;


 State state[5] = {
   {"auto", 0x05},
   {"low", 0x04},
   {"mid", 0x02},
   {"high", 0x01},
   {"fix", 0x00}
};

и так используем.

state[0].name;
state[0].value;

 

 

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

eldev пишет:

cond fans[3]={{"low", B101},{"mid", B111},{"high", B110}};

Ну вот и все.

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

Скажем вам нужно вывести имя второго, состония serial.println(fans[1].name), или значение первого serial.println(fans[0].value);

Можно for-ром, по ним пробежатся. Можно завести еще одну переменную в которой хранить текущий режим вашего вентилятора.

byte currentMode=0; // первый режим

И, скажем где-то в Loop делать analogWrite(fans[currentMode].value));

А одновременно выводит на экран имя текущего режима lcd.print(0,0, fans[currentMode].name);

И, скажем кнопками (или по таймеру), просто менять режим изменяя циферку в currentMode (естественно следя за тем что-бы она не вышла за границы массива).

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

__Alexander пишет:

можно еще по другому

typedef struct {
  unsigned char* name; 
  unsigned int value; 
} State;


 State state[5] = {
   {"auto", 0x05},
   {"low", 0x04},
   {"mid", 0x02},
   {"high", 0x01},
   {"fix", 0x00}
};

и так используем.

state[0].name;
state[0].value;

 

 

Это не "по другому", это и есть то к чему мы пытались привести топикстартера. Только что-бы он сам к этому пришел, а не "вот скопируй себе готовую магию".

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

eldev пишет:

так а структура массивов чем хуже?

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

Тем что в этом случае зазор между кодом и семантикой и синтаксисом - больше.

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

В том что если нужно, скажем, добавить еще одно состояние, то мы должны будем его "добавить расписать" в два разных места, а не в одно. В том что "закоментить" или copy-paste одно состояние - трудней.

У нас части одной, по сути, "сущности" размазны по разным массивам. А если полей будет 10-ток? 10-ть массивов лепить? А если, нужно будет скажем передать в функцию в качестве параметра?

Сейчас-то просто... void myFunc(cond* arg); А с массивами как?  Не ну можно, конечно, только ведь насколько "угробищьней" код будет выглядить.

А скопировать описание состояния?  В массиве структур я сделаю memcpy (&state_copy, &state, sizeof(cond));

А в случае структуры массивов как ваш код будет выглядеть?

Вообщем если вы делаете "структуру массивов", то после этого выкидываете структуру, ничего при этом не потеряв и улучшив читаемость кода, и получаете просто "два массива". Что есть тоже вариант. О чем изначально и говорилось.

sirota
Offline
Зарегистрирован: 18.08.2015

А как теперь узнать размерность?

typedef struct {
  unsigned int id;
  unsigned int x;
  unsigned int y;
  unsigned int w;
  unsigned int h;
  } Baton;

  Baton baton[3]= {
    {1, 0, 0, 150, 80},
    {2, 0, 113, 50, 50},
    {3, 270, 113, 50, 50}
  };

Конструкция вида:

int i = baton.length;

Не работает (

Псрото в делфе подобная вещь спокойно работает. Даже когда скажем я использую конструктор типа массив в массиве length всегда отрабатывает. А тут (

Сам же и отвечу на свой вопрос:

int i = sizeof( baton ) / sizeof( Baton )

Первый раз получаем размер в байтах всего массива, а затем делим его на размер записи одного элемента. Очень удобно.