Не инициализируется переменная

AsNik
Offline
Зарегистрирован: 24.10.2020

Здравствуйте. Подскажите пожалуйста почему так происходит. Данный код:

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<

AsNik
Offline
Зарегистрирован: 24.10.2020

Sorry, продублирую результат

Start
11
10
5
>222_333_55w<
11
5
3
>222_3w3_55w<
11
2
2
>22w_3w3_55w<
 
AsNik
Offline
Зарегистрирован: 24.10.2020

А если Buff перенести в локальную:

void setup() {
  Serial.begin(115200); Serial.println("Start");
  Test(10);
  Test(5);
  Test(2);
}

void loop() {

}


void Test(const byte len) {
  char * Buff;
  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_555<
11
5
3
>222_333_555<
11
2
2
>222_333_555<
 
Т.е. она (Buff) не изменяется
AsNik
Offline
Зарегистрирован: 24.10.2020

...

b707
Offline
Зарегистрирован: 26.05.2017

AsNik - char* - это указатель на символьную переменную. А сама переменная -то где у вас? - нет ее

AsNik
Offline
Зарегистрирован: 24.10.2020

b707 пишет:

AsNik - char* - это указатель на символьную переменную.

Аааа, вроде начинаю понимать. Спасибо. Ох уж эти указатели, как я их люблю

AsNik
Offline
Зарегистрирован: 24.10.2020

А как указатель заменить на переменную в данном случае:

  char Buff[15];
  Buff = "222_333_555";
 
так нельзя, я так понял.. 
incompatible types in assignment of 'const char [12]' to 'char [15]'
Про: char Buff[15] = {"222_333_555"}; - это я знаю, но нужна инициализация потом.
 
только strcpy? Или... я уже запутался(

 

b707
Offline
Зарегистрирован: 26.05.2017

строка в Си - это просто массив символов. Массивы в Си не поддерживают копирования при присваивании, поэтому вот это не прокатит:

char Buff[15];
  Buff = "222_333_555";

Так что либо функциями из библиотеки string.h. либо посимвольно. Или переходите на класс String - там присваивание поддерживается

rkit
Offline
Зарегистрирован: 23.11.2016

AsNik пишет:

А как указатель заменить на переменную в данном случае:

  char Buff[15];
  Buff = "222_333_555";
 
так нельзя, я так понял.. 
incompatible types in assignment of 'const char [12]' to 'char [15]'
Про: char Buff[15] = {"222_333_555"}; - это я знаю, но нужна инициализация потом.
 
только strcpy? Или... я уже запутался(

 

Указатель это char * Buff;. А ты написал где-то выделенный блок памяти, что не совсем то же самое.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

AsNik - char* - это указатель на символьную переменную. А сама переменная -то где у вас? - нет ее

Вы поторопились. Он нормально присваивает указателю значение и всё там хорошо.

Проблема в другом. Он гадит в завершающий ноль в строке:

Buff[len] = 'w';

ТС, у Вас больно много скетчей, глаза разбегаются. Давайте сначала. Выложите один скетч (не пишите "см. выше", а выложите) и задайте вопросы.

AsNik
Offline
Зарегистрирован: 24.10.2020

b707 пишет:

строка в Си - это просто массив символов. Массивы в Си не поддерживают копирования при присваивании, поэтому вот это не прокатит:

char Buff[15];
  Buff = "222_333_555";

Так что либо функциями из библиотеки string.h. либо посимвольно. Или переходите на класс String - там присваивание поддерживается

Понятно. Не, String не пойдет - из-за экономии памяти.

Как обычно, хотел упростить, а получается...))

Началось все из-за не реализованного астериска перед s в printf. Хотел сделать функцию, которая вернет строку определенной длины (длина передается параметром)...

Ну суть понял своей ошибки. Буду пробовать подходить к своему вопросу с другой стороны. Спасибо

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

Проблема в другом. Он гадит в завершающий ноль в строке:

Ну вроде как не в "завершающий" len - заведомо меньше чем "222_333_555"

ЕвгенийП пишет:

ТС, у Вас больно много скетчей, глаза разбегаются. Давайте сначала. Выложите один скетч (не пишите "см. выше", а выложите) и задайте вопросы.

Хорошо, но чуть позже...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AsNik пишет:

Ну суть понял своей ошибки. 

Ничего Вы не поняли.

AsNik пишет:

Началось все из-за не реализованного астериска перед s в printf. 

А это вообще, про что?

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Вы поторопились. Он нормально присваивает указателю значение и всё там хорошо.

вот тут хорошо?

char * Buff;
Buff = (char*)"222_333_555";

А память для хранения строки  "222_333_555" в какой момент выделяется?

 

rkit
Offline
Зарегистрирован: 23.11.2016

b707 пишет:

А память для хранения строки  "222_333_555" в какой момент выделяется?

 

Во время компоновки

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

А это вообще, про что?

Я дико извиняюсь, что ненадолго прерву свой же начатый диалог, нужно уехать... буду через несколько часов.

А это было про:

  • The variable width or precision field (an asterisk * symbol) is not realized and will to abort the output.

Из https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1

Но этот комментарий (про астериск) был косвенный, и к данному вопросу темы напрямую не относится.

ЕвгенийП пишет:

Ничего Вы не поняли.

Мне действительно интересно разобраться, так что буду позже. Спасибо!

Datak
Offline
Зарегистрирован: 09.10.2014

AsNik пишет:

Т.е. она (Buff) не изменяется

AsNik, а для чего вы вот здесь, при присваивании значения указателю, написали (char*) ?

AsNik пишет:

  Buff = (char*)"222_333_555";

Ведь и без этого всё правильно, кажется? Или нет? ))

