Jump to content

    
Salamander

Как скопировать символы из обычного буфера в массив строк?

Recommended Posts

Господа, ситуация такая. Есть массив из 100 строк

char* strings_buffer[10]={"1","2","3","4","5","6","7","8","9","10"};

 

Есть массив из обычных байт, в который принимаются данные по UART

uint8_t rx_buffer[RX_BUFFER_SIZE] = {0,};

 

Когда ловится символ конца строки, то все содержимое rx_buffer с нулевого символа до того, где был пойман конец строки, должно копироваться в массив строк, точнее в один из его элементов под номером str_buffer_write_position.

Я не стал заморачиваться с классическим кольцевым буфером, так как длина принимаемых строк гарантированно не превышает RX_BUFFER_SIZE, после захвата последовательности r\n индекс записи просто переносится на нулевой элемент rx_buffer

for (uint8_t i=0;i<rx_write_buffer_position;i++) *strings_buffer[str_buffer_write_position]++=rx_buffer[i];

не работает, вылетает в хард (контроллер STM32)

Что я делаю не так?

Edited by Salamander

Share this post


Link to post
Share on other sites
char* strings_buffer[10]={"1","2","3","4","5","6","7","8","9","10"};

Это массив указателей на строки во флэш или озу ?


*strings_buffer[str_buffer_write_position]++ = rx_buffer[i];

Что тут хотели сделать ? Каша какая то.

22 minutes ago, Salamander said:

Что я делаю не так?

Не читаете книг. Не пользуетесь отладчиком.

Share this post


Link to post
Share on other sites
2 часа назад, Salamander сказал:

Когда ловится символ конца строки, то все содержимое rx_buffer с нулевого символа до того, где был пойман конец строки, должно копироваться в массив строк, точнее в один из его элементов под номером str_buffer_write_position.

Массив байт копируете в массив строк???  :wacko2:

Советую почитать учебник по си по теме "стандартные типы данных".

2 часа назад, Salamander сказал:

for (uint8_t i=0;i<rx_write_buffer_position;i++) *strings_buffer[str_buffer_write_position]++=rx_buffer[i];

не работает, вылетает в хард (контроллер STM32)

И правильно делает, потому что код выше пытается делать запись в одну из строк "1","2","3","4","5","6","7","8","9","10", которые слишком короткие для этого. А возможно что ещё и находятся во флешь.

Share this post


Link to post
Share on other sites
9 часов назад, Salamander сказал:

Есть массив из 100 строк

А у вас код из 10. И это не массив строк. Это массив указателей.

 

9 часов назад, Salamander сказал:

Что я делаю не так?

Вы делаете не так то, что объявляете массив указателей, а не строк. Соответственно, каждый элемент такого массива - 4 байта на архитектуре Cortex-Mx. И хранит такой элемент не строку (N байт), а всего лишь адрес из четырёх байт. При этом данные, на которыу указывает адрес могут быть вообще в разных участках разной памяти (NOR, FLASH, SRAM, SDRAM и т.п.).

 

Скомпилируйте свой проект без оптимизации, запустите отладчик и поглядите что у вас за типы данных. Вам станет всё понятнее.

Share this post


Link to post
Share on other sites
07.04.2021 в 08:09, MrBearManul сказал:

И это не массив строк. Это массив указателей.

Это массив из десяти строк.

const char *str[] = {"message 1", "message 2", "message 3"}; - это массив сообщений... или массив строк. Понятно, что char *str[] - это массив указателей, Hо на практике такой массив называют "массив строк" и это подразумевает, что каждый эл-нт массива есть указатель на char и в 32-х битной архит-ре каждый эл-нт занимает 4 байта и каждый элемент указывает на строку. Двумя словами - массив строк.

06.04.2021 в 22:21, Salamander сказал:

for (uint8_t i=0;i<rx_write_buffer_position;i++) *strings_buffer[str_buffer_write_position]++=rx_buffer[i];

не работает, вылетает в хард (контроллер STM32)

Что я делаю не так?

1) "5" - строковая константа константная строка. Никогда не пишите код char *str = "5"; По мойму, на это компилятор должен выдать ворнинг. Если инициализируете строкой указатель, то всегда пишите const char *str = "5"; Избежите много ошибок на этапе компиляции.

2) Даже, если массив строк в озу, то у вас длинна каждой строки в в массиве строк strings_buffer два байта. 4-ая строка состоит из символа '5' и символа '\0'.

Если индекс массива равен 4, т0 вы копируете 4 байта (судя по коду).

Вы первый раз в цикле for записали в *strings_buffer[4] = rx_buffer[0]. Хорошо. Перетерли символ '5'. *strings_buffer[4]++ - теперь этот указатель указывает на следующий символ, на символ '\0'.

