Возникла проблема с доступом к значениям из указателя

Контекст

Возможно, это больше вопрос по C++, чем по Arduino, но он касается arduino C++, поэтому я решил начать здесь.

Я создаю класс для абстрагирования простой мелодии, которую я хочу использовать в проекте. У меня все работало процедурным образом, поэтому я начал перемещать все в заголовок и файл cpp (все еще новая для меня территория).

Общая концепция заключается в том, что я хочу вызвать общедоступный метод своего класса, чтобы мой код мог воспроизводить определенную мелодию. Я определил перечисление для каждой доступной мелодии, и в моем методе playMelody() я использую пару указателей и оператор switch, чтобы получить конкретные частоты и длительность, необходимые для воспроизведения конкретной мелодии. Эти значения частоты и продолжительности хранятся в закрытых массивах класса.

Вот заголовок:

// MelodyPlayer.h

enum MELODY
{
    SHAVE_AND_A_HAIRCUT = 0,
    IDLE,
    READY,
    PROCESSING,
    COMPLETE,
};

class MelodyPlayer
{
    uint8_t speakerPin;

    int melody_shaveAndAHairCut[9];
    int durations_shaveAndAHairCut[9];
    int *activeMelody;
    int *activeDurations;

    void _playMelody();

public:
    MelodyPlayer(uint8_t speakerPin);
    void playMelody(MELODY name);
};

MelodyPlayer::MelodyPlayer(uint8_t pin)
{
    speakerPin = pin;

    int melody_shaveAndAHairCut[] = {
        NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4, 0};

    int durations_shaveAndAHairCut[] = {
        4, 8, 8, 4, 4, 4, 4, 4, 4};
}

void MelodyPlayer::playMelody(MELODY name)
{
    switch (name)
    {
    case SHAVE_AND_A_HAIRCUT:
        Serial.println("Shave and a hair cut");
        activeMelody = melody_shaveAndAHairCut;
        activeDurations = durations_shaveAndAHairCut;
        break;
    }

    _playMelody();
}

А вот и реализация:

// MelodyPlayer.cpp

void MelodyPlayer::_playMelody()
{
    Serial.println("Playing Melody");
    // * pulled from the toneMelody arduino example
    for (int thisNote = 0; thisNote < 8; thisNote++)
    {

        int activeDuration = activeDurations[thisNote];
        int noteDuration = 1000 / activeDurations[thisNote];
        int noteFrequency = activeMelody[thisNote];

        Serial.println(thisNote);
        Serial.println(activeDuration);
        Serial.println(noteDuration);
        Serial.println(noteFrequency);

        tone(speakerPin, noteFrequency, noteDuration);

        int pauseBetweenNotes = noteDuration * 1.30;
        delay(pauseBetweenNotes);

        noTone(speakerPin);
    }
}

И я вызываю это в своем файле .ino следующим образом:

MelodyPlayer player = MelodyPlayer(SPEAKER);
player.playMelody(SHAVE_AND_A_HAIR_CUT);

Проблема

Я загружу скетч и все заработает. Проблема, с которой я сталкиваюсь, заключается в том, что когда я получаю частный метод _playMelody(), значения, которые я получаю для activeDuration, noteDuration и noteFrequency абсолютно неверны:

пример вывода

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

Вы можете увидеть/вытащить фактический код из abstracting-to- class ветвь моего репозитория, если вы хотите покопаться.

Я выполнил похожий динамический выбор через указатель в доказательстве концепции ранее, но он был написан процедурно, а не классифицирован. Не могу понять, в чем разница :|

Есть идеи?

, 👍0

Обсуждение

Ваши массивы мелодии и длительности, содержащие фактические данные, являются локальными для конструктора. Кроме того, они не используются, поэтому компилятор их оптимизирует., @Majenko


1 ответ


Лучший ответ:

3

Как упомянул Майенко в комментарии, вы создали новые локальные массивы в конструкторе, но никогда ничего не помещали в массивы-члены классов. Они имеют одно и то же имя, но не являются одной и той же переменной. За создание новой переменной отвечает ключевое слово int. Однако вы не можете просто присвоить значения массива, просто опуская int. Есть несколько вариантов:

  • Можно заполнить массив для каждого индекса: durations_shaveAndAHairCut[0] = 1;

  • Вы можете скопировать локальный массив в переменную-член с помощью memcpy: memcpy((void*)this->durations_shaveAndAHairCut, (void*)durations_shaveAndAHairCut, 9*sizeof(int));

  • Вы можете объявить массивы статическими в объявлении класса и инициализировать их вне конструктора в MelodyPlayer.cpp:

    int MelodyPlayer::durations_shaveAndAHairCut[] = {
        4, 8, 8, 4, 4, 4, 4, 4, 4};
    

    Я предпочитаю последний вариант.

,

Потрясающий! Спасибо за помощь! Я пошел с последним вариантом. Это определенно кажется самым простым и прямым решением., @Chris Schmitz