Попробуйте, просто ради интереса, убрать, скомпилировать, и посмотреть что скажет компилятор.

Тут, скорее, надо удивлятося не тому что скетч из второго сообщения не работает - а тому что работает скетч из первого. Но это уж вопрос к знатокам всех тонкостей стандартов языка. Предполагаю, такое поведение компилятора ими, стандартами, допускается, но не гарантируется.

Logik
Offline
Зарегистрирован: 05.08.2014

Datak пишет:

Ведь и без этого всё правильно, кажется? Или нет? ))

Без этого троллинг не будет таким тонким. )))

C:\Users\Стас\Documents\Arduino\sketch_dec15a\sketch_dec15a.ino:15:8: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
 
Еще интересней закомментировать Buff[len] = 'w'и посмотреть как изменится hex.
 

Datak пишет:

 скорее, надо удивлятося не тому что скетч из второго сообщения не работает - а тому что работает скетч из первого. 

так он и не совсем работает, у МК нет контроля времени исполнения за изменением констант, которые в ОЗУ сидят. Студия к примеру уверено рубится в верном месте.

 

AsNik
Offline
Зарегистрирован: 24.10.2020

Datak пишет:

AsNik, а для чего вы вот здесь, при присваивании значения указателю, написали (char*) ?

Что бы не было: (warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings])

 

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

Проблема в другом. Он гадит в завершающий ноль в строке:

Buff[len] = 'w';

ТС, у Вас больно много скетчей, глаза разбегаются. Давайте сначала. Выложите один скетч (не пишите "см. выше", а выложите) и задайте вопросы.

Хорошо. По поводу завершающего ноля не понял, но...

Вот код:

void setup() {
  Serial.begin(115200); Serial.println("Start");
  Test(10);
  Test(5);
  Test(2);
}

void loop() {}

char * Buff;
void Test(const byte nCh) {
  Buff = (char*)"ooo_ooo_ooo";
  Serial.println(strlen(Buff));
  Serial.println(nCh);
  Serial.println(Buff[nCh]);
  Buff[nCh] = '+';
  Serial.println(Buff[nCh]);
  Serial.println(strlen(Buff));
  Serial.print('>'); Serial.print(Buff); Serial.println('<');
}