Второй раз *strings_buffer[4] = rx_buffer[1]. Перетёрли символ '\0'. Строка "5" кончилась. Больше выделенной памяти для строки strings_buffer[4] нет.

Ещё инкримент *strings_buffer[4]++ - теперь этот указатель указывает за пределы строки "5". Далее, при попытки записать в *strings_buffer[4] = rx_buffer[j] будет неопределённое поведение. HF - получите и распишитесь.

3)Где, после копирования,  сброс указателя strings_buffer[4] на начало строки "5"?

4)Как вы скопируете массив байт в строку strings_buffer[0] таким кодом? Ведь для этого str_buffer_write_position должен быть равен 0, но тогда вы не разу не зайдете в тело for.

 

5)for (uint8_t i=0;i<rx_write_buffer_position;i++) *strings_buffer[str_buffer_write_position]++=rx_buffer;

Это что за дичь? Что такое str_buffer_write_position?

 

Может вам всетаки нужен не массив строк, а строка (или массив символов)?

char strings_buffer[10]={'1','2','3','4','5','6','7','8','9','0'};//строка "1234567890" в ОЗУ, размером в 10 байт/символов, без символа "конец строки" ('\0')
for (uint8_t i=0;i<rx_write_buffer_position;i++) 
  if(i < 10) //защита от выхода за границы строки strings_buffer
  	strings_buffer[i]=rx_buffer[i];

ps не путайте одинарные кавычки и двойные.

 

 

pps К моератору..... что сделали с редактором? Раньше, выделил текст, нажал "I" - в начале и в конче текста в окне редактора появились символы [_i_]     [\_i_]  - текст в окне редатора не наклонный, видны таги. После публикации таги не видны, текст наклонный. Сейчас в редакторе таги не видны, сразу наклон. По мне, так менее удобно, раньше было лучше. Но да бохсним... Это ИМХО ни кого не интересуещее.... но сейчас выделил несколько слов в середине текста, нажал I, - в окне редактора наклонились нужные слова. Опубликовал - наклонился ВЕСЬ текст после этого слова. Раз 5 уже переправлял сообщение из-за этого глюка.

ppps я понял в чем глюк. я хочу написать текст rx_buffer[тут "и" с точкой]. Т.е. если написать "эр Икс буффер итое, то индекс массива редактор воспринимает как открывающий таг наклонного текста. Мне кажется это косяк редактора, Как набрать текст "rx_buffer[j]", только вместо 'j' должна быть 'i'?

 

 

Edited by razrab83

Share this post


Link to post
Share on other sites
2 часа назад, razrab83 сказал:

ppps я понял в чем глюк. я хочу написать текст rx_buffer[тут "и" с точкой]. Т.е. если написать "эр Икс буффер итое, то индекс массива редактор воспринимает как открывающий таг наклонного текста. Мне кажется это косяк редактора, Как набрать текст "rx_buffer[j]", только вместо 'j' должна быть 'i'?

Просто оформляйте такое как блок кода. В нём тэги не обрабатываются.

Share this post


Link to post
Share on other sites
4 часа назад, jcxz сказал:

Просто оформляйте такое как блок кода. В нём тэги не обрабатываются.

что значит "блок кода"? Это то что раньше было обрамлено в [с0de] [\c0de]? Так такой блок кода будет в рамке, с подсветкой, с подсветкой индекса. У меня это не код с/с++, у меня это текст.... поспрашивал веберов - те накидали подобных костылей.

 

Например, в си/с++, строка пишется в обрамлении кавычек "это строка 123", но если текст строки должен включать кавычку, есть управляющие символы  "это строка \"123\"", где '\' - это управляющий символ.

В этом редакторе WysiBB (или другое, поправте), [и] - это управляющи таг. Но должны же быть какие-то способы, чтобы редактору сказать - "этот текст не воспринимай как таг, а просто как текст". Веберы такого не знают. Кто знает как редактору сказать что "[и]" - это текст?

Edited by razrab83

Share this post


Link to post
Share on other sites

2 ТС: язык С не занимается самостоятельным управлением динамической памятью. Строки (за исключением констант в программе) по своей природе сущности динамические, т.к. могут менять свой размер. Так что у вас 3 выхода:

  • Управлять памятью самому (malloc/free)
  • Выделить сразу массивы достаточного размера, и смериться с потерями памяти, если строки будут короче, и с ограничением на макимальную длинну строк
  • Сменить язык (например на С++ и std::string)

Share this post


Link to post
Share on other sites
1 час назад, razrab83 сказал:

