Официальный сайт компании Arduino по адресу arduino.cc
Результат функции строка.
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Здравствуйте. Мне нужна функция, результат которой пойдет в другую, а точнее в метод
lcd.print(myFunc());
Хотелось бы максимально быструю и не затратную. Сам я сделал так:
void setup() { Serial.begin(9600); while (!Serial); float t = 49.37; //-99,99..99,99; Serial.print(">>>Result: >"); Serial.print(myStr(&t)); Serial.println("<"); } String myStr(float* x) { char str[6] = {0, 0, 0, 0, 0, 0}; dtostrf(*x, 1, 1, str); for (byte n = 0; n < 6; n++) { if (str[n] == 0) { if (n == 5) { str[n] = 0x43; } else { str[n] = 0x20; str[n + 1] = 0x43; break; } } } return str; } void loop() { }
Тут не на дисплей, а в сериал идет отправка но это не суть пока.
Она работает, но так как я в си не очень силен, хотелось бы услышать как можно ее(myStr) улучшить.
Или может вообще другой вариант предложите?
Что нужно. В функцию передается float параметр (я, если я правильно сделал, передаю параметр по ссылке) В функции просто этот параметр конвертируем в строку, после точки оставляем 1 знак и потом если есть место(результат шесть символов) то добавить проел и символ "С" или без пробела (например "99,9 С" или "-99.9С")
Я пошел на одно "преступление" в функции dtostrf вторым параметром нужно по идее передавать '6', а я передаю '1'. Если передавать 6 - то строка выравнивается по правой стороне. И что бы вставить "С" получится не так просто.
Я попробовал с sprintf, но что-то у меня с ним не получилось
А зачем все так сложно?
А зачем все так сложно?
А как проще сделать?
В общем когда передал на дисплей, то появились артефакты :( В сериал нормально уходило...
Подозреваю, что терминальный ноль затираю когда мудрю с str
PS Так и есть исправил так:
т.е. просто седьмым символом добавил 0
Я пошел на одно "преступление" в функции dtostrf вторым параметром нужно по идее передавать '6', а я передаю '1'. Если передавать 6 - то строка выравнивается по правой стороне.
Если нужно выравнивание влево, передавайте -6 и не надо никаких преступлений :-)
Ну, цикл в строке 12, конечно, не нужен. Там все через strend делается (или через strlen). Попробуйте, если не получится, я после хоккея посмотрю.
С выравниванием, да получилось, но strlen вернет размер массива т.е. в моем случае 7. Но мне это не нужно я и без strlen'а знал длину массива :)
А по strend вообще ничего не нашел :( Если я правильно понял, то она должна была вернуть индекс в массиве char с последним значащим символом... Получается цикл все равно нужен(
хотелось бы услышать как можно ее(myStr) улучшить.
для начала стоило бы исправить несоответвие - функция описано с возвращаемым типом String. а на самом деле отдаете char* - непорядок
strlen вернет размер массива т.е. в моем случае 7. Но мне это не нужно я и без strlen'а знал длину массива :)
Да, неужели? Это Вам кто сказал? Вас обманули. Почитайте её описание и попробуйте сделать.
Ваши двенадцать строк (с 12-ой по 23-ю) заменяются на две строки, если делать правильно и на одну, если хочется выпендриться и уложиться в одну.
Попробуйте, а если не получится, я покажу.
strlen вернет размер массива т.е. в моем случае 7. Но мне это не нужно я и без strlen'а знал длину массива :)
Да, неужели? Это Вам кто сказал? Вас обманули. Почитайте её описание и попробуйте сделать.
Хм... Странно, в описании действительно должна вернуть длину строки, но у меня код :
Возвращает:
для начала стоило бы исправить несоответвие - функция описано с возвращаемым типом String. а на самом деле отдаете char* - непорядок
Да я думал об этом, но пока моих знаний не хватает избавится от String...
а результат функции массив:
char myStr[7] (float* x) с ходу не получается. Я подозреваю, что нужно свой тип создавать и результат функции уже его...
Возвращает:
А кто будет за вас присваивать начальное значение массиву str[7] ?
Ну даже если расскоментировать
char
str[7];
// = {0, 0, 0, 0, 0, 0};
все равно одинаково результат. Или даже если пробелами забить
char str[7] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
все равно 7 показывает
AsNik,
Вы, похоже, не знаете что такое длина строки. Она же (строка) у Вас пробелами заполнена (а во втором случае, так одними пробелами - char str[7] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20};). А пробел - это такой же символ, как и все остальные - ничем не хуже других, также считается, как и любая буква. Длина строки считается до символа '\0' - именно он является признаком конца строки. А пробелы - это обычные символы.
Так что Вам нужно либо искать пробел, либо делать так, чтоб dtostrf не расширяла строку пробелами. Последнее Вы знаете как делать.
Попробуйте, а если не получится, я покажу.
Так то думаю должно что-то типа такого получится:
str[strlen(str)]=0x20; str[strlen(str)+1]=0x43;
И все равно нужно проверить нужен пробел или нет. Так что одной-двумя строками не получится...
Последнее Вы знаете как делать.
В dtostrf указать длину 1?
А пока пробуйте. Только не так, как Вы написали (прочитайте моё сообщение про конец строки - Вы в своём решении его стёрли, а нового не поставили :-(
AsNik,
Вы, похоже, не знаете что такое длина строки. Она же (строка) у Вас пробелами заполнена (а во втором случае, так одними пробелами - char str[7] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20};). А пробел - это такой же символ, как и все остальные - ничем не хуже других, также считается, как и любая буква. Длина строки считается до символа '\0' - именно он является признаком конца строки. А пробелы - это обычные символы.
Так что Вам нужно либо искать пробел, либо делать так, чтоб dtostrf не расширяла строку пробелами. Последнее Вы знаете как делать.
Да, не я в курсе про символы и терминальный ноль.
'\0' - а это разве не два символа?. Но и такая инициализация char str[7] = {'\0', '\0', '\0', '\0', '\0', '\0'};
Возвращает 7 :(
В общем я немного запутался... :( Буду думать почему после dtostrf в строке нет терминального ноля
В dtostrf указать длину 1?
А Вы описание dtostrf читали? Судя по всему, нет. Что вообще означает второй параметр?
Я Вам говорю, разбирайтесь и пробуйте. Выкладывайте свой код и результат. Посмотрим.
'\0' - а это разве не два символа?
Вы не поверите, но даже '\377' - это ОДИН символ :-)
Но и такая инициализация char str[7] = {'\0', '\0', '\0', '\0', '\0', '\0'};
Возвращает 7 :(
А вот это уже, как говаривал Бегемот, - "типичный случай так-называемого вранья" :(
Запускаем и смотрим
У меня печатается ноль. У Вас тоже :-)
В dtostrf указать длину 1?
А Вы описание dtostrf читали?
Ну так-то читал... У меня с англ проблема. Пользуюсь переводчиками...
Но я читал в разных местах и русские варианты. И вот в некоторых местах пишут, что второй параметр это кол-во символов до точки, а в других общая длина строки.
Вот по Вашей ссылке - это минимальная длина строки.
Она делает буфер указанной длины, а за ним ставит ноль, разумеется.
т.е. он с моим объявлением str[7] и вторым параметром dtostrf -7 делает его за пределами моей переменной?
В общем я теперь не пойму для чего второй параметр dtostrf
Сейчас возвращает как и положено - 3. Буду разбираться со вторым параметром, ну а потом уже свою функцию допилю. Спасибо
ЗЫ Если я правильно понял, то второй параметр dtostrf нужен для выравнивания строки и не более. В моем случае можно смело указывать 1. Или я вообще не понял :(
т.е. он с моим объявлением str[7] и вторым параметром dtostrf -7 делает его за пределами моей переменной?
Таки да. И испортит соседнюю переменную, если она там есть.
Вот, запустите этот пример и полюбуйтесь, что происходит с переменной duck
В общем я теперь не пойму для чего второй параметр dtostrf
Он задаёт МИНИМАЛЬНУЮ длину строки.
Вот Вы печатает отчет. Числа должны быть друг под другом. А как сделать друг под другом 3 и 100500? Очень просто, сказать что минимальная длина 7 и она Вам выдаст " 3" и " 100500" - при печати они будут друг под другом по правому краю
минимальная длина 7 и она Вам выдаст " 3" и " 100500" - при печати они будут друг под другом по правому краю
Это я уже понял. при -7 она забьет пробелами до 7 справа т.е. строка получится "3 "
Но что значит:
Он задаёт МИНИМАЛЬНУЮ длину строки.
[/quote]
Вот тут я туплю :( Если я указываю в моем случае 6 (это максимальная длинна моей строки) то strlen всегда вернет 6. Если укажу 1, то strlen возвращает как положено, но после манипуляций с добавлением пробела и "С" после С может еще какой-то мусор появится.... В общем сижу, разбираюсь.... Боюсь как бы моя ардуина не задымила раньше меня)
ЗЫЖ Вот например:
Вроде за рамки не выхожу..
Вот этот вариант правильно все делает, но:
Н-да. Вот так вот я избавился от цикла, но строк кода меньше не стало(
И еще, я всеж учту замечание от b707 и попробую потом избавится от String. И вот теперь задумался, может сначала вопрос с String решить, а потом оптимизировать.... Но подскажите, что нужно что бы от стринга избавится
Вот тут я туплю :(
Бывает.
Вот откуда эта I появилась?
Вы затёрли ноль, который там был, а новый кто за Вас прописывать будет?
Блин, движок форума тут ужасный... Сейчас набирал текст, и что-то случилось и текст потерялся :(
Но вот еще раз, хоть уже и ответили, но я сам до этого додумался.
Когда я указал вторым параметром в dtostrf 1 то после нее моя строка стала 9.0 и терминальный ноль. Причем в конце еще один. После первого ноля в переменной был мусор. И когда я вставлял пробел с C я затирал первый терминальный ноль и мусор автомато добавлялся в мою переменную. Ну, я до этого более подробно расписал, но.... ужасный движок(
кто за Вас прописывать будет?
в #26 сделал)
Ну, а где вариант в две строки после dtostrf? Зачем Вы там циклов развели?
После вызова dtistrf всё остальное делается в одну - две строки. Всё, что свыше - неоправданное усложнение и вынос самому себе мозга.
Циклов там на самом деле нет, касаемо самой функции.
Циклы там для отладки в сериал...
Ну так-то там в один оператор if после dtostrf ну если не считать временную переменную n.
Согласен, строк получилось 6 :( Но я со своими знаниями лучше не соображу :(
ЗЫЖ Мне еще важен конечный результат. Так как на lcd уже места отведены. Поэтому и пробел убираю, когда "-99.9С" в других случаях добавляю "9.9 С"
Да там соображать-то нечего, держите и разбирайтесь! Запустите, проверьте, кстати.
Ё, моё.... Спасибо.
Реально все просто, но я бы долго до этого доходил... :(
Я эту конструкцию ? : знаю, но почему то ей не пользуюсь. Но тут даже не в ней дело, а в объединении строк (strcat)
Я даже и не думал об этом. Ох... стар я наверное для программирования)
Запустите, проверьте, кстати.
Немного подправил:
Работает четко. ПодскАжите как от String'а избавится или это лучше не сделает?
1. Нафига вернули указатель? Вы ничего этим не выиграли, а время выполнения увеличилось. Зачем?
2. Я уже писал выше. что в одну строку можно, но это выпендрёж. Лучше добавить ещё одну строку, но работать будет вдвое быстрее. Вот так.
Дело в том, что и strlen, и strcat требуют прохода вдоль всей строки. А в таком варианте проход всего один - в strlen.
(хотя, если уж выпендриваться, то можно и такой вариант в одну строку упихать, примерно так)
По поводу String, для этого принимающий буфер нужно хранить в вызывающей функции. Попробуйте
1. Нафига вернули указатель?
Я думал что наоборот так быстрее будет. Т.е. не будет копироваться переменная в функцию, а передастся сама
Ну я очень давно писал на делфях. И там были переменные var и const ну и просто типа так:
function Fu (const a: byte; var b: integer; c: float): PChar;
begin
end;
так вот там было так, что переменные a и b не копировались а передавались по ссылке. Отличие a - можно изменить в функции и она изменится там где вызывали эту функцию а b тоже самое, только меня ее нельзя, а вот с: float - будет передана копия этой переменной в функцию.
Я думал и тут так же(
По поводу String, для этого принимающий буфер нужно хранить в вызывающей функции. Попробуйте
Не, мне так не пойдет. Я расчитывал на результат функции. Т.е. ее передаю в lcd.print(MyFunc());
Нашел такой пример:
char * MyFunc() {
char ch[6]="hello";
return ch; }
Но в моем случае не смог ее прикрутить (
А если честно, меня пугают эти * &. Я наверное никогда не запомню для чего они.
Они то спереди ставятся, то сзади, то посередине, то к переменной, то к типу.... мой мозг взрывается когда я с ними что-то делаю. И если Вы говорите убрать эту * и будет даже быстрее, то для меня это даже камень с плеч.
(хотя, если уж выпендриваться, то можно и такой вариант в одну строку упихать, примерно так)
У меня не та цель, что бы было как можно меньше строк. А чтоб код был оптимальным, быстрым и в тоже время понятным.
А вообще я восхищаюсь, когда вижу такие вещи, кода я делаю 1000 строк, оптимизировав вроде до нехочу , а кто-то берет и эту тыщу впихивает в десяток строк. Круто.
Почитал я про передачу параметров по указателю и по ссылке
Т.е. как у меня - это по указателю. По ссылке будет так:
String myStr(float &x) {
dtostrf(x, 1, 1, str);
}
Ну и вызов уже не lcd.print(myStr(&gg)); а просто как обычно lcd.print(myStr(gg));
Не совсем понимаю разницу, кроме визуальной в коде. В принципе это же одно и тоже. Так же передается не сама переменная а указатель на нее? И в чем тогда разница по указателю или по ссылке? Если и там и там передается адрес а не значение....
Я думал что наоборот так быстрее будет. Т.е. не будет копироваться переменная в функцию
Длина переменой типа float в данной платформе - 2 байта, длина указателя - тоже два байта. И что в таком случае Вы сэкономили? А вот хуже Вы сделали - Вы запретили компилятору располагать Вашу переменную в регистрах, т.к. у регистра нет адреса, поэтому если на переменную нужен указатель, она обязана быть в памяти.
там были переменные var и const
Кстати, const и у нас не помешает. Лучше написать заголовок функции как "
String myStr (
const float
x) {
"По поводу String, для этого принимающий буфер нужно хранить в вызывающей функции. Попробуйте
Не, мне так не пойдет. Я расчитывал на результат функции. Т.е. ее передаю в lcd.print(MyFunc());
Кто ей мешает получать адрес буфера параметром и этот же адрес возвращать? Тогда всё будет как надо.
Нашел такой пример:
char * MyFunc() {
char ch[6]="hello";
return ch;
}
Запомните, где взяли этот пример (автора) и впредь ни строчки оттуда не берите. Уровень безграмотности автора - примерно первая неделя изучения языка, не более. Здесь ошибка за которую бьют по рукам студентов - первокурсников (и школьников там, где преподают программирование). Переменная ch существует только внутри функции. После выхода её уже нет и занимаемая ею память свободна. Если до того, как Вы используете результат никто ничего туда не пропишет, то может показаться, что всё работает. Но потом, любое изменения в программе, кто-то загадит эту память и всё - приплыли.
В том, что можно с этим параметром делать. Указатель - честная переменная, его можно менять и он начнёт указывать на что-то другое. Ссылка намертво привязана и с ней ничего делать нельзя.
Длина переменой типа float в данной платформе - 2 байта, длина указателя - тоже два байта.
Четыре вроде:
Результат:
Кстати, const и у нас не помешает. Лучше написать заголовок функции как "
String myStr (
const float
x) {
"В том, что можно с этим параметром делать. Указатель - честная переменная, его можно менять и он начнёт указывать на что-то другое. Ссылка намертво привязана и с ней ничего делать нельзя.
Запомните, где взяли этот пример (автора) и впредь ни строчки оттуда не берите. .... Переменная ch существует только внутри функции.
Так то, да. Про жизнь переменных я в курсе. Они живы только в том месте, где они описаны. Я еще удивился, что в результате
char * MyFunc() {
char ch[6]="hello";
return ch;
}
возвращают локальный массив а он (массивы - не данные, а указатель на первый байт в памяти) вроде как в свою очередь просто указатель возвращает, но меня притормозило использование звездочки да и малознание си.... Но я сильно и не удивился, когда данный метод мне выдал мусор в результате...
Кто ей мешает получать адрес буфера параметром и этот же адрес возвращать? Тогда всё будет как надо.
т.е. примерно как в плохом коде выше char * MyFunc() { только внутри выделить память под результат.... new()? или как-то подобно... тут наверное malloc
И вопрос, если я выделю память в myStr сделав вызов lcd.print(myStr()); то кто ее освободит потом?
Если Вам не сложно, напишите. Я так-то разберусь, но потрачу уйму времени. Но обидно не это, а то что "завтра" я снова забуду это все. :(
т.е. примерно как в плохом коде выше char * MyFunc() { только внутри выделить память под результат....
вроде пишете выше, что "понимаете жизнь переменных" - и снова хотите выделить память внутри?? Посмотрите, что вам пишет Евгений - создать массив снаружи и в функцию передать на него ссылку
вооот! правильный вопрос. Поэтому и не нужно так делать
Если Вам не сложно, напишите. Я так-то разберусь, но потрачу уйму времени. Но обидно не это, а то что "завтра" я снова забуду это все. :(
если кто-то другой напишет - забудете еще быстрее. Поэтому старайтесь разобраться сами.
А то что забудете - это абсолютно естесственный процесс. Чтобы это надежно запомнить - вам нужно пройти процесс изучения не один раз, а три или пять... Не переживайте, у большинсва людей все так же. Тех, кто все запоминает с первого раза - единицы.
Понятно. Спасибо. Вот читаю статью ЕвгенияП очень хорошо написано, понятно... Но у меня в голове какой-то крах становится :(
Более того уже думаю, что все то, что уже написал возможно вообще не оптимально.... жуть.
Но все таки надеюсь, что это только если работать с памятью напрямую.... И так как в основном по моему коду я с памятью напрямую не работаю, то может и не все так плохо у меня. Решил пока не нырять сильно глубоко в си. Оставлю стринг...
Статью еще читаю... по несколько раз некоторые места. Тяжко для меня это дается(
Этот проект оставлю как есть, а дальше буду по возможности применять знания вновь полученные.... если не забуду)
На самом деле я не программист по специальности. Программирование - это мое хоби в молодости. Вот решил вспомнить, потому как хобби все равно осталось, но появились МК - и это еще больше нравится, чем писать для ПК.
А вообще скажу честно, я пользуюсь такой схемой. Отлажу какой-то момент, алгоритм или принцип в каком-то проекте. И потом я просто помню, что в таком-то проекте я это делал. И если мне где это нужно потом, то я не помню как я это делал, но помню где и оттуда беру как шаблон.
Поэтому я стараюсь доводить некоторые моменты до "совершенства". Но если не получается, то я даже и не запоминаю это для следующего шаблона. И потом если нужно, то буду опять с нуля решать данный вопрос. Получится - запомню как шаблон, нет - ну сделаю как получится) Все что я делаю - это для себя. Так что криминального тут ничего нет и никого я таким образом не обижу.
Результат:
Size var: 4
Size pointer: 2
или я мимо?
Нет, это я мимо - забыл, что там 4. Но всё равно, это ничего не меняет, делайте параметр const float и не выпендривайтесь.
только внутри выделить память под результат.... new()?
Память под результат нужно иметь снаружи, а не внутри. Посмотрите на dtostrf - Вы же резервируете память под результат снаружи и ей передаёте указатель. Так же и свою функцию делайте.
Писать не буду - это медвежья услуга. Вам это важно самому написать, я то умею.
делайте параметр const float и не выпендривайтесь.
Да я не выпендриваюсь, просто хочу разобраться.
Писать не буду - это медвежья услуга. Вам это важно самому написать, я то умею.
Память под результат нужно иметь снаружи, а не внутри. Посмотрите на dtostrf
За подсказку огромное спасибо.
Если я правильно понял, то должно быть примерно так (рядом ардуины сейчас нет, ели что за синтаксис прошу прощение):
char * myStr(const float x, char *_str) {
}
ну и вызов так:
void myfunc () {
char str[7];
float f = 9.99;
lcd.print(myStr(f, str));
}
Чуть позже смогу проверить на ардуине... На верном я хоть пути?
Если я правильно понял, то должно быть примерно так (рядом ардуины сейчас нет, ели что за синтаксис прошу прощение):
ну и вызов так:
Чуть позже смогу проверить на ардуине... На верном я хоть пути?
нифига не понял, зачем вызов отдельной процедурой? Откуда в этой процедуре возьмется float f ?
По-моему, вас опять что-то не туда понесло
Ну, примерно так.
Ок. Тогда как доберусь до ардуины буду рыть в эту сторону... И почитывать Ваши этюды;)
нифига не понял, зачем вызов отдельной процедурой? Откуда в этой процедуре возьмется float f ?
По-моему, вас опять что-то не туда понесло
На самом деле код в #45 - это для теста и по большей части что бы не потерять пришедшую мысль. Я его даже проверить не смогу, пока не доберусь до ардуины. А вообще это будет примерно так. У меня есть несколько переменных. И есть вывод этих значений на дисплей. И что бы это сделать, как бы правильнее сказать, по универсальнее решил сделать через функцию, которая сформатирует строчку для экрана.
вместо lcd.print(x, 1); lcd.print(" C"); А еще нужно так же, только без пробела перед С....
Я не думаю, что меня понесло в другую сторону. Хотя все может быть :(
(Ой, сейчас в меня полетят помидоры :))
но при компиляции вылезли варнинги по возврату строковых констант. Правильно ли я их привел к PChar'у?