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

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

Метки:
  1. mcureenab

    mcureenab Гуру

    Неправильные программы иногда работают.
     
  2. mcureenab

    mcureenab Гуру

    сделал функцию Serial_write которая работает со строками в программной памяти

    Код (C++):

    #define FP(string_pointer) reinterpret_cast<const __FlashStringHelper *>(string_pointer)

    void Serial_write(const __FlashStringHelper * str_, int len) // такого варианта Serial.write нет.
    {
      const char *str1_ = reinterpret_cast<const char *>(str_);
      for ( int i = 0 ; i < len; ++i, ++str1_)
      {
        Serial.write(pgm_read_byte_near(str1_));
      }
    }

    const char a[] PROGMEM = "Message"; // Размер объекта 7 + 1 char.

    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      while(!Serial){};
      Serial.println(F("Start..."));
    }

    void loop() {
      // put your main code here, to run repeatedly:
    // буфер для строки должен быть достаочного размера.
    // инициализировать его не надо
      char b[4]; // 3 char под размер строки + 1 под терминирующий 0.
      memcpy_P(b, a+ 3, 3);
      b[3] = 0; // четвертый char. терминирующий 0.
      if(!Serial)
      {
        while(!Serial){};
        Serial.println(F("Restart..."));
      }
      Serial.print  (F("b="));
      Serial.println(b);
      Serial.print  (F("a="));
      Serial_write(FP(a+3), 3);
      Serial.write('\n');
      delay(1000);
    }

     
    Restart...
    b=sag
    a=sag
    b=sag
    a=sag
    b=sag
    a=sag
    b=sag
    a=sag
    b=sag
    a=sag
    b=sag
    a=sag
    b=sag
    a=sag
    b=sag
    a=sag
    b=sag
    a=sag
     
    Последнее редактирование: 12 июн 2017
    Hatski нравится это.
  3. Hatski

    Hatski Нуб

    Как смог написать, так и работают. Я тут только недавно про существования указателей узнал, которые изменили мою жизнь, а вы теперь меня еще и memcpy "грузите" ))
    О благодарю! Мне будет интересно поразбирать этот код (паралельно читая инфу), чтобы точно понять как эта функция работает
     
  4. Unixon

    Unixon Оракул Модератор

    p.s. AFAIK, s* и s[] - это эквивалентные определения указателя. С каким нельзя адресную арифметику делать?
     
  5. mcureenab

    mcureenab Гуру

    PROGMEM это не для слабонервных )))
    Компилятор сам не различает где находится объект - в оперативной памяти или в программной памяти. Это все равно как 31 декабря ехать из аэропорта на улицу Строителей, не уточняя в каком городе это.

    Обычное разыменовывание указателя ptr - звездочкой ( *ptr ), возвращает объект в оперативной памяти.
    Разыменовывание указателя ptr через pgm_read_byte_near возвращает объект ( byte ) в программной памяти.
     
  6. Hatski

    Hatski Нуб

    Unixon рискну предположить, что нельзя делать адресную арифметику с s[].

    mcureenab заинтриговали, значит придется голову поломать. Мне и так приходится раза со второго-третьего вьезжать в то, что вы пишите))
     
  7. mcureenab

    mcureenab Гуру

    Всё можно. Всюду, где можно воткнуть указатель, можно воткнуть массив.

    С другой стороны такая гибкость выходит боком там, где это не надо.

    Код (C++):

    int a,b;

    int *ptr = &a; // теперь ptr -> a.

    *ptr = 0; // Ok. a = 0.
    ptr[0] = 1; // Ok. a = 1.
    ptr[1] = 2; // Error. Неопределенное поведение. Может быть b = 2 , а может быть испорчен другой объект.

     
     
  8. Unixon

    Unixon Оракул Модератор

    Если объявляется статический массив, тогда переменная не будет указателем, это верно.
    Динамический массив можно объявлять и так и ... а да, вы правы, я тут немного в дезинформацию ударился, динамический массив через [] не объявляется.
     
  9. Hatski

    Hatski Нуб

    mcureenab опять же рискну предположить, что
    Код (C++):
    ptr[1] = 2; // Error. Неопределенное поведение. Может быть b = 2 , а может быть испорчен другой объект.
    Потому, что нужно различать константный указатель и указатель на константу.
    Указатель на константу - нельзя менять содержимое объекта, на который указывает указатель, но можно менять содержимое самого указателя (указатель — это переменная, содержащая адрес другой переменной).
    Константный указатель - можно менять содержимое объекта, но нельзя менять значение самого указателя. Проще говоря, указатель нельзя переназначить на другой объект, но сам указатель поменять можно.

    Возможно я ошибаюсь и это из другой оперы
     
  10. mcureenab

    mcureenab Гуру

    s[] не может быть lvalue. s это адрес статического или автоматического массива, его первого элемента

    s = &(s[0]).

    но s[1] и *(s+1) это одно и то же.
     
  11. mcureenab

    mcureenab Гуру

    Из другой.

    Код (C++):


    int a(13), b(25), c;
    const int * prt = &a;
    c = *ptr; // Ok. c == 13
    c = prt[0]; // Ok. c == 13
    c = prt[1]; // Error. c == неопределенное значение
    ptr[0] = 34; // Error. нельзя менять значение константы
    prt = &b; // Ok. Сам указатель не константа
    c = prt[0]; // Ok. c == 25

     
     
  12. qwone

    qwone Гик

    Код (C++):
    const int *a;/* указатель показывает на переменую которую нельзя менять*/
    int * const b;/* неменяющий указатель показывает на переменую которую можно менять*/
    const int * const d;/* ничего нельзя поменять, ни указатель ни переменную*/
     
  13. Unixon

    Unixon Оракул Модератор

    Да это я знаю, просто запамятовал, существует ли конструкция, когда s[] может быть lvalue при инициализации динамического массива. Освежил память - таки нет, это только для статических массивов.

    см. http://www.cplusplus.com/doc/tutorial/ntcs/
    http://www.cplusplus.com/doc/tutorial/dynamic/

    При объявлении char s[] = "mystring"; будет создан статический массив, при объявлении char *s = "mystring"; указатель на настоящий массив где-то еще в памяти. Почему-то мне показалось, что вполне законным будет синтаксис <typename> s[] = new ... наряду с <typename> *s = new ... , но в стандарте это не так.
     
  14. mcureenab

    mcureenab Гуру

    Стоит заметит, что
    type s [] PROGMEM = {... массив .};
    Помещает массив в программную память.
    А
    type *s PROGMEM = { массив };
    Помещает в программную память только сам указатель.