Дает такой результат:

Start
11
10
o
+
11
>ooo_ooo_oo+<
11
5
o
+
11
>ooo_o+o_oo+<
11
2
o
+
11
>oo+_o+o_oo+<
 
 
Почему переменная, которая при входе в функцию Test не инициализируется повторно строковой константой?
Видно же что и длина строки не меняется, т.е. ноль не затирается. Но и при каждом вызове меняется содержимое Buff. Это если Buff глобальная. С локальной немного по другому, но я так понял пока об этом не будем.
А вообще, я как раз и хотел туда изначально ноль писать, т.е. обрезать строку до нужной длины.
 
Я поменял len на nCh что бы не вводило в заблуждение, что len - это длина строки Buff...
rkit
Offline
Зарегистрирован: 23.11.2016

AsNik пишет:

Почему переменная, которая при входе в функцию Test не инициализируется повторно строковой константой?

Потому что ты устанавливаешь указатель, а не инициализируешь переменную

Datak
Offline
Зарегистрирован: 09.10.2014

AsNik пишет:

Почему переменная ... при входе в функцию Test не инициализируется повторно строковой константой?

Она не может, потому что у неё совсем другой тип - указатель.

Причём указывает она не на константу, а на переменную, о чём вам дружно намекали и Logic, и я, и компилятор своим предупреждением, которое вы победили явным принудительным преобразованием типа. Я сам, кстати, пример не компилировал, и думал что выдаваться будет не предупреждение, а ошибка.

То есть, свой '+' вы записываете в константную строку, и удивляетесь, почему оно не всегда получается.

А я там выше говорил, что удивляться логичнее тому что вообще получалось, хоть иногда.

AsNik
Offline
Зарегистрирован: 24.10.2020

Все равно не понятно( Ведь при первом вызове Test как бы все так, как и должно быть. Второй и последующие вызовы Test не должны отличаться по результатам от первого. Ведь там те-же самые действия... так же локально должна заново инициализироваться глобальная Buff.... Ну и пусть указатель - Buff. Он же заново должен указывать на память где  снова лежит строковая константа...

Или я прямо саму константу меняю что ли??? Ну так не должно же быть...

Ладно, дождусь Евгения....

 

Datak
Offline
Зарегистрирован: 09.10.2014

AsNik пишет:

Или я прямо саму константу меняю что ли??? Ну так не должно же быть...

Ну вот же! :)

Не должно. Вас и компилятор от этого пытался спасти - но вы заставили его сделать так как вам хочется.

А заставлять можно только если вы очень чётко представляете чего хотите, и готовы взять на себя всю ответственность за последствия.

AsNik
Offline
Зарегистрирован: 24.10.2020

Ну если я правильно понял, то прямо вот так вот строки тут не инициализируются.... т.е. без strcpy не обойтись, так?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Только если char Buff, а не char * Buff

AsNik
Offline
Зарегистрирован: 24.10.2020

Если сделать так:

void setup() {
  Serial.begin(115200); Serial.println("Start");
  Test(10);
  Test(5);
  Test(2);
}

void loop() {}

char Buff;
void Test(const byte nCh) {

  Buff = "ooo_ooo_ooo";
  Serial.println(strlen(Buff));
  Serial.println(nCh);
  Serial.println(Buff[nCh]);
  Buff[nCh] = '+';
  Serial.println(Buff[nCh]);
  Serial.println(strlen(Buff));
  Serial.print('>'); Serial.print(Buff); Serial.println('<');
}

То куча варнингов и ошибка... Причем само присвоение не ошибочно, но с варнингом... А ошибка - когда по индексу обращаюсь, но это и понятно, тут уже не массив... Чет я вообще притупил с этими строками, указателями...меняющимися константами...

AsNik
Offline
Зарегистрирован: 24.10.2020

Datak пишет:

То есть, свой '+' вы записываете в константную строку, и удивляетесь, почему оно не всегда получается.

