Не инициализируется переменная
- Войдите на сайт для отправки комментариев
Ср, 15/12/2021 - 13:23
Здравствуйте. Подскажите пожалуйста почему так происходит. Данный код:
void setup() { Serial.begin(115200); Serial.println("Start"); Test(10); Test(5); Test(2); } void loop() { } char * Buff; void Test(const byte len) { Buff = (char*)"222_333_555"; Serial.println(strlen(Buff)); Serial.println(len); Serial.println(Buff[len]); Buff[len] = 'w'; Serial.print('>'); Serial.print(Buff); Serial.println('<'); }
Выдает такой результат:
Start 11 10 5 >222_333_55w< 11 5 3 >222_3w3_55w< 11 2 2 >22w_3w3_55w<
Sorry, продублирую результат
А если Buff перенести в локальную:
То результат такой:
...
AsNik - char* - это указатель на символьную переменную. А сама переменная -то где у вас? - нет ее
AsNik - char* - это указатель на символьную переменную.
Аааа, вроде начинаю понимать. Спасибо. Ох уж эти указатели, как я их люблю
А как указатель заменить на переменную в данном случае:
строка в Си - это просто массив символов. Массивы в Си не поддерживают копирования при присваивании, поэтому вот это не прокатит:
Так что либо функциями из библиотеки string.h. либо посимвольно. Или переходите на класс String - там присваивание поддерживается
А как указатель заменить на переменную в данном случае:
Указатель это char * Buff;. А ты написал где-то выделенный блок памяти, что не совсем то же самое.
AsNik - char* - это указатель на символьную переменную. А сама переменная -то где у вас? - нет ее
Вы поторопились. Он нормально присваивает указателю значение и всё там хорошо.
Проблема в другом. Он гадит в завершающий ноль в строке:
Buff[len] =
'w'
;
ТС, у Вас больно много скетчей, глаза разбегаются. Давайте сначала. Выложите один скетч (не пишите "см. выше", а выложите) и задайте вопросы.
строка в Си - это просто массив символов. Массивы в Си не поддерживают копирования при присваивании, поэтому вот это не прокатит:
Так что либо функциями из библиотеки string.h. либо посимвольно. Или переходите на класс String - там присваивание поддерживается
Понятно. Не, String не пойдет - из-за экономии памяти.
Как обычно, хотел упростить, а получается...))
Началось все из-за не реализованного астериска перед s в printf. Хотел сделать функцию, которая вернет строку определенной длины (длина передается параметром)...
Ну суть понял своей ошибки. Буду пробовать подходить к своему вопросу с другой стороны. Спасибо
Проблема в другом. Он гадит в завершающий ноль в строке:
Ну вроде как не в "завершающий" len - заведомо меньше чем "222_333_555"
ТС, у Вас больно много скетчей, глаза разбегаются. Давайте сначала. Выложите один скетч (не пишите "см. выше", а выложите) и задайте вопросы.
Хорошо, но чуть позже...
Ну суть понял своей ошибки.
Ничего Вы не поняли.
Началось все из-за не реализованного астериска перед s в printf.
А это вообще, про что?
Вы поторопились. Он нормально присваивает указателю значение и всё там хорошо.
вот тут хорошо?
А память для хранения строки "222_333_555" в какой момент выделяется?
А память для хранения строки "222_333_555" в какой момент выделяется?
Во время компоновки
А это вообще, про что?
Я дико извиняюсь, что ненадолго прерву свой же начатый диалог, нужно уехать... буду через несколько часов.
А это было про:
*
symbol) is not realized and will to abort the output.Из https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1
Но этот комментарий (про астериск) был косвенный, и к данному вопросу темы напрямую не относится.
Ничего Вы не поняли.
Мне действительно интересно разобраться, так что буду позже. Спасибо!
AsNik, а для чего вы вот здесь, при присваивании значения указателю, написали (char*) ?
Ведь и без этого всё правильно, кажется? Или нет? ))
Попробуйте, просто ради интереса, убрать, скомпилировать, и посмотреть что скажет компилятор.
Тут, скорее, надо удивлятося не тому что скетч из второго сообщения не работает - а тому что работает скетч из первого. Но это уж вопрос к знатокам всех тонкостей стандартов языка. Предполагаю, такое поведение компилятора ими, стандартами, допускается, но не гарантируется.
Ведь и без этого всё правильно, кажется? Или нет? ))
Без этого троллинг не будет таким тонким. )))
Buff[len] =
'w'
;
и посмотреть как изменится hex.скорее, надо удивлятося не тому что скетч из второго сообщения не работает - а тому что работает скетч из первого.
так он и не совсем работает, у МК нет контроля времени исполнения за изменением констант, которые в ОЗУ сидят. Студия к примеру уверено рубится в верном месте.
AsNik, а для чего вы вот здесь, при присваивании значения указателю, написали (char*) ?
Что бы не было: (warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings])
Проблема в другом. Он гадит в завершающий ноль в строке:
Buff[len] =
'w'
;
ТС, у Вас больно много скетчей, глаза разбегаются. Давайте сначала. Выложите один скетч (не пишите "см. выше", а выложите) и задайте вопросы.
Хорошо. По поводу завершающего ноля не понял, но...
Вот код:
Дает такой результат:
Почему переменная, которая при входе в функцию Test не инициализируется повторно строковой константой?
Потому что ты устанавливаешь указатель, а не инициализируешь переменную
Почему переменная ... при входе в функцию Test не инициализируется повторно строковой константой?
Она не может, потому что у неё совсем другой тип - указатель.
Причём указывает она не на константу, а на переменную, о чём вам дружно намекали и Logic, и я, и компилятор своим предупреждением, которое вы победили явным принудительным преобразованием типа. Я сам, кстати, пример не компилировал, и думал что выдаваться будет не предупреждение, а ошибка.
То есть, свой '+' вы записываете в константную строку, и удивляетесь, почему оно не всегда получается.
А я там выше говорил, что удивляться логичнее тому что вообще получалось, хоть иногда.
Все равно не понятно( Ведь при первом вызове Test как бы все так, как и должно быть. Второй и последующие вызовы Test не должны отличаться по результатам от первого. Ведь там те-же самые действия... так же локально должна заново инициализироваться глобальная Buff.... Ну и пусть указатель - Buff. Он же заново должен указывать на память где снова лежит строковая константа...
Или я прямо саму константу меняю что ли??? Ну так не должно же быть...
Ладно, дождусь Евгения....
Или я прямо саму константу меняю что ли??? Ну так не должно же быть...
Ну вот же! :)
Не должно. Вас и компилятор от этого пытался спасти - но вы заставили его сделать так как вам хочется.
А заставлять можно только если вы очень чётко представляете чего хотите, и готовы взять на себя всю ответственность за последствия.
Ну если я правильно понял, то прямо вот так вот строки тут не инициализируются.... т.е. без strcpy не обойтись, так?
Только если char Buff, а не char * Buff
Если сделать так:
То куча варнингов и ошибка... Причем само присвоение не ошибочно, но с варнингом... А ошибка - когда по индексу обращаюсь, но это и понятно, тут уже не массив... Чет я вообще притупил с этими строками, указателями...меняющимися константами...
То есть, свой '+' вы записываете в константную строку, и удивляетесь, почему оно не всегда получается.
А тут тогда что меняется:
Buff - перенесен локальной в Test. Результат:
А тут уже наверно и я предпочёл бы умолкнуть, и дождаться Евгения. ))
Ну вот честное слово, лучше до такой путаницы не доводить, чем потом в ней разбираться.
Мы, несмотря на предупреждение, поставили компилятор в ситуацию, которая наверно даже не предусмотрена никакими стандартами. Это значит, результат может быть просто не определённым и непредсказуемым. Поведение программы может зависеть и от компилятора, и от опций компиляции - например выбранного уровня оптимизации.
Вот как хотите, а я в этом участвовать отказываюсь. ))
Глянул листинг ...
При оптимизации Os - строка Buff[nCh] = '+'; игнорируется, а Serial.println(Buff[nCh]); превращается в Serial.println('+');
При оптимизации O0
А тут тогда что меняется:
Привыкайте делать вывод более информативным. Так очень трудно смотреть что там где среди цифирок.
Вот Ваш же код, чу-чуть поменянный. Смотрите, насколько информативнее стало. Всё тоже самое, ничего не поменялось, но читать легче.
теперь по поводу Вашего вопроса.
Вы, наверное знаете, что я сразу решения редко выдаю, начинаю с подсказки. Попробуйте код ниже. Он практически не отличается от Вашего. Запустите, посмотрите на результат. Напишите мне, что думаете.
Завтра продолжим.
строка Buff[nCh] = '+'; игнорируется .... превращается ...
Игнорируется - потому что пытаемся константу менять? Ой, у меня сейчас мозг взорвется...
Вот где должен быть варнинг, хотя бы по умолчанию... ибо я никаких дополнительных настроек компилятора, линковщика (кто там еще трудится над созданием конечного кода) не менял....
Ну и как это - превращается :) Я жду одно, а оно там бах и превратилось)
Привыкайте делать вывод более информативным.
Я так не умею, :( к сожалению.... Но это круто.... с одной стороны, но с другой - мне стало немного запутанней вывод смотреть, но спорить не буду. Возможно нужно привыкнуть)
Вы, наверное знаете, что я сразу решения редко выдаю, начинаю с подсказки. Попробуйте код ниже. Он практически не отличается от Вашего. Запустите, посмотрите на результат. Напишите мне, что думаете.
Знаю.... и знаю, что у Вас уже готов ответ.)
Код запустил, если пренебречь макросом и явным преобразованием (char(*)) перед каждой Buff, то локальная переменная Buff стала valatile
И повела себя так же как и глобальная. Valatile - у меня ассоциируется с прерываниями и неделимостью (атомарностью) переменных ...при чтении. (так же если посмотреть на Komandir #29, то от настроек оптимизации поведение Buff становится таким же)
Но прочитав тут на сайте про valatile
особо яснее для меня не стало. Но чувствую, что где-то рядом.... Ну слабый мой уровень в си :(
Поэтому пока у меня никаких новых мыслей, кроме того, что я действительно меняю константное значение в памяти, на которое указывает указатель Buff....
И если это так, то я думаю, что дальше смысл вопроса уже становится другим... И если не против, я продолжу эту тему немного другим вопросом, даже кодом (точнее функцией)... Собственно в ходе написания которого(ой) и возник вопрос этой темы. Но там уже реализовал по другому...
Если это не так, то я пока подожду с функцией и готов разобраться дальше.
Ну вот честное слово, лучше до такой путаницы не доводить, чем потом в ней разбираться.
Парадокс. Что бы не доводить, нужно сначала разобраться :)
Но для меня хуже всего, что я люблю разбираться и разберусь, но через год благополучно могу все забыть :( Так как Весна-лето-начало осени вообще некогда программить..., да и мозги уже не те... памяти нет нифика(
volatile указывает компилятору не оптимизировать действия с переменной.
просто увеличивает адрес строки на 10 или 5, туда и впихует ваш +, почти ассемблерное программирование )))
Привыкай, матьтваю. Ты не в скаску попал, а в Си вляпался. С точки зрения ISO, то что стоИт справа от знака равенства
является строковым литералом, т.е константой, поэтому правильное обьявление будет
тогда ты можешь менять указатель, но не саму строку
А вот описав это так
ты определяешь константный указатель на изменяемые данные, т.е
А есть еще константный указатель на константу, верёвка, мыло, табурет...
Ты скажи, что тебе надо сделать, тебе, мошт, и раскажут как.
Ты скажи, что тебе надо сделать, тебе, мошт, и раскажут как.
Деда, ему надо присвоить значение самому обычному символьному массиву. НЕ КОНСТАНТЕ! И что ему делать. я ему уже указал в сообщении #7
А вся эта длинная псевдонаучная дискуссия возникла на пустом месте только потому, что ТС не отличает константы от переменных
Вопщем, с указателями ТС не дружит.
Вопщем, с указателями ТС не дружит.
он что, редактор текста собрался на микроконтроллере делать? чего с ними дружить, просто использовать )))
Блин, опять протупил(((
И ведь это очевидно, что ж мне этот сишный кошмар никак не дойдет...(
Привыкай, матьтваю. Ты не в скаску попал, а в Си вляпался.
Вляпался ...по самые помидоры)) Дед опять бухал всю ночь из-за меня) Шучу. Ну такой я древний ученик.... даже переученик.)
ты определяешь константный указатель на изменяемые данные, т.е
А есть еще константный указатель на константу, верёвка, мыло, табурет...
Вот вроде я это все знаю, понимаю, но почему-то когда дело доходит до реализации путаюсь.
И прекрасно я отличаю (в теории) переменные, константы, строковые литералы, которые по определению константы, но указатели на них могут это опровергнуть)
Есть немного) И явно многих тут это раздражает( Мои искренние извинения.
И на сколько я заметил, сложнее всего мне идут указатели связанные со строками... Другие худо-бедно я понимаю (точнее использую, реализую, понимать-то я и строковые понимаю)....
Ты скажи, что тебе надо сделать, тебе, мошт, и раскажут как.
Вот очередной код:)
Вопрос данной темы возник на строке 3 в Test. Ну и да ладно с горем пополам вроде разобрался. Но реализовал немного по другому.
Данный пример - это мне нужно из функции вернуть строку определенной длины, дополнив ее пробелами (33 заменить на 32) с начала и конца. Сейчас у меня вопрос. Я не слишком измудрился с кодом в Test? Или можно это сделать проще и эффективнее?
Да, знаю что так if (aLen > BUFF_LEN) return; делать не очень правильно, но в данном контексте код - это вопрос, а не ответ. Поэтому оставил пока так и без комментариев. Хотя в си на МК этого может и достаточно)
И вот еще: strcpy_P(Str, PSTR("Txt")); - это тоже не конечный вариант, вместо Txt будет генерироваться (браться) другой текст. Собс-но данной функцией должна вернуться некая строка определенной длины и отцетрована пробелами внутри этой длины. Далее она пойдет в ("Text:%s", Test(7, Buff)) или ("Text:%s %s", Test(6, Buff), Test(6, Buff2))
Мошт, пожже найду у себя функцию центровки и вывода в 1602. Где-то была, и без всего вот этого вот бизабра...
Мошт, пожже найду у себя функцию центровки и вывода в 1602. Где-то была, и без всего вот этого вот бизабра...
Погоди, Дед... Это Только в некоторых случаях, строка центруется по центру, в других - будет по правому краю с одним пробелом в конце... (Возможно еще будут варианты). Так, на всякий случай) Я сам это реализую, просто на верном пути или...?
Я видел в инете пример вставки символов в начало строки (в конец - проблем нет, лишь бы за границу буфера не выйти). Типа смещение посимвольно вправо строки... Но сам сделал так. Изначально хотел:
но strcpy вставляет ноль....
функцию центровки и вывода в 1602.
Ну что, мне опять все с ноля переписывать? :) Там небось на низком уровне с подменой вывода print....
А чего тут разбираться? Вам уже объяснили, что Вы завели указатель char *. Это не массив символов - это только указатель (это не дом - это его адрес, а дома-то нет!). Вы направили этот указатель на литерал "ооо_ооо_ооо". Но это литерал, т.е. константа, которую менять нельзя и компилятор Вас об этом добросовестно предупредил. Он не вредничал - он защищал Вас от ошибки. Но Вы поставили перед литералом (char *), чем изнасиловали защиту компилятора с особым цинизмом и, что важнее, обманули сами себя - получили указатель на литерал с правом изменения.
Дальше вопрос оптимизации. Если её нет, Вы меняете литерал и всё как бы нормально. А если есть, то оптимизатор (считая, что литерал неизменен!!!) неправильно оптимизирует. Т.е. поставив перед литералом (char *) Вы назло компилятору себе уши отморозили.
Так делать можно, когда надо, но нужно понимать, что делаешь. А если это не Ваш случай, то делайте правильно!
Теперь о том, как делать правильно.
Правильно - если Вам нужен массив в памяти, так и объявляйте массив в памяти, а не указатель!
В Вашем коде (вернее, в первом коде из поста #30 )я меняю всего несколько символов, смотрите:
Запустите, полюбуйтесь!
А теперь перенесите строку №13 внутрь функции test (первой строкой). Обязательно запустите и такой вариант и почувствуйте разницу! Надо объяснять откуда разница взялась?
Та не такая уж она и константа. Вот я взял и поменял "ооо_ооо_ооо" на "ооо_йух_ооо". И любой ее поменять может. А Пи - хрен поменяешь!))) И контроллер эту константу при случае, во время исполнения меняет как хочет, т.к. она в ОЗУ лежит и ни чем от изменений не защищена. Ну никак она не ReadOnly. Если обойти изящно ограничения времени компиляции или неизящно стрельнуть по памяти, то эта типо константа меняется в атмеге аж гай шумит. Что собственно ТС нам и продемонстрировал.
А чего тут разбираться? Вам уже объяснили, что Вы завели указатель char *. Это не массив символов - это только указатель (это не дом - это его адрес, а дома-то нет!). Вы направили этот указатель на литерал "ооо_ооо_ооо".
Спасибо... Я уж понял. Меня смутило, что когда уже сказали в самом начале темы про неправильное мое использование указателей, Вы дали ответ, что "все правильно я делаю, но затираю ноль". Меня это насторожило и я уж ожидал какой другой подвох, но....
В Вашем коде (вернее, в первом коде из поста #30 )я меняю всего несколько символов, смотрите:
Запустите, полюбуйтесь!
А теперь перенесите строку №13 внутрь функции test (первой строкой). Обязательно запустите и такой вариант и почувствуйте разницу! Надо объяснять откуда разница взялась?
Так я тоже пробовал еще до поднятия вопроса. Дело в том, что это - char Buff[] = "ooo_ooo_ooo"; присваивается(инициализируется). Но если дальше попробовать написать Buff = "ooo_zyx_ooo" - то не катит.
Сбивают меня с толку эти звездочки... а со строками (коих в си "нет") вообще трындец...
Дело в том, что это - char Buff[] = "ooo_ooo_ooo"; присваивается(инициализируется). Но если дальше попробовать написать Buff = "ooo_zyx_ooo" - то не катит.
потому что Buff[] - это массив, а Buff - указатель на его первый (нулевой) элемент. Нельзя присвоить строку указателю....
Учите Си
Так я ж и говорю, что так делать можно, если понимаете, что делаете. Я думал, что Вы понимаете. А вообще, Вы очень невнятно задаёте вопросы.
Вот, опять
Я же Вас просил дать один код и задать вопрос. Вы дали и задали. Я Вам ответил. Мой код работает. Ни про какие "дальше попробовать написать Buff = "ooo_zyx_ooo"" в Вашем вопросе ничего не было.
Если у Вас проблема с этим, а не с объявлением массива, так давайте код про это (что и как Вы делаете, а, главное, что хотите сделать) и задавайте внятный вопрос.
char Buff[] = "ooo_ooo_ooo"; присваивается(инициализируется). Но если дальше попробовать написать Buff = "ooo_zyx_ooo" - то не катит.
Сбивают меня с толку эти звездочки... а со строками (коих в си "нет") вообще трындец...
А ты пишы
char Buff[] = "ooo_ooo_ooo";
char *BufPtr = Buff;
и настанет камунизм в отдельно взятом пространстве памяти.
Но если дальше попробовать написать Buff = "ooo_zyx_ooo" - то не катит.
Ох! Тяжело тебе будет... Ты из каких в Си пришел? Из Java? Скорее из JS или Python, да?
Так не присваиваются строки в Си. В Яве такая работа со строками тоже исключение для базового типа. В Си, как легко догадаться, при этом копируется УКАЗАТЕЛЬ, а не содержимое. Для копирования содержимого нужно явно копировать при помощи strcpy() или memcpy(), если желаешь. То есть ровно как в Яве, при присваивании объект НЕ КОПИРУЕТСЯ, за исключением строк. Вот в Си даже строки так НЕ КОПИРУЮБТСЯ. Ок?