Инициализация трехмерного массива двумерными

MXPain
Offline
Зарегистрирован: 13.06.2014
int pattern_1[8][16] =  {{1, 0, 0, 0,  1, 0, 0, 0,  1, 0, 0, 0,  1, 0, 0, 0},
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},//drop bomb
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0}};//siren
                         
int pattern_2[8][16] =  {{1, 0, 0, 0,  0, 0, 0, 0,  0, 0, 1, 0,  0, 0, 0, 0},
                         {0, 0, 0, 0,  1, 0, 0, 0,  0, 0, 0, 0,  1, 0, 0, 0},
                         {0, 0, 1, 0,  0, 0, 1, 0,  0, 0, 1, 0,  0, 0, 1, 0},
                         {0, 0, 0, 0,  0, 1, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 1, 0,  0, 0, 0, 0},//drop bomb
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 1, 0, 0,  0, 0, 0, 0},
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0}};//siren

int song[4][8][16]= {pattern_1, pattern_1, pattern_2, pattern_2};

выдает ошибку array must be initialized with a brace-enclosed initializer

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

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

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

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

MXPain пишет:

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

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

Если надо просто инициализировать, то  Вам уже всё подсказал компилятор - надо использовать " brace-enclosed initializer" - какие подсказки Вам ещё нужны? Просто используете как говорят, и всё.

#define pattern_1	{{1, 0, 0, 0,  1, 0, 0, 0,  1, 0, 0, 0,  1, 0, 0, 0},\
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},\
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},\
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},\
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},\
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},\
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},\
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0}}
                         
#define pattern_2	{{1, 0, 0, 0,  0, 0, 0, 0,  0, 0, 1, 0,  0, 0, 0, 0},\
                         {0, 0, 0, 0,  1, 0, 0, 0,  0, 0, 0, 0,  1, 0, 0, 0},\
                         {0, 0, 1, 0,  0, 0, 1, 0,  0, 0, 1, 0,  0, 0, 1, 0},\
                         {0, 0, 0, 0,  0, 1, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},\
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0},\
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 1, 0,  0, 0, 0, 0},\
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 1, 0, 0,  0, 0, 0, 0},\
                         {0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0}}
                         
int song[4][8][16]= {pattern_1, pattern_1, pattern_2, pattern_2};

Другое дело, что непонятно зачем держать в памяти по два одинаковых массива - Вы их что, менять собираетесь по ходу выполнения? А если нет, то нафига дублируете? Не логичнее ли завести указатели и указывать на одно и тоже место?

MXPain
Offline
Зарегистрирован: 13.06.2014

Ну да, по идее массив song должен содержать в себе указатели на массивы паттернов, правильно? 

MXPain
Offline
Зарегистрирован: 13.06.2014

mykaida пишет:

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

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

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

MXPain пишет:

Ну да, по идее массив song должен содержать в себе указатели на массивы паттернов, правильно? 

В song четыре паттерна, но на самом деле - две пары одинаковых. Если не предполагается их менять в процессе работы программы, то лучше сделать указателями, чтобы не хранить одинаковые данные в двух разных кусках памяти. А предполагается, или если по какой другой причине они по жизни должны занимать разную память, то можно оставить как я написал

MXPain
Offline
Зарегистрирован: 13.06.2014

В процессе менять не планируется, это пока так быстрый набросок девайса за вечерок и всю логику еще  до конца не продумывал, по идее нужно сделать определенное число редактируемых паттернов например 99, т е это число будет неизменным, и например 10 динамических массивов для сонгов, в которые уже можно забивать любые последовательности паттернов.

MXPain
Offline
Зарегистрирован: 13.06.2014

int *song[4] = {&pattern_1, &pattern_1, &pattern_2, &pattern_2};

будет ли такой вариант правильным? Или нужно указывать полную размерность массива int *song[4][8][16]?

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

Ни то ни другое.

Если Вам нужен указатель, то для начала определитесь "на что" он указывает. И тогда уж описывайте его тип

MXPain
Offline
Зарегистрирован: 13.06.2014

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

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

Не знаю, Вам виднее, что Вам нужно.

MXPain
Offline
Зарегистрирован: 13.06.2014

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

Ни то ни другое.

Если Вам нужен указатель, то для начала определитесь "на что" он указывает. И тогда уж описывайте его тип

кстати объясните плиз почему ни то и не другое, разве int *song[4] не массив указателей создаст?  {&pattern_1, &pattern_1, &pattern_2, &pattern_2} а эта запись по идее же проинициализируют его ссылками на реальные структуры и не создаст в памяти их копий? Объясните как оно правильно должно быть))

b707
Offline
Зарегистрирован: 26.05.2017

MXPain пишет:

кстати объясните плиз почему ни то и не другое, разве int *song[4] не массив указателей создаст?  {&pattern_1, &pattern_1, &pattern_2, &pattern_2} а эта запись по идее же проинициализируют его ссылками на реальные структуры и не создаст в памяти их копий? Объясните как оно правильно должно быть))