А тут тогда что меняется:

void setup() {
  Serial.begin(115200); Serial.println("Start");
  Test(10);
  Test(5);
  Test(2);
}

void loop() {}

void Test(const byte nCh) {
char * Buff;  
  Buff = (char*)"ooo_ooo_ooo";
  Serial.println(strlen(Buff));
  Serial.println(nCh);
  Serial.println(Buff[nCh]);
  Buff[nCh] = '+';
  Serial.println(Buff[nCh]);
  Serial.println(strlen(Buff));
  Serial.print('>'); Serial.print(Buff); Serial.println('<');
}

Buff - перенесен локальной в Test. Результат:

Start
11
10
o
+
11
>ooo_ooo_ooo<
11
5
o
+
11
>ooo_ooo_ooo<
11
2
o
+
11
>ooo_ooo_ooo<
 
Т.е. видно же что Buff[nCh] = '+'; и следом Serial.println(Buff[nCh]); там "что-то" поменялось, но если дальше вывести всю Buff разом, то она не изменилась....
Datak
Offline
Зарегистрирован: 09.10.2014

А тут уже наверно и я предпочёл бы умолкнуть, и дождаться Евгения. ))

Ну вот честное слово, лучше до такой путаницы не доводить, чем потом в ней разбираться.

Мы, несмотря на предупреждение, поставили компилятор в ситуацию, которая наверно даже не предусмотрена никакими стандартами. Это значит, результат может быть просто не определённым и непредсказуемым. Поведение программы может зависеть и от компилятора, и от опций компиляции - например выбранного уровня оптимизации.

Вот как хотите, а я в этом участвовать отказываюсь. ))

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Глянул листинг ...

При оптимизации Os - строка Buff[nCh] = '+'; игнорируется, а Serial.println(Buff[nCh]); превращается в Serial.println('+');

При оптимизации O0

Start
11
10
o
+
11
>ooo_ooo_oo+<
11
5
o
+
11
>ooo_o+o_oo+<
11
2
o
+
11
>oo+_o+o_oo+<
 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AsNik пишет:

А тут тогда что меняется:

Привыкайте делать вывод более информативным. Так очень трудно смотреть что там где среди цифирок.

Вот Ваш же код, чу-чуть поменянный. Смотрите, насколько информативнее стало. Всё тоже самое, ничего не поменялось, но читать легче.

#define printVar(x) do { Serial.print(#x);  Serial.print('='); Serial.print(x); Serial.println(';'); } while (false)

void setup() {
	Serial.begin(115200); 
	Serial.println("Start");
	Test(10);
	Test(5);
	Test(2);
}

void loop() {}

void Test(const byte nCh) {
	char * Buff;  
	Buff = (char*)"ooo_ooo_ooo";
	printVar(strlen(Buff));
	printVar(nCh);
	printVar(Buff[nCh]);
	Buff[nCh] = '+';
	printVar(Buff[nCh]);
	printVar(strlen(Buff));
	printVar(Buff);
}

теперь по поводу Вашего вопроса.

Вы, наверное знаете, что я сразу решения редко выдаю, начинаю с подсказки. Попробуйте код ниже. Он практически не отличается от Вашего. Запустите, посмотрите на результат. Напишите мне, что думаете.

#define printVar(x) do { Serial.print(#x);  Serial.print('='); Serial.print(x); Serial.println(';'); } while (false)

void setup() {
	Serial.begin(115200); 
	Serial.println("Start");
	Test(10);
	Test(5);
	Test(2);
}

void loop() {}

void Test(const byte nCh) {
	volatile char * Buff;  
	Buff = (char*)"ooo_ooo_ooo";
	printVar(strlen((char *)Buff));
	printVar(nCh);
	printVar((char)Buff[nCh]);
	Buff[nCh] = '+';
	printVar((char)Buff[nCh]);
	printVar(strlen((char *)Buff));
	printVar((char *)Buff);
}

Завтра продолжим.

