Почему char функция возвращает пустое значение?

Тема в разделе "Arduino & Shields", создана пользователем Suyano, 24 июл 2020.

  1. Suyano

    Suyano Нерд

    Добрый день!

    Код (C++):
    char inputData[25] = "Hello!!!";

    char* readData() {
      char* msg;
      sprintf(msg, "%s", inputData);
      return msg;
    }

    void setup() {
      Serial.begin(9600);
      Serial.println(readData());
    }

    void loop() {}
    Функция readData() вернет пустое значение вместо "Hello!!!"

    В чем причина и как сделать так, чтобы функция вернула ответ в виде char?
     
  2. b707

    b707 Гуру

    тут сразу не одна ошибка, а больше

    Во-первых, переменная msg - это только указатель на строку. а сама строка где? - ее нет, ее надо создать сначала
    Во-вторых, переменная msg - локальная для процедуры readData(). в основной программе ее не существует. Если вы так же попытаетесь вернуть из процедуры строчку типа массив char - у вас возникнет утечка памяти

    если вы только что задали вопрос - не стаьте отметку "Решено", это означает, очевидно, что вы уже нашли решение и помощь вам не нужна)
     
  3. Suyano

    Suyano Нерд

    Спасибо за ответ!

    Вопрос возможно глупый.
    "*" в данном случае (char* msg) - не указание ее размера?
    Я * разместил там взамен указания размера массива (вместо char msg[25]).

    При тег "Решено" проглядел название, хотел вставить "Вопрос", но его там не было)
     
    Последнее редактирование: 24 июл 2020
  4. Suyano

    Suyano Нерд

    Основная цель применения char функции - получить массив байтов из SPI и вернуть в виде char массива. Сейчас вопросы именно по реализации возврата char из функции.
     
  5. Asper Daffy

    Asper Daffy Иксперд

    И каков же в этом случае её размер? 1? 33? Или 100500?
     
  6. Suyano

    Suyano Нерд

    Я считал так, так как это компилировалось.
    Ошибка есть ошибка.

    Вот так работает, но здесь через void.
    Код (C++):
    char inputData[] = "Hello World!";
    char outputBuffer[25];

    void readData(char * data) {
      sprintf(data, "%s", inputData);
    }

    void setup()
    {
      Serial.begin(9600);
      readData(outputBuffer);
      Serial.println(outputBuffer);
    }

    void loop() {}
    По итогу это вызывается так:
    Код (C++):
    readData(outputBuffer);
    Хотел сделать так:
    Код (C++):
    char response = readData();
     
  7. b707

    b707 Гуру

    хотели - так сделайте. Кто мешает вам возвращать из этой функции указатель на data ?
     
  8. parovoZZ

    parovoZZ Гуру

    возвращать надо не переменную, а указатель на неё. А чтобы его вернуть, его необходимо создать в вызывающей функции (main(), loop() и подобных), в которой происходит вывод данных.
     
  9. SergeiL

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

    Разве? Не совсем понял.
     
  10. b707

    b707 Гуру

    имел в виду вернуть из процедуры указатель на локальный массив:
    Код (C++):
    char* readData() {
      char msg[15];
      sprintf(msg, "%s", inputData);
      return msg;
    }
     
  11. SergeiL

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

    А почему утечка будет.
    msg будет выделен на стеке, при выходе из функции стек будет освобожден.
    Данные останутся на том же месте, пока не будут перезаписаны.
     
    Andrey12 нравится это.
  12. parovoZZ

    parovoZZ Гуру

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

    b707 Гуру

    Ок, согласен.
    Я. правда, думал. что если на кусок стека есть неосвобожденный указатель - стек тоже не освобождается...
    Но это видимо у меня "аллюзии" из других языков :)
     
    Andrey12 нравится это.
  14. parovoZZ

    parovoZZ Гуру

    а стек откуда узнает, что на него где-то болтается указатель? В сях он вычистится весь. Без остатка. Работа с памятью на сях целиком и полностью на программисте.
     
  15. Asper Daffy

    Asper Daffy Иксперд

    Я рад, что скомпилировалось, но как "так" считал?

    Что
    Вот я и спрашиваю как считал - что это какой размер? 1? 33? Или 100500?
     
  16. parovoZZ

    parovoZZ Гуру

    я не понимаю, почему ты не понимаешь? Компилятор скомпилировал без видимых ошибок, значит всё правильно и он всё посчитал.
     
  17. Suyano

    Suyano Нерд

    Изначально я ставил * везде, где мне не был известен размер входящих данных в массив.
    Я считал, что это указание на более-менее безразмерный массив, куда можно вписать разумное количество байтов, изначально не зная их длину.

    Почему это укрепилось отсутствием ошибок компиляции?
    Так как при экспериментах вылетали ошибки типа "преобразования char* в char" или "const* char в char", у меня еще не было никакого представления об указателях. Чтобы устранить ошибки я начал вставлять * или наоборот.

    Спустя некоторое время это окончательно укрепилось в неверное утверждение.

    Именно по этому я здесь.
     
  18. SergeiL

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

    Ну указатели в Си тема интересная.
    Все путаются на первом этапе. И особенно в отношении массивов.
    Тут самое главное усвоить, что и как передается в функцию.

    Вот тут все понятно:
    Код (C++):
    char* readData() {
      char msg[15];
      sprintf(msg, "%s", inputData);
      return msg;
    }
    А тут??? ;):
    Код (C++):
    char* readData(char msg[15])
    {
      sprintf(msg, "%s", inputData);
      return msg;
    }
    Компилятор съест это без каких либо предупреждений. ;)
    Что будет передано в функцию?
    Что с памятью?
     
    Suyano нравится это.
  19. Suyano

    Suyano Нерд

    Последний вариант работает:

    Код (C++):
    char inputData[25] = "Hello World!";

    char* readData(char msg[15])
    {
      sprintf(msg, "%s", inputData);
      return msg;
    }

    void setup() {
      Serial.begin(9600);
      char msg[25];
      char* output = readData(msg);
      Serial.println(output);
    }
    void loop() {}
     
    Но для этого создано две переменных.

    При попытке сделать так:
    Код (C++):
      Было - char* output = readData(msg);
      Стало -  char* output = readData(output);
    На выходе пустота.

    Возможно этот вариант более эффективный и распространенный?

    Код (C++):
    char inputData[25] = "Hello World!";

    void readData(char * output) {
      sprintf(output, "%s", inputData);
    }

    void setup() {
      Serial.begin(9600);
      char output[25];
      readData(output);
      Serial.println(output);
    }
    void loop() {}
     
    SergeiL нравится это.
  20. SergeiL

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

    Нет, так:
    Код (C++):
    char* readData(char msg[15])
    делать не нужно, я просто написал, что компилятор съест.
    Последний вариант - правильный.
    Но учтите, что переменные output в setup и readData - это две разные переменные.
     
    Andrey12 нравится это.