Метод toCharArray, странности

Тема в разделе "Arduino & Shields", создана пользователем Ринат, 19 июл 2014.

  1. Ринат

    Ринат Нерд

    Добрый день!
    Необходимо строку преобразовать в массив

    data = "1234567890";
    char charBuf[69];
    data.toCharArray(charBuf, 11);
    Serial.println(charBuf)

    Странности с размерностью массива charBuf, если он меньше 69, начинают переодически появлятся левые символы и чем меньше размерность, тем хуже. При размерности 11 одни каракули вместо символов. Подскажите, почему так?
     
  2. Unixon

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

    Это Java (processing) или что?
     
  3. geher

    geher Гуру

    По всей видимости это фрагмент скетча.
     
  4. Unixon

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

    Тогда что в нем делают строки 1 и 3 и какого типа data?
    Видимо, это объект класса String. В таком случае понятно.
     
  5. Unixon

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

    Странно это, в реализации String::toCharArray() и String::getBytes() вроде бы никаких косяков нет.
     
  6. geher

    geher Гуру

    Возможно, где-то проблемы, которые приводят к "заползанию" на память, выделенную для charBuf[69].
    Увеличение размера строки создает некоторую защиту от этого, давая место для внедрения ошибочных символов.

    PS. Прерываний нет с записью больших объемов данных в локальные переменные функции прерываний?
     
    Последнее редактирование: 19 июл 2014
    Ринат нравится это.
  7. Ринат

    Ринат Нерд

    Извините, писал пост глубойкой ночью, потому так коряво объяснил...

    Вот переделанный скетч:

    #include <LiquidCrystal.h>
    void setup()
    {
    Serial.begin(9600);
    }
    void loop()
    {
    Serial.println(_Date());
    }
    char* _Date()
    {
    String data = "1234567890";
    char charBuf[11];
    data.toCharArray(charBuf, 11);
    Serial.println(charBuf);
    return charBuf;
    }

    А вот результат выполнения:

    1234567890
    K
    1234567890
    K
    1234567890
    K
    1234567890
    K
    ...

    Поскольку сам скетч маленький, заползание начинается с размерности 39 (при уменьшении начинают "съедаться" символы с конца). Понял что ошибка с указателем char* функции _Date, только почему?
     
  8. Megakoteyka

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

    Код (Text):
    char* _Date()
    {
      String data = "1234567890";
      char charBuf[11];
      data.toCharArray(charBuf, 11);
      Serial.println(charBuf);
      return charBuf;
    }
    Массив charBuf существует только внутри функции _Date, его нельзя возвращать. Передавайте его в функцию извне.
     
    Ринат нравится это.
  9. Ринат

    Ринат Нерд

    Поясню суть задачи. Необходимо получить дату с часов реального времени и привести ее к виду 19/07/2014 т.е. выполнить конкатенацию строки. Поскольку фукция вывода на экран у меня реализована в char, то и тут необходимо на выходе вернуть char. Код при конкатенации char получается больно уж массивный (у меня опыта маловато) поэтому использовал String с последующим преобразовании в char.

    // >>>>>>>>>>>>>>> функция возвращает отформатированную текущую дату
    char* _Date(){
    String date;
    clock.getTime(); //запрос данных с модуля часов
    if (clock.dayOfMonth < 10) date += "0";
    date += clock.dayOfMonth; //день
    date += "/";
    if (clock.month < 10) date += "0";
    date += clock.month; //месяц
    date += "/";
    date += clock.year+2000; //год
    char charBuf[69];
    date.toCharArray(charBuf, 11);
    return charBuf;
    }

    Может посоветуете более оптимальный способ решения моей задачи?
     
  10. geher

    geher Гуру

    Тогда все становится на свои места. Массив существует в стеке. Стек растет в обратную сторону. Чем больше строка, тем меньше вероятности, что программа испортит меняющимся содержимым стека массив.
    Чтобы этого не происходило, нужно объявлять массив в вызывающей функции и передавать параметром.
    Например, так:
    Код (Text):

    void setup()
    {
      Serial.begin(9600);
    }
    void loop()
    {
      char charBuf[11];
      Serial.println(_Date(charBuf,11));
    }
    char* _Date(char *charBuf,int cblen)
    {
      String data = "1234567890";
      data.toCharArray(charBuf, cblen);
      Serial.println(charBuf);
      return charBuf;
    }
     
    Ринат нравится это.
  11. Ринат

    Ринат Нерд

    А если так?
    Код (Text):

    void setup()
    {
    Serial.begin(9600);
    char charBuf[11];
    }
    void loop()
    {
    Serial.println(_Date());
    }
    char* _Date()
    {
    String data = "1234567890";
    data.toCharArray(charBuf, 11);
    Serial.println(charBuf);
    return charBuf;
    }
     
    Какой вариант будет работать оптимальнее?
     
  12. geher

    geher Гуру

    Это не должно даже компилироваться.
    charBuf будет виден только по месту объявления - в функции setup).
    Тогда уж лучше объявить переменную глобально, перед функцией setup.
     
  13. Ринат

    Ринат Нерд

    Объявил массив charBuf глобально, заработало, спасибо
     
  14. Ринат

    Ринат Нерд

    Ну да, промахнулся, хотел перед loop объявить. И все же, что оптимальнее?
     
  15. Unixon

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

    Функция, которая способна работать только с массивом на 11 байт, про что нигде не написано? Оригинально. :) Только так никто не делает.

    Вам geher правильно все написал, берите пример. Передавайте буфер в аргументах.
     
  16. Ринат

    Ринат Нерд

    Моя функция _Data всегда работает с массивом в 11 байт, не больше и не меньше. Так не лучше ли сразу зарезервировать за ней в памяти эти 11 байт? Или я что то недопонимаю?
     
  17. Unixon

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

    Ну это как будто была бы функция для работы со строками, но только если эти строки длиной в 11 символов. Сюрреализм полный.
     
  18. Unixon

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

    Не должно быть скрытых параметров в коде. Это очень плохой стиль.
     
    Ринат нравится это.
  19. Ринат

    Ринат Нерд

    Вот теперь понятно, спасибо.
     
  20. geher

    geher Гуру

    Тут есть два аспекта. Оптимальность (по размеру кода. по оперативной памяти, по быстродействию) и "правильность" кода, которая прежде всего обеспечивает удобство написания программы и ее последующего сопровождения (исправление ошибок, модернизация).
    Данные моменты несколько противоречат друг другу. а потому вроде как рекомендуется сначала писать "правильно", а потом уже оптимизировать под конкретный проект, сохраняя старый код для облегчения сопровождения.
    Если очень хочется функцию, которая работает только со строками длиной до 11 символов, то это надо хотя бы показать в названии.
    И для переменной charBuf объявить пользовательский тип, примерно так:
    typedef char string11[11];
    string11 charBuf;

    и в toCharArray передавать не просто константу 11, а sizeof(string11)

    Можно попробовать объявить charBuf локально в Data, как оно было раньше, только приделав модификатор static:
    static char charBuf[11];
    Но передача результатом локальной переменной (даже если она static) вроде как считается более "некрасивой", чем объявление глобальной переменной.
     
    Unixon и Ринат нравится это.