что значит "блок кода"? Это то что раньше было обрамлено в [с0de] [\c0de]?

да.

Цитата

Так такой блок кода будет в рамке, с подсветкой, с подсветкой индекса. У меня это не код с/с++, у меня это текст....

Подсветку синтаксиса можно выключить - там есть соответствующий combobox:

"это строка \"123\""
"[и]" - это текст?

ку?

Share this post


Link to post
Share on other sites
42 минуты назад, jcxz сказал:

да.

Подсветку синтаксиса можно выключить - там есть соответствующий combobox:


"это строка \"123\""
"[и]" - это текст?

ку?

да так-то ку. можно сделать так "array[ i]" - тоже ку. Это всё костыли. Можно текст в ворде написать, вырезать ножницами скрин и сюда вставить картинку. Но интересно не как на этом форуме показать "[ i]", а как сказать вьюверу/редактору, что ЭТО НЕ УПРАВЛЯЮЩИЙ ТАГ наклонного текста? Как это делается правильно? Как, авторы этой разметки предусмотрели вывод текста "[ i]"? Через подобные костыли?

 

2 часа назад, xvr сказал:

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

....

Сменить язык (например на С++ и std::string)

Язык с++ тоже самостоятельно не занимается управлением динамической памятью. Этим занимаются всякие аля-контейнеры, например std::string/vector/.... Но контейнеры можно и на СИ организовать.

Edited by razrab83

Share this post


Link to post
Share on other sites
3 hours ago, razrab83 said:

Язык с++ тоже самостоятельно не занимается управлением динамической памятью. Этим занимаются всякие аля-контейнеры, например std::string/vector/.... Но контейнеры можно и на СИ организовать.

 

В языке С++ эти контейнеры входят в стандартную библиотеку. Причем настолько входят, что под неё были сделаны расширения в синтаксисе языка.

В С придётся писать самому, или брать какие то готовые со стороны.

 

Share this post


Link to post
Share on other sites

В общем я сделал вот так:

#define RX_BUFFER_SIZE 256

uint8_t rx_buffer[RX_BUFFER_SIZE];
char TERMINAL_TEXT[100][256];

for(uint8_t i=0;i<255;i++) TERMINAL_TEXT[str_buffer_write_position][i]=rx_buffer[i];

Работает.

Дальше мне понадобился скроллинг. То есть, есть 100 строк, появляется 101-я, я в цикле переписываю содержимое строки n+1 в строку n, и лишь потом пишу 101ю строку в ячейку №100.

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

   for(uint8_t i=0;i<100;i++) 
		{
			   for(uint8_t j=0;j<256;j++) TERMINAL_TEXT[i][j]=TERMINAL_TEXT[i+1][j]
       }	

Вопрос такой - сопряжен ли такой способ копирования с существенным замедлением быстродействия? 

Есть более быстрые способы?

Share this post


Link to post
Share on other sites
3 hours ago, Salamander said:

Вопрос такой - сопряжен ли такой способ копирования с существенным замедлением быстродействия?

Да. но насколько существенным зависит от процессора

 

Quote

Есть более быстрые способы?

Да. как минимум используйте функцию memmove - она оптимизирована для копирования массивов памяти.

Если надо ещё быстрее - делайте промежуточный массив указателей на строки -

char TERMINAL_TEXT_BUF[256][100];
char* TERMINAL_TEXT[256];

for(i=0;i<256;++i) TERMINAL_TEXT[i] = TERMINAL_TEXT_BUF[i];

Потом копируете указатели в TERMINAL_TEXT (не забудьте их зациклить по исходному массиву - иначе затрёте память)

 

Share this post


Link to post
Share on other sites
26 minutes ago, xvr said:

Потом копируете указатели в TERMINAL_TEXT (не

Идея не совсем понятна. 

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

А.. Погодите, кажется понял. Исходгэный буфер сделать кольцевым,  а массивом указателей по нему как бы скользить.  Чтобы последний элемент массива указателей всегда указывал на  только что обновлённый элемент исходного буфера? 

 

Ещё есть сопутствующие вопрос. Скажите а что происходит, если  при возникновении прерывания по приёму UART, оно успевает обработаться аппаратно, но не успевает программно? У меня пока что код скроллинг а находится в обработчике прерывания. Знаю, это не рационально, но скорость позволяла, между входящими посылка и времени достаточно.  Но иногда бывает, что приходит две посылки подряд.  Чтение из регистров UART я успеваю сделать, строку тоже успеваю, а вот когда идёт скроллинг - приходит следующая посылка. 

Выносить скроллинг за пределы обработчик прерывания? Хм... В принципе, с описанным вами вариантом кольцевого буфера это несложно. 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.