Перейти к содержанию
    

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

Господа, ситуация такая. Есть массив из 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)

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

Изменено пользователем Salamander

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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", которые слишком короткие для этого. А возможно что ещё и находятся во флешь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

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

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

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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'?

 

 

Изменено пользователем razrab83

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, jcxz сказал:

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

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

 

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

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

Изменено пользователем razrab83

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, razrab83 сказал:

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

да.

Цитата

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

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

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

ку?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

42 минуты назад, jcxz сказал:

да.

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


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

ку?

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

 

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

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

....

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

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

Изменено пользователем razrab83

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 hours ago, razrab83 said:

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

 

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

#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]
       }	

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 (не забудьте их зациклить по исходному массиву - иначе затрёте память)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

26 minutes ago, xvr said:

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

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

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

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...