AsNik
Offline
Зарегистрирован: 24.10.2020

Komandir пишет:

строка Buff[nCh] = '+'; игнорируется .... превращается ...

Игнорируется - потому что пытаемся константу менять? Ой, у меня сейчас мозг взорвется...

Вот где должен быть варнинг, хотя бы по умолчанию... ибо я никаких дополнительных настроек компилятора, линковщика (кто там еще трудится над созданием конечного кода) не менял....

Ну и как это - превращается :) Я жду одно, а оно там бах и превратилось)

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

Привыкайте делать вывод более информативным.

#define printVar(x) do { Serial.print(#x);  Serial.print('='); Serial.print(x); Serial.println(';'); } while (false)

Я так не умею, :( к сожалению.... Но это круто.... с одной стороны, но с другой - мне стало немного запутанней вывод смотреть, но спорить не буду. Возможно нужно привыкнуть)

Цитата:

Вы, наверное знаете, что я сразу решения редко выдаю, начинаю с подсказки. Попробуйте код ниже. Он практически не отличается от Вашего. Запустите, посмотрите на результат. Напишите мне, что думаете.

Знаю.... и знаю, что у Вас уже готов ответ.)

Код запустил, если пренебречь макросом и явным преобразованием (char(*)) перед каждой Buff, то локальная переменная Buff стала valatile

И повела себя так же как и глобальная. Valatile - у меня ассоциируется с прерываниями и неделимостью (атомарностью) переменных ...при чтении. (так же если посмотреть на Komandir #29, то от настроек оптимизации поведение Buff становится таким же)

Но прочитав тут на сайте про valatile

Он указывает компилятору загрузить переменную из ОЗУ, и не из запоминающего регистра – временной ячейки памяти, в которой хранятся переменные программы и производятся операции с ними. При определенных условиях значения переменных, хранящихся в регистрах, могут оказаться неточными.

особо яснее для меня не стало. Но чувствую, что где-то рядом.... Ну слабый мой уровень в си :(

Поэтому пока у меня никаких новых мыслей, кроме того, что я действительно меняю константное значение в памяти, на которое указывает указатель Buff....

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

Если это не так, то я пока подожду с функцией и готов разобраться дальше.

AsNik
Offline
Зарегистрирован: 24.10.2020

Datak пишет:

Ну вот честное слово, лучше до такой путаницы не доводить, чем потом в ней разбираться.

Парадокс. Что бы не доводить, нужно сначала разобраться :)

Но для меня хуже всего, что я люблю разбираться и разберусь, но через год благополучно могу все забыть :( Так как Весна-лето-начало осени вообще некогда программить..., да и мозги уже не те... памяти нет нифика(

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

volatile указывает компилятору не оптимизировать действия с переменной.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

просто увеличивает адрес строки на 10 или 5, туда и впихует ваш +, почти ассемблерное программирование )))

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Привыкай, матьтваю.  Ты не в скаску попал, а в Си вляпался.  С точки зрения ISO, то что стоИт справа от знака равенства

char *Ptr = "string1";  // warning, ISO forbids, б-ть!!!

является строковым литералом, т.е константой, поэтому правильное обьявление будет

const char *Ptr = "string1";  // указатель на константную строку

тогда ты можешь менять указатель, но не саму строку

Ptr = "string2";  // можно, Ptr теперь указывает на другую константную строку

Ptr[2] = 't'; // хрен тебе в сумку, нельзя ничего менять по указателю на константу

А вот описав это так

char *const Ptr = "string1";

ты определяешь константный указатель на изменяемые данные, т.е 

Ptr[2] = 'x'; // пройдёт, но 

Ptr = "string2"; // хрен тебе в сумку, брат, указатель константный, может указывать только на string1

А есть еще константный указатель на константу, верёвка, мыло, табурет... 

Ты скажи, что тебе надо сделать, тебе, мошт, и раскажут как. 

b707
Offline
Зарегистрирован: 26.05.2017

