Ви не увійшли.
Загальні вимоги до скетчу:
1 Якщо приходить повідомлення в вигляді цислового масива не визначеної довжини (від 1 до до 5, наприклад: 1/24/35 або 759/ або1/0/245/657/841 або...) треба занесті відповідні числа у масив rArr. Ділянки масиву, що не отримали новид даних, повинні отримати 0.
2. після отриманя числовиго массина та розкладання його у rArr, потрібно викликати зовнішний void.
3. ящо у повідомленні є символи, що не належать числовому масиву, всі значення rArr потрібно перетворити у 0 і перейти до очикування наступного сповіщення.
Остання редакція filat18 (2025-08-05 13:58:48)
Неактивний
Ви намагаєтесь робити складно. Робіть просто.
1. просто приймайте символи в буфер. Коли приймете n - обробіть весь буфер зразу. Якщо буфер переповниться - ну, придумайте щось. Це помилка в даних.
2. обробка буфера. знаходите розділювачі полів, викусюєте частини з цифрами, перетворюєте в int. int кидаєте в масив.
Весь алгоритм.
Не треба придумувати байто@0bства на рівному місці. Не треба економити рядки коду. Не треба придумувати саморобні парсери. atoi нормально працює.
Неактивний
Мав меркування, що розділення на масив має буте швидше, ниж займатися розділом після отримання...
Но ті результати, що отримую та Ваші зауваження - підтвержують хибність моїх меркувань...
Неактивний
!? як що закоментувати позначений рядок - маю наступну відповідь, при однаковому сповіщєнні
Тому що rIndex=0 у вас не там де він повинен бути.
Але чи не простіше було б просто надрукувати уривок коду, що дійсно працює?
Та мабуть, простіше. Тільки розуміння того, що таке "дійсно працює", у нас з вами, мабуть, дуже різне.
Ось вам приклад. Написав якомога простіше, по-ардуінівськи. Ніякої обробки помилок у вхідних даних нема: що не влазить, те ігнорується, що atoi() повертає, те і записується. Обробка помилок на вході - то вже на ваc.
void setup()
{
Serial.begin(115200);
}
size_t idx { 0 };
size_t str_idx { 0 } ;
int data[10];
char str[7];
void push_number()
{
if (idx < sizeof(data)/sizeof(*data)) {
str[str_idx] = '\0';
data[idx++] = atoi(str);
}
}
void loop()
{
for (int c; (c = Serial.read()) != -1;)
{
switch (c) {
case '/':
push_number();
str_idx = 0;
break;
case '\n':
case '\r':
if (idx == 0 && str_idx == 0) {
break;
}
push_number();
for (size_t i = 0; i < idx; i++) {
Serial.print(F("data["));
Serial.print(i);
Serial.print(F("] = "));
Serial.println(data[i]);
}
idx = 0;
str_idx = 0;
break;
default:
if (str_idx < sizeof(str)/sizeof(*str) - 1) {
str[str_idx++] = c;
}
break;
}
}
}
Активний
розділення на масив має буте швидше, ниж займатися розділом після отримання...
Число операцій приблизно однакове. Розпихувати операції з розбором окремих полів має смисл, якщо одна велика операція в ваші обмеження не влізе. Ну, зробите це окремою функцією, будете викликати після кожного розділювача. Головне - не робити суперфункцій з суперциклами і глобальними суперзмінними. Робіть функції прості і зрозумілі.
Неактивний
UPD: запостив приклад до того як побачив ваші наступні повідомлення з описом задачі.
Ділянки масиву, що не отримали новид даних, повинні отримати 0.
Так обнуліть їх перед тим як передавати кудись той масив.
Якщо так вже кортить обнуляти весь масив перед отриманням нового рядка, то
memset(rArr, 0, sizeof(rArr));
Або, те ж саме:
for (auto &it : rArr) {
it = 0;
}
Або, те ж саме:
for (auto *p = rArr; p < rArr + sizeof(rArr)/sizeof(*rArr);) {
*p++ = 0;
}
Або, те ж саме:
for (size_t i = 0; i < sizeof(rArr)/sizeof(*rArr); i++) {
rArr[i] = 0;
}
Можна навигадувати ще багато способів обнулити масив в C++.
Активний
1 Якщо приходить повідомлення в вигляді цислового масива не визначеної довжини (від 1 до до 5, наприклад: 1/24/35 або 759/ або1/0/245/657/841 або...) треба занесті відповідні числа у масив rArr.
А якщо приходить більше ніж 5 чисел, решта має ігноруватись?
Чи потрібно передати 5 уже отриманих чисел, а решту розглядати як наступний рядок?
Чи весь такий рядок має ігноруватись до наступного?
2. після отриманя числовиго массина та розкладання його у rArr, потрібно викликати зовнішний void.
Спробую вгадати, що "викликати зовнішний void" - це передати масив у іншу функцію?
3. ящо у повідомленні є символи, що не належать числовому масиву, всі значення rArr потрібно перетворити у 0 і перейти до очикування наступного сповіщення.
Тобто ігнорувати цей рядок.
А якщо число 32768 чи більше, яке не влазить в AVR'івський int? Яке максимально допустиме значення, і що програма має робити зі значеннями, які його перевищують?
Активний
sizeof(data)/sizeof(*data)
Не люблю.
Не смію вам перешкоджати щось не любити, маєте на це повне право
І щось мені здається що там помилка
Аргументуйте, в чому саме помилка.
#define DATA_SIZE 10 int data[DATA_SIZE];
Просто і зрозуміло.
Просто і зрозуміло - це std::array та std::vector. А в ардуіно - що маємо, те маємо.
Активний
sizeof(data)/sizeof(data[0]) часто зустрічаю. Теж не люблю. А так.. Неочевидно трохи. Я здогадуюсь що в С масив і вказівник майже синоніми, і так теж можна. Але в такому записі легко допустити помилку, і компілятор її нормально пропустить. І фіг потім знайдете що не так
Неактивний
dimich, дякую за варіант коду - дуже цікаво! З затиранням даних зрозуміло. А от що цікаво: код дає різну кількість отриманих груп для повідомлення 4/5 і для 4/5/
Неактивний
Але в такому записі легко допустити помилку, і компілятор її нормально пропустить.
Компілятор взагалі багато чого нормально пропускає. Для того і потрібна прокладка між стільцем та клавіатурою.
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x)))
Або взагалі std::array без кофеіну:
template <typename T, size_t N>
struct array
{
T data[N];
constexpr size_t size() const noexcept { return N; }
};
А там можна і оператор [] перевантажити, і ітератори прикрутити.
Активний
А от що цікаво: код дає різну кількість отриманих груп для повідомлення 4/5 і для 4/5/
Так, тому що між розділювачем / та кінцем рядка пусто. atoi() для пустого рядка повертає 0.
Активний
Просто і зрозуміло - це std::array та std::vector. А в ардуіно - що маємо, те маємо.
Активний