имя массива в Си - это уже указатель на нулевой элемент. А что такое &pattern_1 - я даже затрудняюсь сказать, что-то типа адреса указателя....пусть старшие подскажут

 

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

& - операция взятия адреса. То, на что указывает пойнтер.

int a = 3; int *b = &a;

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

MXPain пишет:
разве int *song[4] не массив указателей создаст?
Массив указателей на int, а Вам надо на двухмерный массив int'ов

b707
Offline
Зарегистрирован: 26.05.2017

sadman41 пишет:
& - операция взятия адреса. То, на что указывает пойнтер. int a = 3; int *b = &a;

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

Почитал немного в гугле - разобрался:

если x - это массив, описанный как int x[3], то

x - это адрес нулевого элемента

а &x - это адрес всего массива

Численно эти два значения совпадают, но типы разные, именно поэтому выражение ТС неверное.

MXPain
Offline
Зарегистрирован: 13.06.2014

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

int (*song)[8][16] = {&pattern_1[0], &pattern_1[0], &pattern_2[0], &pattern_2[0]};

 

b707
Offline
Зарегистрирован: 26.05.2017

MXPain пишет:

Если со второй половиной выражения я более менее понял что в качестве указателя на массив, нужна ссылка на первый элемент массива

Нет, с правой частью вы тоже разобрались не до конца. Во-первых, приоритет операции взятия адреса выше, чем получения элемента массива, поэтому запись &x[0] сработает как (&x)[0], а вам надо &(x[0]). Ну а во-вторых - буквально в предыдущем сообщении я написал. что ссылка на первый жлемент массива записывается куда проще - просто x

Что у вас написано в левой части - я вообще не понимаю, обьясните

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

Загнать все данные в многомерный массив - это принципиальное решение? По-моему задача излишне усложнена.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

b707 пишет:

sadman41 пишет:
& - операция взятия адреса. То, на что указывает пойнтер. int a = 3; int *b = &a;

если x - это массив, описанный как int x[3], то

x - это адрес нулевого элемента

а &x - это адрес всего массива

это как???

b707
Offline
Зарегистрирован: 26.05.2017

ua6em пишет:

это как???

пример попроще. Переменную типа long можно представить как массив байт, верно?

long x = 34;

long  *a = &x;
uint8_t *b = (uint8_t*) &x;

Численное значение ссылок а и b - одинаковое, но тип разный. Точно так же как со сссылкой на массив и на его нулевой элемент.

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

Боюсь, что это больше заморочки компилятора - не дать программисту путать типы. В реальной памяти, надо думать, "адрес массива" и "адрес нулевого элемента" эквивалентны, коль скоро "индекс есть смещение" ;)

b707
Offline
Зарегистрирован: 26.05.2017

sadman41 пишет:

Боюсь, что это больше заморочки компилятора - не дать программисту путать типы. В реальной памяти, полагаю, "адрес массива" и "адрес нулевого элемента" эквивалентны ;)

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

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

Можно я попробую объяснить то, что пытается донести b707? Похоже, нет понимания того, что он хочет сказать. Может, у меня получится.

Вот, смотрите:

byte f[16];

auto f1 = f;
auto f2 = &f;

Численно f, f1 и f2 равны между собой, но f и f1 - это указатели на первый (нулевой) элемент массива, т.е. указатели на байт!!! А вот f2 - указатель на массив целиком - на 16-тибайтовую область. 

Чтобы прочувствовать разницу, запустите вот такой пример и посмотрите на то, что он печатает

#include <Printing.h>

byte f[16];

void setup() {
	Serial.begin(57600);
	auto f1 = f;
	auto f2 = &f;

	printf("   f = %p\r\n", f);
	printf("  f1 = %p\r\n", f1);
	printf("  f2 = %p\r\n", f2);
 	//
	printf("f1+1 = %p\r\n", f1 + 1);
 	printf("f2+1 = %p\r\n", f2 + 1);
}
void loop() {}

// РЕЗУЛЬТАТ
//   f = 0x158
//  f1 = 0x158
//  f2 = 0x158
//f1+1 = 0x159
//f2+1 = 0x168

Строки №№ 20-22 показывают, что численно все три переменные равны между собой.

В строке №23 мы видим, что при сложении с единицей f1 численно увеличился на 1, это значит, что f1 - указывает на byte. А вот в строке №24 мы видим, что f2 при сложении с 1 увеличился сразу на 16 (0x10), из чего следует, что f2 указывает не на байт, а 16-байтовый кусок памяти, т.е. на массив f целиком.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Гениальна!   Просто и наглядно.  Спасибо!

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Теперь понятно, указатель второго типа позволяет взять адрес конца массива

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

ua6em пишет:

Теперь понятно, указатель второго типа позволяет взять адрес конца массива

Не только. Если у Вас "массив массивов" как у ТС, он позволяет выбирать нужный "подмассив".

MXPain
Offline
Зарегистрирован: 13.06.2014

sadman41 пишет:

Загнать все данные в многомерный массив - это принципиальное решение? По-моему задача излишне усложнена.

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