DetSimen пишет:

Ты скажи, что тебе надо сделать, тебе, мошт, и раскажут как. 

Деда, ему надо присвоить значение самому обычному символьному массиву. НЕ КОНСТАНТЕ! И что ему делать. я ему уже указал в сообщении #7

А вся эта длинная псевдонаучная дискуссия возникла на пустом месте только потому, что ТС не отличает константы от переменных

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Вопщем, с указателями ТС не дружит. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

Вопщем, с указателями ТС не дружит. 

он что, редактор текста собрался на микроконтроллере делать? чего с ними дружить, просто использовать )))

AsNik
Offline
Зарегистрирован: 24.10.2020

DetSimen пишет:

const char *Ptr = "string1"; // указатель на константную строку


 
тогда ты можешь менять указатель, но не саму строку
 
Ptr = "string2";  // можно, Ptr теперь указывает на другую константную строку

Блин, опять протупил(((

И ведь это очевидно, что ж мне этот сишный кошмар никак не дойдет...(

Цитата:

Привыкай, матьтваю.  Ты не в скаску попал, а в Си вляпался. 

Вляпался ...по самые помидоры))  Дед опять бухал всю ночь из-за меня) Шучу. Ну такой я древний ученик.... даже переученик.)

Цитата:
А вот описав это так

char *const Ptr = "string1";

ты определяешь константный указатель на изменяемые данные, т.е 

Ptr[2] = 'x'; // пройдёт, но 

Ptr = "string2"; // хрен тебе в сумку, брат, указатель константный, может указывать только на string1

А есть еще константный указатель на константу, верёвка, мыло, табурет...

Вот вроде я это все знаю, понимаю, но почему-то когда дело доходит до реализации путаюсь.

И прекрасно я отличаю (в теории) переменные, константы, строковые литералы, которые по определению константы, но указатели на них могут это опровергнуть)

Цитата:
Вопщем, с указателями ТС не дружит.

Есть немного) И явно многих тут это раздражает( Мои искренние извинения.

И на сколько я заметил, сложнее всего мне идут указатели связанные со строками... Другие худо-бедно я понимаю (точнее использую, реализую, понимать-то я и строковые понимаю)....

AsNik
Offline
Зарегистрирован: 24.10.2020

DetSimen пишет:

Ты скажи, что тебе надо сделать, тебе, мошт, и раскажут как. 

Вот очередной код:)

#define BUFF_LEN 15

char Buff[BUFF_LEN];

void setup() {
  Serial.begin(115200); Serial.println("Start");
  Serial.println(Test(11, Buff));
  Serial.println(Test(10, Buff));
  Serial.println(Test(9, Buff));
  Serial.println(Test(5, Buff));
  Serial.println(Test(4, Buff));
  Serial.println(Test(3, Buff));
  Serial.println(Test(2, Buff));
}

void loop() {}

char * Test(const byte aLen, char * aTxt) {
  if (aLen > BUFF_LEN) return;
  char Str[aLen];
  //Str = "Txt";
  strcpy_P(Str, PSTR("Txt"));
  byte L = strlen(Str);
  byte nPos;
  if (L >= aLen) strcpy(aTxt, Str);
  else {
    nPos = (aLen + 1 - L) / 2;
    memset(aTxt, 33, nPos);   // 33 (!) чтобы наглядно было, заменится на 32
    strcpy(aTxt + nPos, Str);
    memset(aTxt + nPos + L, 33, aLen - nPos - L);
  }
  aTxt[aLen] = '\0';
  return aTxt;
}

Вопрос данной темы возник на строке 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))

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Мошт, пожже найду у себя функцию центровки и вывода в 1602. Где-то была, и без всего вот этого вот бизабра...

AsNik
Offline
Зарегистрирован: 24.10.2020

DetSimen пишет:

Мошт, пожже найду у себя функцию центровки и вывода в 1602. Где-то была, и без всего вот этого вот бизабра...

