Передача двумерного массива в функцию
Я работаю над проектом светодиодной матрицы, где запускаю серию паттернов, сделанных из растровых кадров.
Вот пример: https://vimeo.com/564184465
Прямо сейчас я использую серию вызовов методов с именем per pattern для запуска анимации:
void CSMatrix::runPattern(PATTERNS pattern, uint8_t totalRuns)
{
for (uint8_t i = 0; i < totalRuns; i++)
{
switch (pattern)
{
case PATTERN_ZIG_ZAG:
runPatternSpacedStripes();
break;
case PATTERN_ARROW_UP:
runPatternArrowUp();
break;
...
}
}
}
void CSMatrix::runPatternSpacedStripes()
{
for (uint8_t i = 0; i < SPACED_STRIPES_LEN; i++)
{
renderFrame(SPACED_STRIPES[i]);
FastLED.show();
delay(100);
}
}
void CSMatrix::runPatternArrowUp()
{
for (uint8_t i = 0; i < ARROW_UP_LEN; i++)
{
renderFrame(ARROW_UP[i]);
FastLED.show();
delay(100);
}
}
...
А растровые изображения, используемые для управления состояниями пикселей матрицы, выглядят следующим образом (функции под renderFrame
в основном говорят: "если это 1, используйте этот цвет, если это 0, используйте этот цвет":
const byte SPACED_STRIPES[][8] = {
{0b11000110,
0b10001100,
0b00011000,
0b00110001,
0b01100011,
0b11000110,
0b10001100,
0b00011000},
{0b01100011,
0b11000110,
0b10001100,
0b00011000,
0b00110001,
0b01100011,
0b11000110,
0b10001100},
...
};
const int SPACED_STRIPES_LEN = sizeof(SPACED_STRIPES) / 8;
Это работает нормально, но иметь кучу одинаковых методов для запуска каждого шаблона не очень хорошо.
Итак, после этой работы я решил провести рефакторинг, чтобы создать общий метод runTwoColorPattern, который мог бы принимать кадры шаблона и длину для запуска данного шаблона:
void CSMatrix::runTwoColorPattern(const byte *frames, const int length, int delayDuration)
{
for (uint8_t i = 0; i < length; i++)
{
renderFrame(frames[i]);
FastLED.show();
delay(delayDuration);
}
}
Проблема, с которой я сталкиваюсь, заключается в том, чтобы выяснить, как правильно передать двумерный массив функции.
Я попытался обновить свой оператор switch, передав указатель SPACED_STRIPES
в runTwoColorPattern
:
switch (pattern)
{
case PATTERN_ZIG_ZAG:
runTwoColorPattern(SPACED_STRIPES, SPACED_STRIPES_LEN, 100);
//runPatternSpacedStripes();
break;
Но когда я это делаю, я получаю ошибку
аргумент типа "const byte (*)[8]" несовместим с параметром типа "const byte *"C/C++(167)
Я обнаружил, что могу исправить это, разыменовав первый элемент многомерного массива (что означало бы, что я передаю адрес памяти первому элементу указателя многомерного массива (я думаю)), но когда я делаю это, шаблон работает в обратном направлении и дрожит :|
https://vimeo.com/564184624
Я не совсем уверен, как это исправить. Я все еще довольно новичок в указателях, поэтому я уверен, что есть что-то, что я неправильно понимаю при передаче указателя для многомерного массива, но я думал, что то, что я передавал, было в основном адресом того, с чего начать для указателя, поэтому я не уверен, почему я попадаю в эти коряги или как чтобы все исправить.
Есть какие-нибудь предложения?
@Chris Schmitz, 👍0
Обсуждение2 ответа
Лучший ответ:
2D - массив будет передаваться в виде кадров const byte[][8]
. Однако вам действительно не нужна сложность 2D - массива-вы можете сделать это с помощью 1D-массива.
Ваш массив будет выглядеть следующим образом:
const byte SPACED_STRIPES[] = {
0b11000110,
0b10001100,
0b00011000,
0b00110001,
0b01100011,
0b11000110,
0b10001100,
0b00011000,
0b01100011,
0b11000110,
0b10001100,
0b00011000,
0b00110001,
0b01100011,
0b11000110,
0b10001100,
...
};
И вы ссылаетесь на фреймы внутри него как на кратное 8 индексу. Используя ваш существующий код, это будет выглядеть так:
void CSMatrix::runTwoColorPattern(const byte *frames, const int length, int delayDuration)
{
for (uint8_t i = 0; i < length; i++)
{
renderFrame(&frames[i * 8]); // Взять адрес первого значения кадра, кратного 8
FastLED.show();
delay(delayDuration);
}
}
Потрясающе, это сработало! Я обновил свой шаблон и метод, и теперь анимация работает так, как ожидалось. Реализация изменений также помогла мне понять, к чему именно вы стремитесь; структура многомерного массива помогла мне визуально, но не является необходимой для синтаксического анализа. Другое дополнительное преимущество такого способа заключается в том, что теперь, когда это плоский массив, я могу отправлять большие двоичные объекты произвольного размера для матриц разного размера (16x16, 32x32 ...) и просто параметризовать множитель для захвата индекса указателя. Еще раз спасибо за помощь!, @Chris Schmitz
Re “const byte *frames[8]
”: вы имеете в виду const byte (*frames)[8]
., @Edgar Bonet
@EdgarBonet Я никогда в жизни не видел такого формата. На самом деле я имел в виду " кадры[][8]. Является ли
(*frames)[8]` каким-то более новым синтаксисом C++, которого не существовало, когда меня учили C в университете?, @Majenko
AFAIK, `(*frames)[8] ' - это ANSI C, может быть, даже K&R C., @Edgar Bonet
Ну, я когда-либо сталкивался с такими скобками только при работе с указателями функций., @Majenko
@EdgarBonet Я рыскал по сети, и я нашел ровно один пример, использующий этот формат, без объяснения того, что это такое и как это работает. Я нашел тот, который использует (*name)[X][Y]
, который утверждает, что передает указатель на 2D-массив, и который я могу полностью понять. Я думаю, что (*name)[X]
передает 2D-массив в качестве указателя на 1D-массив. Действительный, но какой-то взлом. Кажется, нигде он не используется, все примеры либо " *name []", либо "**name", либо `name[][X]"., @Majenko
Вы найдете пару примеров с объяснением, если будете искать “указатель C на массив” в stackoverflow. Это не хак, это стандартный синтаксис, хотя и достаточно запутанный для большинства людей, чтобы избежать его. [name[][X]
неявно переводится компилятором в (*name)[X]
](http://c-faq.com/aryptr/aryptrparam.html), но этот перевод выполняется только в объявлениях параметров функций. См. также [Как объявить указатель на массив?](http://c-faq.com/aryptr/ptrtoarray.html) и [Как передать двумерный массив](http://c-faq.com/aryptr/pass2dary.html) в разделе C FAQ., @Edgar Bonet
Сообщение об ошибке довольно явное:
аргумент типа "const byte (*)[8]" несовместим с параметром типа "const byte *".
Если вы хотите передать SPACED_STRIPES
методу, он будет
передан как const byte (*)[8]
, то есть указатель на массивы из 8 байтов
. Вы
можете просто установить тип параметра соответствующим образом:
void CSMatrix::runTwoColorPattern(
const byte (*frames)[8], const int length, int delayDuration)
{
// тело без изменений
}
Спасибо за этот ответ. В итоге я предложил упростить массив, но этот ответ помогает мне понять ошибку, которую я получал. Я не понимал, что могу написать сигнатуру метода с помощью паренов вокруг указателя., @Chris Schmitz
- Массив динамического размера в качестве члена класса
- Работает с gcc, но не с Arduino. ошибка: taking address of temporary array
- Передача массивов, глобальных массивов внутри функций, указателей и объявление размеров массивов.
- Скетч с несколькими классами (.h и .cpp) – как соединить классы
- Установка указателя массива на null при объявлении
- Почему я не могу получить размер массива указателей
- Как работают массивы?
- Поменять местами два массива (используя указатели, а не копирование)
Для этого вам действительно не нужен 2D - массив-подойдет простой 1D-массив и просто используйте смещения, кратные 8, для чтения каждого кадра., @Majenko
Ааааааа это правда! Я работал с этим форматом b/c, было легко визуально проанализировать и настроить растровые изображения вручную после их генерации из онлайн-калькулятора, но в конечном счете этот формат не нужен. Итак, чтобы повторить, чтобы убедиться, что я понимаю: я могу сделать массив 1d, где каждый элемент представляет собой одно числовое представление кадра, и эти числа могут быть проанализированы по 8 бит за раз, чтобы получить строки внутри кадра, верно?, @Chris Schmitz
Нет, у вас просто будет большой "blob" из 8-битных значений. Точно так же, как у вас сейчас, но без
}, {
между каждым кадром. Затем кадр 0 начинается со смещения 0. Кадр 1 со смещением 8. Рамка 2 со смещением 16 и т. Д. В основном&frames[i * 8]
, @Majenkoа, еще проще. Я попробую, и когда он заработает, я опубликую ответ. Спасибо за помощь!!, @Chris Schmitz