Возвращение Си-строки Функцией
- Войдите на сайт для отправки комментариев
Чт, 11/08/2022 - 03:28
Доброго дня, есть простая задача : в одной из локальных функций нужно формировать си-строку (массив char) из комбинации префикса и номера элемента.
Сделал такой код, который работает:
char pref[]="ledbtn_"; //префикс, numbutton - глобальная=5 int sz=sizeof(numbutton)*(sizeof (pref)+sizeof(numbutton)); //рассчитываем размер итоговой строки char string[sz]=""; for (int i=0; i<numbutton; ++i){ char num[sizeof(numbutton)]; itoa(i,num,DEC); strcat(string,pref); strcat(string,num); if(i<numbutton-1){ //после последнего элемента запятая не нужна strcat(string,","); } } Serial.println(string); // вывод: ledbtn_0,ledbtn_1,ledbtn_2,ledbtn_3,ledbtn_4
Но когда я пытаюсь вынести этот кусок в отдельную функцию - ничего не получается. постоянно жалуется на "invalid conversion from 'char' to 'const char*' "
Идея сделать так:
//вызов функции char pref[]="ledbtn_"; char string[]=CharStrPrefixNum(numbutton, pref); char CharStrPrefixNum(int imax, char *prefix){ int sz=sizeof(imax)*(sizeof (prefix)+sizeof(imax)); char string[sz]=""; for (int i=0; i<imax; ++i){ char num[sizeof(imax)]; itoa(i,num,DEC); strcat(string,prefix); strcat(string,num); if(i<imax-1){ strcat(string,","); } } // Serial.println(string); return string; }
пробовал ставить звездочки, но я тему указателей слабо понимаю, почти наугад, не хотелось бы потом огрести с дебагом.. вот такой вариант компилится, но при запуске крашится и уходит в перезагрузку.
const char *str=CharStrPrefixNum(numbutton, pref); char* CharStrPrefixNum (int imax, char *prefix){ int sz=sizeof(imax)*(sizeof (prefix)+sizeof(imax)); char string[sz]=""; Serial.println(sizeof(string)); for (int i=0; i<imax; ++i){ char num[sizeof(imax)]; itoa(i,num,DEC); strcat(string,prefix); strcat(string,num); if(i<imax-1){ strcat(string,","); } } Serial.println(string); return string; }
Как правильно делать в данном случае?
Изучить тему указателей, чтобы не работать наугад?
Изучить тему указателей, чтобы не работать наугад?
слишком сложная тема чтобы её полностью изучить. Я гуглил темы "как передавать массив из функции" - но путного особо ничего не нашел. Либо предлагают применять malloc() - а это ведет к фрагментации памяти и сложно отлавливаемым багам - лучше этими функицями не пользоваться в принципе. темболее, что не зная размер массива который я получу от функции, я не смогу очистить память.
Либо управление внешней переменной через указатель. да, это работает, но тогда нужно задавать размер итогового массива вне функции - а он может менятся каждый раз, функция для того и нужна, чтобы не писать эту строку каждый раз.
слишком сложная тема чтобы её полностью изучить
Тогда программирование это не твое и тебе нужно писать ТЗ в платный раздел.
я резиновые данные возвращал через стек (но я не настоящий сталевар)
В весь код не вникал, но как минимум обьявляемая строка в функции должна быть static и её размер должен быть фиксированный.
И const на char не может быть т к переменная меняется.
слишком сложная тема чтобы её полностью изучить.
не пугайтесь, не такая и сложная. Указатель - это адрес переменной в памяти, вот и все :)
а других вариантов, собственно, и нет. Либо заранее выделяете кусок памяти с запасом, чтобы в него вошла любая из используемых строк, либо пользуетесь malloc. Беспокоится о размере массива в случае очистки не надо, это один из немногих примеров в С++, когда система действует автоматически.
В WinAPI раньше (да и сейчас, наерно, особенно в функциях IOCTL) была распространена такая практика. Когда размер отдаваемой структуры был заранее не известен, функцию вызывали 2 раза, первый раз передавали вместо структуры NULL, тогда она отдавала размер который необходим для размещения структуры. Второй раз, когда известно какой будет размер отданной структуры, под нее хапалась память, функции передавался указатель на нее, и она её радостно заполняла требуемымми байтиками. За распределение/освобождение памяти отвечала вызывающая программа. Ты не в сказку попал, а в Си вляпался.
В строке 4 последнего скетча написано что-то невразумительное. Например, "
sizeof
(prefix)
" на 8-битной ардуине ВСЕГДА (от слова "совсем всегда") равно 2. Вы этого хотели? Боюсь, что нетТы не в сказку попал, а в Си вляпался.
я жеж и говорю, лживый ваш С )))
Ты не в сказку попал, а в Си вляпался.
я жеж и говорю, лживый ваш С )))
Не лживый, а черезчур развязный )))
я жеж и говорю, лживый ваш С )))
лживый как раз не Си, а С++. В нем никогда нельзя сказать точно, что сегодня с утра значит оператор присваивания, а в Си - можно.
я жеж и говорю, лживый ваш С )))
лживый как раз не Си, а С++. В нем никогда нельзя сказать точно, что сегодня с утра значит оператор присваивания, а в Си - можно.
прямо как в ассемлере )))
В строке 4 последнего скетча написано что-то невразумительное. Например, "
sizeof
(prefix)
" на 8-битной ардуине ВСЕГДА (от слова "совсем всегда") равно 2. Вы этого хотели? Боюсь, что нетНет, этого я не хотел) prefix в данном случае произвольная си-строка. Вроде компилятор никак не подсвечивал prefix как зарезервированное имя. Но я к слову делаю проект под esp8266 если это что-то меняет.
если сделать static то содержимое строки будет сохранятся при последующих вызовах функции - а это не нужно
а других вариантов, собственно, и нет. Либо заранее выделяете кусок памяти с запасом, чтобы в него вошла любая из используемых строк, либо пользуетесь malloc. Беспокоится о размере массива в случае очистки не надо, это один из немногих примеров в С++, когда система действует автоматически.
Размер можно посчитать точно, но строка некрасивая и вызывать её несколько раз не хочется. вот через внешний указатель - вполне работает.. если бы только размер тоже считать внутри функции.
Надо подумать... по идее я могу передать вместо указателья на итоговую строку NULL, проверить это условием, посчитать внутри размер и вернуть int размера, инициализировать строку этим размерам и вызвать функцию с указателем на эту строку.. как-то так, пока не тестировал:
дык если вы в процедуре измените содержимое строки объявленной static, то как оно сохраниться то при последующем вызове?
я например при вызове функции, возвращающей строку, всегда в первый байт записываю ноль, соотвественно она никогда не повториться.
впрочем все зависит от задачи, учитывая что в МК не так много памяти, передавать функции указатель глобальной строки иногда даже более правильно.
prefix в данном случае произвольная си-строка
Это не строка, а указатель на символ. Собственно, Ваша ошибка как раз и связана с непониманием этого фундаментального различия. Вы берёте размер указателя, а вовсе не длину строки. А размер указателя всегда одинаковый.
Вроде компилятор никак не подсвечивал prefix как зарезервированное имя.
А с чего бы ему подсвечивать? Он никакой гадости не курит.
Но я к слову делаю проект под esp8266 если это что-то меняет.
Меняет. sizeof(prefix) на esp8266 равен не 2 (как на Uno) а 4. Всегда 4. Можете напечатать его в Serial и полюбоваться.
Это не строка, а указатель на символ. Собственно, Ваша ошибка как раз и связана с непониманием этого фундаментального различия. Вы берёте размер указателя
не только этого... товарищ похоже вообще не понимает, зачем нужен оператор sizeof()
В другом месте он берет sizeof() от целого, что он рассчитывает получить?
Это не строка, а указатель на символ. размер указателя всегда одинаковый.
Да, это я понял, тогда в функцию стоит передавать не указатель, а копию prefix, без звездочки.. либо придется передавать еще и размер
не только этого... товарищ похоже вообще не понимает, зачем нужен оператор sizeof()
В другом месте он берет sizeof() от целого, что он рассчитывает получить?
ну я подозревал, что int всегда занимает одинаковый размер, но кто его знает, вдруг двузначное число будет занимать больше места чем однозначное - лучше лишний раз проверить
ну я подозревал, что int всегда занимает одинаковый размер, но кто его знает, вдруг двузначное число будет занимать больше места чем однозначное - лучше лишний раз проверить
Чем подозревать неведомое, мошт лучше почитать чо-нить?
Да, это я понял, тогда в функцию стоит передавать не указатель, а копию prefix, без звездочки..
похоже что не понял... "prefix без звездочки" это как раз указатель и есть
поэтому вы берете размер целого и используете его для длины строки? - ну не смешите. Признайтесь. в первую очередь самому себе, что вы ни черта не понимаете в строках и указателях и отправляйтесь читать учебник. Худшее. что вы можете сделать в этой ситуации - делать вид. что "так и задумано"...
похоже что не понял... "prefix без звездочки" это как раз указатель и есть
поэтому вы берете размер целого и используете его для длины строки? - ну не смешите.
без звездочки вообще не работает... не компилится. по поводу целого и длины строки - не подумал что размер поменяется при переводе int в строку, спасибо что указали)).Хотя ниже я пытаюсь посчитать размер строки из int - но все равно нужно сперва задать размер для результирующей строки а где его взять? замкнутый круг))
я точно знаю, что imax в функции всегда <10, т.е. строка из этого числа будет 2 байта. Но задавать это явным образом (num[2]) - плохой тон, хотелось чтобы это вычислялось, но как-то пока не выходит. ну да фиг с ним. В итоге пока что рабочий пример получится такой:
Да, это я понял
Ну, если поняли, то и делайте. Зачем Вы вопросы задаёте? Нас экзаменуете?
Да, это я понял
Ну, если поняли, то и делайте. Зачем Вы вопросы задаёте? Нас экзаменуете?
Понял после вашего комментария, и в следующих примерах я как раз передаю размер строки prefix в функцию, так что делаю, да) но дальше уже новые вопросы появляются)
и что, это компилируется?
размер массива должен быть известен на этапе компиляции, использование функций для этого, как мне кажется, не катит.
Что касается вот этого
что-то мне сдается. что вы опять два размера указателей складываете
и что, это компилируется?
размер массива должен быть известен на этапе компиляции, использование функций для этого, как мне кажется, не катит.
Что касается вот этого
что-то мне сдается. что вы опять два размера указателей складываете
Компилируется. Это же вне функции куда передается указатель, поэтому это сама строка, а не указатель. вывод в Serial sizeof(str) выдает 150. ну и строка выводится верно. Также я поправил рассчет размера массива в примере выше в строке 18... видимо про это писали что там не нужен sizeof, но я как-то в упор не догонял о чем речь.
Пидец, на тебя извели целую рощу стоеросового дерева...
Парни, прекращаем подсказывать, пока тему не прочитает и зачёт на здаст.
в Serial sizeof(str) выдает 150.
Вы кого хотите обмануть? Себя или нас? Если нас, то не надо - всё равно не поверим. А если себя, так это можно и без форума делать. Выведите и посмотрите.
ну и строка выводится верно.
А вот вот это самая большая подлость этого языка для не желающих учиться новичков. Это называется "распашка памяти". На таком "верно" может всё что угодно быть. например, "сама строка верно", зато пачка других переменных почему-то изменяется. Да и строка ... вроде верно, а через пару строк программы, в которых её не трогают, она вдруг перестаёт быть верной ... Тут всякие шутки возможны.
Может, Вам всё-таки поучиться немного? Книжки почитать?
DetSimen, я всегда говорил, что "писец" - это профессия раньше была. Люди книжки переписывали. Так они хоть читали их заодно :(
в Serial sizeof(str) выдает 150.
Вы кого хотите обмануть? Себя или нас? Если нас, то не надо - всё равно не поверим. А если себя, так это можно и без форума делать. Выведите и посмотрите.
эмм, зачем мне обманывать кого-то? я вывел и сказал что выводится. вот вам скрин если сомневаетесь
вот в хорошем качестве, а то сюда как-то мутно загружается: https://i.postimg.cc/50ZkSzhb/24.jpg
Будет иметь реальный размер только в том случае, если str1 и str2 описаны массивами, а не указателями, как Вы описывали раньше
Т.е. они описаны НЕ
А, например,
вот тогда будет 150.
Будет иметь реальный размер только в том случае, если str1 и str2 описаны массивами, а не указателями, как Вы описывали раньше
Т.е. они описаны НЕ
А, например,
вот тогда будет 150.
Ну так они же так и описаны. Я правда не читал книжек по C, но думаю в данном случае вы немного запутались в моих примерах и поспешили сказать что я обманываю. Насколько я вижу, складываются размеры массивов, а не указателей, вывод в сериал это подтверждает. тыкните пожалуйста где я не прав в комментариях к коду:
Что есть, то есть, извините.
Вы постоянно выкладываете какие-то куски и огрызки и непонятно к чему они относятся. Привыкайте для вопросов писать отдельный маленький скетч и публикуйте его целиком, чтобы можно было запустить. Причём в каждом новом сообщении (при каждом новом вопросе), выкладывайте текущую версию скетча прямо в этом сообщении, чтобы люди не сомневались к какому именно скетчу относится вопрос. Так будет намного меньше недоразумений и эффективность увеличится.
Под ESP можно просто юзать String безо всяких либеральных указателей.
Люди книжки переписывали. Так они хоть читали их заодно :(
Не только переписывали, ещё и перерисовывали схемы. Заодно стараясь понять как эти самые схемы работают. Две тетради всегда были, одна «черновая», вторая «чистовая». Даже где-то лежат, последние лет 10 на глаза не попадали. Интернет их заменил... (((
Не только переписывали, ещё и перерисовывали схемы.
ну Евгений не про современных копипастов :), а про древних летописцев :) Те тоже переписывали и перерисовывали, а когда чего не понимали или просто скучно было - то и придумывали свое :) поэтому у нас в истории столько интересных событий, причем в каждой летописи - свои :)
Да я понял, но суть та же.
Переписал таким образом чтобы можно было отправлять сразу пачку "префиксов" и склеивать в строку внутри фукнции:
работает)
Работает без объявления str1 и выделения памяти? Удивительное событие.
Вам здесь можно всё.
понятное дело что там просто str должно быть. опечатка при копировании на сайт
понятное дело что там просто str должно быть. опечатка при копировании на сайт
См. #32. Это не было шуткой. Так как Вы себя ведёте - Вас просто будут посылать.
понятное дело что там просто str должно быть. опечатка при копировании на сайт
См. #32. Это не было шуткой. Так как Вы себя ведёте - Вас просто будут посылать.
не понял к чему это вообще?
я написал целый отдельный рабочий скетч с расширенным функционалом, вопросов у меня по нему нет - выложил для того чтобы принести так сказать пользу обществу - тот кто ищет подобное решение сможет найти и использовать.
ну оказалось есть одна очевидная опечатка - подумаешь, кто будет использовать код у себя - сразу же её обнаружит и исправит. в чем проблема то?
Какой смысл выкладывать "на пользу обществу" с отношением "подумаешь, опечатка" ? Разбираться в неизвестном коде, который даже не компилируется, никто не станет
не понял к чему это вообще?
я написал целый отдельный рабочий скетч с расширенным функционалом, вопросов у меня по нему нет - выложил для того чтобы принести так сказать пользу обществу - тот кто ищет подобное решение сможет найти и использовать.
ну оказалось есть одна очевидная опечатка - подумаешь, кто будет использовать код у себя - сразу же её обнаружит и исправит. в чем проблема то?
Пытался помочь Вам адаптироваться здесь (если Вы в этом не нуждаетесь, извините).
А объяснить я пытаюсь простую вещь, которую Вы, похоже, так до сих пор и не поняли.
1. Человек потратил своё время на просмотр Вашего кода и написал про ошибку.
2. Вы - "на самом деле код другой, а в этом опечатка".
Т.е. Вы дали человеку "не тот" код, который у Вас есть на самом деле, а он потратил на него время!
Угадайте сколько раз такое должно произойти, чтобы люди, увидев Ваш код, сразу же начинали думать: да, ну нах в нём разбираться, там опять поди "опечатка"?
Впрочем, далёк от мысли Вам что-то навязывать - это Ваша жизнь. Прекращаю базар.