Погоди, Дед... Это Только в некоторых случаях, строка центруется по центру, в других - будет по правому краю с одним пробелом в конце... (Возможно еще будут варианты). Так, на всякий случай)  Я сам это реализую, просто на верном пути или...?

Я видел в инете пример вставки символов в начало строки (в конец - проблем нет, лишь бы за границу буфера не выйти). Типа смещение посимвольно вправо строки... Но сам сделал так. Изначально хотел:

memset(aTxt, 33, aLen);
strcpy(aTxt + nPos, Str);

но strcpy вставляет ноль....

Цитата:

функцию центровки и вывода в 1602. 

Ну что, мне опять все с ноля переписывать? :) Там небось на низком уровне с подменой вывода print....

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AsNik пишет:
готов разобраться дальше.

А чего тут разбираться? Вам уже объяснили, что Вы завели указатель char *. Это не массив символов - это только указатель (это не дом - это его адрес, а дома-то нет!). Вы направили этот указатель на литерал "ооо_ооо_ооо". Но это литерал, т.е. константа, которую менять нельзя и компилятор Вас об этом добросовестно предупредил. Он не вредничал - он защищал Вас от ошибки. Но Вы поставили перед литералом (char *), чем изнасиловали защиту компилятора с особым цинизмом и, что важнее, обманули сами себя - получили указатель на литерал с правом изменения.

Дальше вопрос оптимизации. Если её нет, Вы меняете литерал и всё как бы нормально. А если есть, то оптимизатор (считая, что литерал неизменен!!!) неправильно оптимизирует. Т.е. поставив перед литералом (char *) Вы назло компилятору себе уши отморозили.

Так делать можно, когда надо, но нужно понимать, что делаешь. А если это не Ваш случай, то делайте правильно!

Теперь о том, как делать правильно.

Правильно - если Вам нужен массив в памяти, так и объявляйте массив в памяти, а не указатель!

В Вашем коде (вернее, в первом коде из поста #30 )я меняю всего несколько символов, смотрите:

#define printVar(x) do { Serial.print(#x);  Serial.print('='); Serial.print(x); Serial.println(';'); } while (false)

void setup() {
	Serial.begin(115200); 
	Serial.println("Start");
	Test(10);
	Test(5);
	Test(2);
}

void loop() {}

char Buff[] = "ooo_ooo_ooo";

void Test(const byte nCh) {
	printVar(strlen(Buff));
	printVar(nCh);
	printVar(Buff[nCh]);
	Buff[nCh] = '+';
	printVar(Buff[nCh]);
	printVar(strlen(Buff));
	printVar(Buff);
}

Запустите, полюбуйтесь!

А теперь перенесите строку №13 внутрь функции test (первой строкой). Обязательно запустите и такой вариант и почувствуйте разницу! Надо объяснять откуда разница взялась?

Logik
Offline
Зарегистрирован: 05.08.2014

Та не такая уж она и константа. Вот я взял и поменял "ооо_ооо_ооо" на "ооо_йух_ооо". И любой ее поменять может. А Пи - хрен поменяешь!))) И контроллер эту константу при случае, во время исполнения меняет как хочет, т.к. она в ОЗУ лежит и ни чем от изменений не защищена. Ну никак она не ReadOnly. Если обойти изящно ограничения времени компиляции или неизящно стрельнуть по памяти, то эта типо константа меняется в атмеге аж гай шумит. Что собственно ТС нам и продемонстрировал. 

AsNik
Offline
Зарегистрирован: 24.10.2020

ЕвгенийП пишет:

А чего тут разбираться? Вам уже объяснили, что Вы завели указатель char *. Это не массив символов - это только указатель (это не дом - это его адрес, а дома-то нет!). Вы направили этот указатель на литерал "ооо_ооо_ооо".

Спасибо... Я уж понял. Меня смутило, что когда уже сказали в самом начале темы про неправильное мое использование указателей, Вы дали ответ, что "все правильно я делаю, но затираю ноль". Меня это насторожило и я уж ожидал какой другой подвох, но....

 

