Диапазон символов из char

Тема в разделе "Arduino & Shields", создана пользователем Hatski, 10 июн 2017.

Метки:
  1. Hatski

    Hatski Нуб

    Доброго времени суток всем гуру кодинга.
    Допустим, есть постоянная char t = "abcde". Ее значение известно и оно не меняется.
    И есть вывод этого значения Serial.print(t[3]). В мониторе порта получаем d.

    И вот собственно вопрос. Можно ли используя минимум кода (без всяких циклов на подобие for) получить на выходе скажем bсd или abce? То есть символы с первого по третий для первого варианта и символы с нуля по второй плюс четвертый для второго варианта.

    Так-как делать t[0]+t[1]+t[2] и т.д. это какой-то быдлокодинг. А вариант с t[0-2] у меня не прокатил =)
    Извиняюсь, если для кого-то этот вопрос покажется глупым и такую возможность не реализовать на таких условиях.
     
  2. mcureenab

    mcureenab Гуру

    strcpy
    sprintf
     
  3. Hatski

    Hatski Нуб

    А можно пример с этими функциями, чтобы в итоге получить какой-то вариант из вопроса?
    А то быстрый пробег по гуглу мне не принес результат
     
  4. mcureenab

    mcureenab Гуру

    Код (C++):
    char *t = "abcde";
    char b [6];
        strcpy ( b, t );
        b [4]=0;
        Serial.print(b+1); // bcd
     
     
    Последнее редактирование: 10 июн 2017
    Tomasina и Hatski нравится это.
  5. Hatski

    Hatski Нуб

    На живом примере понятно как работает.
    Спасибо
     
  6. qwone

    qwone Гик

    Вот вопрос нуба в Си.
    "постоянная char t = "abcde". . Это не постояная а массив из char. Но если бы вниматльно изучили Си, то написали бы const char *t="qaaq" ; это уже указатель. И c ним возможна адресная арифметика. . если t[0] или *t то будет вам 'a' если t[1] или *(t+1) 'b' ; если инрементировать указатель t++ и распечатать Serial.print (t), то будет "aaq". Ну и так далее. Другой вопрос :почему вы такие банальные вещи спрашиваете на форуме, а не ищете в первоисточника,я не смогу ответить.
     
  7. Hatski

    Hatski Нуб

    qwone Понятно, что char это массив символов. Слово постоянная я написал, чтобы заранее было понятно, что с этим значением в процессе кода не будут происходить какие-то либо изменения. Хотя в данном примере это и не важно.
    Смотрите, я написал вопрос. Пускай он по вашему нубский, так-как я использовал неправильные слова для обозначения типов данных. Но я получил на него ответ от mcureenab. Попросил привести пример для лучшего понимания работы кода. mcureenab написал пример. Из которого я сразу понял, что b "берет" значения t, после 4ый символ b обнуляется (конец строки) и далее выводим b начиная с первого символа.
    Из того-что написали вы, я почти ничего не понял. Почему t[0] у вас становится 'a', а (t+1) 'b' если в начале вы написали ''qaaq', а в конце снова
    От куда вы взяли эти 'a' и 'b' тогда? Но не суть важно.
    Я отвечу. Потому, что освоить С++ за 21 день (как в популярном демотиваторе) мне не удалось.
    И штудировать весь материал, ради одной маленькой функции как-то знаете не очень.
    То что мне не понятно, ищу в гугле. Быстрее и "живые" примеры кода лучше усваиваются.
    А вот эту информацию увы не нашел.
    И еще раз повторяю. Я получил вразумительный и "спокойный" ответ на свой вопрос от mcureenab.
    Но вы все равно вставили сюда свои 5 копеек!
     
  8. qwone

    qwone Гик

    Я вставил сюда 5 кореек, потому что вы в упор не заметили 5штук баксов. А проще говоря указатели. в часности указатели на char. Без знаний этого Си , Си++ становится посредсвенностью. А так как вы все же усваете лучше на "живых" примерах, то обучающий пинок это то что доктор прописал.http://cpp.com.ru/kr_cbook/ch5kr.html#cnt
     
  9. rkit

    rkit Гуру

    Serial.print(t+1, 2);

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

    Hatski Нуб

    qwone ну мимо 5ти штук баксов я бы точно не прошел)). А про указатели я действительно не знал. Не приходилось еще с ними сталкиваться. За статью спасибо, обязательно почитаю.
    Но вся суть в чем. Вместо того, чтобы "хвалиться" своими мега крутыми познаниями в этом языке (с которыми вы видимо родились), могли бы тихо, спокойно, написать пример кода как это сделал mcureenab. Заметьте, я сразу понял принцип работы данного кода и мне не пришлось читать тонну возможно лишней для себя информации.

    rkit абсолютно с вами согласен. Но если бы моей целью в жизни было стать богов С++, то со штудирование основ я бы и начал. А так, просто захотел написать маленький кодик, на 700 строк),
    для управления некоторыми устройствами в доме.
    Вы не поверите, но за последний месяц, я практически ничего не зная в C++ научился использовать не только светодиоды да сервоприводы, но и более экзотичные вещи как сдвиговые регистры и ленты WS2812. Даже написал под них несколько своих анимаций.
    А все благодаря таким людям как я и как вы. Одни задавали вопросы на форумах, другие отвечали приводя примеры кода. А я во все это вникал
     
  11. qwone

    qwone Гик

    Где вы нашли лишнюю информацию. Если мне сейчас предложили ,что важнее знать светодиоды, сервоприводы,сдвиговые регистры ленты WS2812 и еще разной хрени или же знать все возможности указателей. То я бы выбрал указатели. Потому что без них у вас не получится программирование.
     
  12. Hatski

    Hatski Нуб

    qwone да я написал, что это для меня возможно пока лишняя информация, а не лишняя информации вообще. Так как я задался целью написать код для своих устройств. И эта цель у меня успешно реализовалась. Но, когда мне захотелось оптимизировать все это дело, чтобы снизить потребление оперативки (которой в ардуино и так не много, а уже поджимало) я столкнулся с проблемой. Появилось эдакая идея сгруппировать некоторые значения. Но вот как это сделать, а именно, как из одного массива char брать выборочно ряд сивмолов для подставленния их в разные функции не знал. Гугл тоже не помог.
    Нашел эту функцию, но не понимал как она работает.
    И у меня лучше складывается осознание происходящего, когда я беру код, вижу что он работает. Потом вникаю в него, возможно меняя какие-то его значения (для еще более лучшего понимания), и после пишу свой код на основе полученных знаний.
    Это процесс куда быстрее и увлекательнее (так как сразу можно пощупать результат), вместо того чтобы часами читать занудные тексты и пытаться в голове все это сложить
     
  13. qwone

    qwone Гик

    Вот когда вы упретесь в очередной потолок, или банально у вас появится тяга почитать нудные книги. То полистайте это http://cpp.com.ru/
    Ну и так код который так интересно посмотреть и посмотреть как он работает. Да и он рабочий.
    Код (C++):
    /*Cl_aJoystick_v3.ino
          синий экран
      Serial clock out   5(SCLK) -->3
      Serial data out     4(DIN) -->4
      Data/Command select 3(D/C) -->5
      LCD chip select      2(CS) -->6
      LCD reset           1(RST) -->7
                          6(Vcc) -->3.3V
                           7(BL) -->3.3V
                          8(GND) -->GND
      Джойстик (GND) --> GND
               (+5V) --> +5V
               (VRx) --> A0
               (VRy) --> A1
                (SW) --> A2
    */

    #include <Adafruit_GFX.h>
    #include <Adafruit_PCD8544.h>
    Adafruit_PCD8544 display = Adafruit_PCD8544(/*SCLK*/3,/*DIN*/4,/*D/C*/5,/*CS*/6,/*RST*/7);
    class Cl_Sys;// предварительно объявить о создании класса Sys для послед подключения к нему
    //-----Cl_aJoystick-------------------------------------------------------
    const int delta = 5; // колебание значения на аналоговых выходах, которые можно игнорировать
    class Cl_aJoystick {
        byte VRx_pin ; // номер ноги на выводе VRx
        byte VRy_pin ; // номер ноги на выводе VRy
        byte SW_pin  ; // номер ноги на выводе SW
        void (* Do_SW)(byte, byte); //указатель на обработчик кнопки SW
        int VRx_old; // старые значение на канале X
        int VRy_old; // старые значение на канале Y
        bool SW, SW_old;
        bool   bounce_VRx = 0, bounce_VRy = 0, bounce_SW = 0; // антидребезговый флаг
        uint32_t past_VRx = 0, past_VRy = 0  , past_SW = 0   ;
      public:
        byte x, y   ; // положение надписи
        char * txt = NULL ; // указатель на надпись
        // указатель на следующий элемент
        Cl_aJoystick *pnt;
        // конструктора
        Cl_aJoystick(Cl_Sys *Sys, byte _1pin, byte _2pin, byte _3pin, void (* _Do_SW)(byte, byte));
        void setup() {
          pinMode(VRx_pin, INPUT)       ;// подключить вывод VRx
          pinMode(VRy_pin, INPUT)       ;// подключить вывод VRy
          pinMode(SW_pin , INPUT_PULLUP);// подключить вывод SW с подтяжкой
          VRx = analogRead (VRx_pin);
          x = map( VRx, 0, 1023, 0, 83);
          VRy = analogRead (VRy_pin);
          y = map( VRy, 0, 1023, 0, 47);
          SW = digitalRead(SW_pin) ;
        }
        // setup()
        void loop() {
          // проверяем аналог канал х
          int analog = analogRead (VRx_pin);
          if (! bounce_VRx && (VRx < analog - delta || VRx > analog + delta)) { // если прошел фронт изм на выводн
            bounce_VRx = 1;                    // выставить флаг
            past_VRx = millis();               // сделать временую засветку
          } else if ( bounce_VRx && millis() - past_VRx >= 5 ) { // если прошло антидребезговое время
            bounce_VRx = 0;      // то снять флаг
            VRx_old = VRx ;
            VRx = analog ; // прочитать реальное значение на выводе
            x = map( VRx, 0, 1023, 0, 83);

          }
          // проверяем аналог канал y
          analog = analogRead (VRy_pin);
          if (! bounce_VRy && (VRy < analog - delta || VRy > analog + delta)) { // если прошел фронт изм на выводн
            bounce_VRy = 1;                    // выставить флаг
            past_VRy = millis();               // сделать временую засветку
          } else if ( bounce_VRy && millis() - past_VRy >= 5 ) { // если прошло антидребезговое время
            bounce_VRy = 0;      // то снять флаг
            VRy_old = VRy ;
            VRy = analog ; // прочитать реальное значение на выводе
            y = map( VRy, 0, 1023, 0, 47);
          }
          // проверяем кнопку SW
          if (! bounce_SW && SW != digitalRead(SW_pin)) { // если прошел фронт изм на выводн
            bounce_SW = 1;                    // выставить флаг
            past_SW = millis();               // сделать временую засветку
          } else if ( bounce_SW && millis() - past_SW >= 5 ) { // если прошло антидребезговое время
            bounce_SW = 0;      // то снять флаг
            SW_old = SW ;
            SW = digitalRead(SW_pin) ; // прочитать реальное значение на выводе
            if (! SW_old && SW)  Do_SW(x, y);
          }
        }
        int VRx ; // значение на канале X
        int VRy ; // значение на канале Y
    };
    //-----Cl_Label-------------------------------------------------------------
    class Cl_Label {
      public:
        byte x, y, w, h; // геомет размеры поз x,y w-ширина h-высота
        char *txt = NULL;
        // указатель на следующий элемент
        Cl_Label *pnt;
        // конструктора
        Cl_Label(Cl_Sys *Sys, byte _x, byte _y, byte _w, byte _h, char *_txt);
        void setup() {
        }
        // setup()
        void loop() {
        }
    };
    //-----Cl_Btn-------------------------------------------------------------
    class Cl_Btn {
      public:
        void (* Do)(); // указатель на обработчик клик
        byte x, y, w, h; // геомет размеры поз x,y w-ширина h-высота
        char *txt = NULL;
        // указатель на следующий элемент
        Cl_Btn *pnt;
        // конструктора
        Cl_Btn(Cl_Sys *Sys, byte _x, byte _y, byte _w, byte _h, char *_txt, void (* _Do)());
        void setup() {
        }
        // setup()
        void loop() {
        }
    };
    //-----Cl_Sys----------------------------------------------------------------
    class Cl_Sys {
        uint32_t past = 0;
      public:
        Cl_aJoystick *Start_aJoystick = NULL;
        Cl_Label     *Start_Label     = NULL;
        Cl_Btn       *Start_Btn       = NULL;
        Cl_Sys() {}
        // setup()
        void setup() {
          display.begin();              // Инициализация дисплея
          display.setContrast(60);      // Устанавливаем контраст
          display.setTextColor(BLACK);  // Устанавливаем цвет текста
          display.setTextSize(1);       // Устанавливаем размер текста
          display.clearDisplay();       // Очищаем дисплей
          display.display();
          for (Cl_aJoystick *i = Start_aJoystick; i != NULL; i = i->pnt) i->setup();
          for (Cl_Label     *i = Start_Label    ; i != NULL; i = i->pnt) i->setup();
          for (Cl_Btn       *i = Start_Btn      ; i != NULL; i = i->pnt) i->setup();
        }
        // loop()
        void loop() {
          for (Cl_aJoystick *i = Start_aJoystick; i != NULL; i = i->pnt) i->loop();
          for (Cl_Label     *i = Start_Label    ; i != NULL; i = i->pnt) i->loop();
          for (Cl_Btn       *i = Start_Btn      ; i != NULL; i = i->pnt) i->loop();
          // вывод обновленой информации раз в 0.5 сек
          if (millis() - past >= 100) {
            past = millis();
            display.clearDisplay();       // Очищаем дисплей
            // вывод Label
            for (Cl_Label *i = Start_Label; i != NULL; i = i->pnt) {
              display.setCursor(i->x + 2, i-> y + 2);
              display.print(i->txt);
              display.drawRect(i->x, i->y, i->w, i->h, BLACK);
            }
            // вывод Btn
            for (Cl_Btn *i = Start_Btn; i != NULL; i = i->pnt) {
              display.setCursor(i->x + 2, i-> y + 2);
              display.print(i->txt);
              display.drawRect(i->x, i->y, i->w, i->h, BLACK);
            }
            // вывод джойстика
            for (Cl_aJoystick *i = Start_aJoystick; i != NULL; i = i->pnt) {
              display.setCursor(i->x, i-> y);
              display.print(i->txt);
              display.display();
            }
          }
        }
        void onClick(byte onClickX, byte onClickY) {
          for (Cl_Btn *i = Start_Btn; i != NULL; i = i->pnt)
            if (i->x <= onClickX && onClickX < (i->x + i->w) && i->y <= onClickY && onClickY < (i->y + i->h))i->Do();
        }
    } Sys;
    //---------описание классов------------
    Cl_aJoystick::Cl_aJoystick(Cl_Sys *Sys, byte _1pin, byte _2pin, byte _3pin, void (* _Do_SW)(byte, byte))
      :                              VRx_pin(_1pin), VRy_pin(_2pin), SW_pin(_3pin), Do_SW(_Do_SW) {
      x = 0; y = 0; txt = "^";
      pnt = Sys->Start_aJoystick;
      Sys->Start_aJoystick = this;
    }
    Cl_Label::Cl_Label(Cl_Sys *Sys, byte _x, byte _y, byte _w, byte _h, char *_txt)
      :                                 x(_x), y(_y), w(_w), h(_h), txt(_txt) {
      pnt = Sys->Start_Label;
      Sys->Start_Label = this;
    }
    Cl_Btn::Cl_Btn(Cl_Sys *Sys, byte _x, byte _y, byte _w, byte _h, char *_txt, void (* _Do)())
      :                           x(_x),   y(_y),   w(_w),   h(_h),   txt(_txt) ,    Do(_Do) {
      pnt = Sys->Start_Btn;
      Sys->Start_Btn = this;
    }
    //----------Компоновка---------------------
    void Do_SW(byte onClickX, byte onClickY) {
      Sys.onClick(onClickX, onClickY);
    }
    Cl_aJoystick *aJoystick = new Cl_aJoystick(&Sys,/*VRx*/A0,/*VRy*/A1,/*SW*/A2,/*обработчик наж SW*/Do_SW); // создать aJoystick_1
    Cl_Label     *Label     = new Cl_Label    (&Sys,/*x*/0 ,/*y*/0 ,/*w*/48,/*h*/11,/*текст*/"Label 1"); // создать Label_1
    void Do_Btn1() {
      Label->txt = "Do_Btn1";
    }
    void Do_Btn2() {
      Label->txt = "Do_Btn2";
    }
    void Do_Btn3() {
      Label->txt = "Do_Btn3";
    }
    Cl_Btn  *Btnl = new Cl_Btn(&Sys,/*x*/0 ,/*y*/36,/*w*/27,/*h*/11,/*текст*/"Btn1",/*обработчик^\_*/Do_Btn1);// создать кнопку 1
    Cl_Btn  *Btn2 = new Cl_Btn(&Sys,/*x*/28,/*y*/36,/*w*/27,/*h*/11,/*текст*/"Btn2",/*обработчик^\_*/Do_Btn2);// создать кнопку 2
    Cl_Btn  *Btn3 = new Cl_Btn(&Sys,/*x*/56,/*y*/36,/*w*/27,/*h*/11,/*текст*/"Btn3",/*обработчик^\_*/Do_Btn3);// создать кнопку 3
    //-----------Main()-----------------------
    void setup() {
      Sys.setup();
    }

    void loop() {
      Sys.loop();
    }
     
  14. Hatski

    Hatski Нуб

    qwone когда я упрусь в "очередной потолок" я снова полезу в гугл))
    За очередную ссылку, очередное спасибо. Но не уверен, что буду все это читать.
    Опять вы решили блеснуть своими мега крутыми знаниями))
    Код еще тяжеловат для моего понимания. Некоторые функции мне не знаком (не искал, не читал, не вникал). Ну если будет нужна, буду изучать. И проверить на сколько он рабочий (увидеть его в действии) у меня не получится. Я использую дисплеи nextion. Нуб edition ))
    Я думал что форумы нужны, чтобы люди обменивались опытом, делились знаниями. А по вашей методики, на все вопросы можно просто отсылать изучать основы. Я рад что не вы ответили первым мне в этой ветке. А то мои знания про ваши УКАЗАТЕЛИ (без которых я не представляю как жил раньше) возможно так и остались бы на нуле.
    Продолжение разговора думаю можно, считать флудом.
    Еще раз СПАСИБО
    mcureenab
     
  15. Hatski

    Hatski Нуб

    Прошу меня простить, не увидел сразу. У меня завелась очень живая дискуссия с qwone )
    Этот вариант не сработал
    "call of overloaded 'print(char*, int)' is ambiguous"
     
    Последнее редактирование: 10 июн 2017
  16. qwone

    qwone Гик

    Код (C++):
    //результат
    //abcd
    //efgh
    //efghijklmnopqrstuw

    const char *buffer = "abcdefghijklmnopqrstuw";
    char M[10];
    char *str_copy(char *dataOUT, char *dataIN, byte start, byte len) {
      byte i, j;
      for (j = 0, i = start - 1; i < (len + start) && dataOUT[i] != 0 ; i++, j++)
        dataIN[j] = dataOUT[i];
     dataIN[j] = 0;
      return dataIN;
    }
    void setup() {
      Serial.begin(9600);
      Serial.println(str_copy(/*откуда*/buffer,/*куда*/M,/*начало*/1,/*длина*/3));
      Serial.println(str_copy(/*откуда*/buffer,/*куда*/M,/*начало*/5,/*длина*/3));
      Serial.println(str_copy(/*откуда*/buffer,/*куда*/M,/*начало*/5,/*длина*/100));
    }

    void loop() {


    }
     
  17. mcureenab

    mcureenab Гуру

    В функциях stdlib порядок аргументов обратный: destination, source.
    Параметр start в принципе избыточен. Достаточно заменить запятую на +.
    К сожалению функция не проверяет, что копируемый диапазон лежит внутри строки. Но функции stdlib тоже не безопасны.

    Код (C++):


    char *str_copy(char *destination, char * source, size_t length) {
      destination[length] = 0;
      memcpy(destination, source, length);
      return destination;
    }

      Serial.println(str_copy(M, buffer+1, 3));

     
     
  18. rkit

    rkit Гуру

    Ну write. Читайте документацию, серьезно. В сто раз быстрее было бы разобраться самостоятельно.
     
    Hatski нравится это.
  19. Hatski

    Hatski Нуб

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


    Если брать именно мой случай, то это не страшно. Так как мой (special for qwone) массив символов char, заведомо известен и не меняется по ходу работы кода.

    rkit Да да, вы правы. Я не посмотрел код, а в торопях просто вставил его и написал результат.
    И к слову "документация" гласит
    "Для того, чтобы передать данные как символы следует использовать другую функцию print()."
    Ваш вариант работает и он отличный. Минимум кода, хорошо и для МК и для моего понимания. Как раз этого я и пытался достичь, когда в качестве эксперимента написал t[0-2] ))
    Благодарю
     
  20. rkit

    rkit Гуру

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