ЕвгенийП пишет:

В Вашем коде (вернее, в первом коде из поста #30 )я меняю всего несколько символов, смотрите:

#define printVar(x) do { Serial.print(#x);  Serial.print('='); Serial.print(x); Serial.println(';'); } while (false)

void setup() {
	Serial.begin(115200); 
	Serial.println("Start");
	Test(10);
	Test(5);
	Test(2);
}

void loop() {}

char Buff[] = "ooo_ooo_ooo";

void Test(const byte nCh) {
	printVar(strlen(Buff));
	printVar(nCh);
	printVar(Buff[nCh]);
	Buff[nCh] = '+';
	printVar(Buff[nCh]);
	printVar(strlen(Buff));
	printVar(Buff);
}

Запустите, полюбуйтесь!

А теперь перенесите строку №13 внутрь функции test (первой строкой). Обязательно запустите и такой вариант и почувствуйте разницу! Надо объяснять откуда разница взялась?

Так я тоже пробовал еще до поднятия вопроса. Дело в том, что это - char Buff[] = "ooo_ooo_ooo"; присваивается(инициализируется). Но если дальше попробовать написать Buff = "ooo_zyx_ooo" - то не катит.

Сбивают меня с толку эти звездочки... а со строками (коих в си "нет") вообще трындец...

b707
Offline
Зарегистрирован: 26.05.2017

AsNik пишет:

Дело в том, что это - char Buff[] = "ooo_ooo_ooo"; присваивается(инициализируется). Но если дальше попробовать написать Buff = "ooo_zyx_ooo" - то не катит.

потому что Buff[] - это массив, а Buff - указатель на его первый (нулевой) элемент. Нельзя присвоить строку указателю....

Учите Си

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AsNik пишет:

Вы дали ответ, что "все правильно я делаю, но затираю ноль". 

Так я ж и говорю, что так делать можно, если понимаете, что делаете. Я думал, что Вы понимаете. А вообще, Вы очень невнятно задаёте вопросы.

Вот, опять

AsNik пишет:

Так я тоже пробовал еще до поднятия вопроса. Дело в том, что это char Buff[] = "ooo_ooo_ooo"; присваивается(инициализируется) Но если дальше попробовать написать Buff = "ooo_zyx_ooo" - то не катит.

Я же Вас просил дать один код и задать вопрос. Вы дали и задали. Я Вам ответил. Мой код работает. Ни про какие "дальше попробовать написать Buff = "ooo_zyx_ooo"" в Вашем вопросе ничего не было.

Если у Вас проблема с этим, а не с объявлением массива, так давайте код про это (что и как Вы делаете, а, главное, что хотите сделать) и задавайте внятный вопрос.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

AsNik пишет:

char Buff[] = "ooo_ooo_ooo"; присваивается(инициализируется). Но если дальше попробовать написать Buff = "ooo_zyx_ooo" - то не катит.

Сбивают меня с толку эти звездочки... а со строками (коих в си "нет") вообще трындец...

А ты пишы 

char Buff[] = "ooo_ooo_ooo";

char *BufPtr = Buff;

и настанет камунизм в отдельно взятом пространстве памяти. 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

AsNik пишет:

 Но если дальше попробовать написать Buff = "ooo_zyx_ooo" - то не катит.

Ох! Тяжело тебе будет... Ты из каких в Си пришел? Из Java? Скорее из JS или Python, да?

Так не присваиваются строки в Си. В Яве такая работа со строками тоже исключение для базового типа. В Си, как легко догадаться, при этом копируется УКАЗАТЕЛЬ, а не содержимое. Для копирования содержимого нужно явно копировать при помощи strcpy() или memcpy(), если желаешь. То есть ровно как в Яве, при присваивании объект НЕ КОПИРУЕТСЯ, за исключением строк. Вот в Си даже строки так НЕ КОПИРУЮБТСЯ. Ок?