Лучше Вы… Заодно по данному примеру пройтись, ведь у него элементы массива это структура…
Если Вам не сильно сложно…
Я бы сказал, что не так Вы сделали когда в функции compare преобразуете указатели на к commandLine *
, а зачем-то к uint16_t *
. Оно понятно, что первый элемент структуры там имеет тип uint16_t *
, но это говнокод. Преобразовывать надо к указателю на структуру и брать её элемент.
А вот это у меня и не получилось… Постоянно ошибки при компиляции…
Без Вашего разъяснения никак…
За основу брать код из №85 или другой какой?
Думаю да.
Сразу хотел написать что @ЕвгенийП за такой код всем по ж…е надаёт …
Хорошо, сегодня сделаю. Но без объяснения как работает qsort
- не прокатит, так что это займёт некоторое время. Возможно, я отдельным постом оформлю.
До этого я дошёл)) Но это же не всё… Впрочем, тут уже поговорили об этом
Я верю, что пятница «захлестнула» Евгения Петровича положительными эмоциями, а не то чтобы он забыл )
С другой стороны «сегодня» еще не закончилось ))
ЗЫ: Просто жду с нетерпением, простите.)
Как обещал.
Функция qsort
универсальная, она может отсортировать любой массив, состоящий из элементов любого типа с одним ограничением – элементы должны позволять присваивание друг другу путём побайтового копирования (для некоторых классов это иногда не выполняется).
Но, надо понимать, что она понятия не имеет, что именно она сортирует и ей просто неоткуда знать какой элемент должен в результате оказаться ближе к началу массива, а какой – к концу. Для этого программист должен предоставить функцию сравнения. Прототип функции выглядит так:
int
<function name> (const void
* a, const void
* b);
параметры – указатели на элементы массива (тип void
нужен для того, чтобы можно было не зависеть от конкретного типа, внутри функции их нужно преобразовать к нужному типу). qsort
, будет вызывать эту функцию много раз. А если точнее, то всякий раз, когда ей нужно понять какой из двух элементов должен стоять ближе к началу массива-результата.
Функция сравнения должна вернуть:
- число меньшее нуля, если элемент
a
должен стоять раньше элементаb
; - число большее нуля, если элемент
a
должен стоять позже элементаb
; - ноль, если пофиг как будут стоять элементы (они равны).
Это всё. Больше никакой магии. Дайте qsort
такую функцию сравнения и она отсортирует всё, что угодно.
Несколько примеров функций сравнения:
Пример 1. сортируем массив чисел типа int по возрастанию
static int compare(const void * _a, const void * _b) {
const int a = * reinterpret_cast<const int *>(_a);
const int b = * reinterpret_cast<const int *>(_b);
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
Для сортировки по убыванию достаточно поменять местами a
и b
в сравнениях
Пример 2. сортируем массив чисел типа int по убыванию
static int compare(const void * _a, const void * _b) {
const int a = * reinterpret_cast<const int *>(_a);
const int b = * reinterpret_cast<const int *>(_b);
if (b < a) return -1;
if (b > a) return 1;
return 0;
}
Кстати, в последнем стандарте С++ появился новый оператор сравнения <=>
, который сразу возвращает то, что нам нужно, но у нас пока этот стандарт не поддерживается.
Для сравнения строк есть замечательная функция strcmp
, которая сравнивает строки и возвращает именно то, что нужно qsort
. Поэтому программы сравнения строк выглядят проще, чем чисел.
При сравнении объектов типа структур, классов и т.п. просто преобразуем переданные указатели к указателям на нужные объекты и сравниваем объекты так как мы понимаем их сравнение (повторюсь, qsort
неоткуда знать, что у нас больше, а что меньше - она полностью полагается на нашу функцию сравнения). В примере программы будет четыре функции сравнения для структуры.
Вот
немного переделанная программа из поста №85
//
// Структура - как была у вас, только я добавил текстовое поле name,
// чтобы сортировать было веселее - хотел показать функцию сравнения строк.
//
struct commandLine {
uint16_t timeFromStart;
uint8_t deviceName;
bool onDevice;
uint16_t timeDeviceOn;
const char * name;
};
//
// Функция печати commandLine с указанием её индекса
//
void printCommandLine(const size_t index, const commandLine & cl, Print& p) {
p.print("cL[");
p.print(index);
p.print("]: ");
p.print("timeFromStart: ");
p.print(cl.timeFromStart);
p.print("; deviceName: ");
p.print(cl.deviceName);
p.print("; onDevice: ");
p.print(cl.onDevice);
p.print("; timeDeviceOn: ");
p.print(cl.timeDeviceOn);
p.print("; name: ");
p.println(cl.name);
}
//
// Функция сравнения для сортировки по полю name по алфавиту по возрастанию
// Для преобразования типа лучше использовать непосредственные преобразования
// а не универсальное в С-стиле, как использовали Вы. Я уже объяснял почему
//
static int compare1(const void * _a, const void * _b) {
const commandLine * a = reinterpret_cast<const commandLine *>(_a);
const commandLine * b = reinterpret_cast<const commandLine *>(_b);
return strcmp(a->name, b->name);
}
//
// Функция сравнения для сортировки по полю name по алфавиту по убыванию
//
static int compare2(const void * _a, const void * _b) {
const commandLine * a = reinterpret_cast<const commandLine *>(_a);
const commandLine * b = reinterpret_cast<const commandLine *>(_b);
return strcmp(b->name, a->name);
}
//
// Функция сравнения для сортировки по полю timeFromStart по возрастанию
//
static int compare3(const void * _a, const void * _b) {
const commandLine * a = reinterpret_cast<const commandLine *>(_a);
const commandLine * b = reinterpret_cast<const commandLine *>(_b);
if (a->timeFromStart < b->timeFromStart) return -1;
if (a->timeFromStart > b->timeFromStart) return 1;
return 0;
}
//
// Функция сравнения для сортировки по полю timeFromStart по убыванию
//
static int compare4(const void * _a, const void * _b) {
const commandLine * a = reinterpret_cast<const commandLine *>(_a);
const commandLine * b = reinterpret_cast<const commandLine *>(_b);
if (b->timeFromStart < a->timeFromStart) return -1;
if (b->timeFromStart > a->timeFromStart) return 1;
return 0;
}
void setup() {
Serial.begin(9600);
//
// Структуру лучше инициализировать по именам полей
// инициализация по порядку следования (как было у вас) чревата тем,
// что Вы в какой-то момент чуть поменяете структуру а про это место забудете
// вот и "приехали"
//
commandLine formovka[] = {
{ .timeFromStart = 17, .deviceName = 2, .onDevice = true, .timeDeviceOn = 170, .name = "Dedka" },
{ .timeFromStart = 8, .deviceName = 3, .onDevice = true, .timeDeviceOn = 88, .name = "Babka" },
{ .timeFromStart = 5, .deviceName = 2, .onDevice = true, .timeDeviceOn = 55, .name = "Vnuchka" },
{ .timeFromStart = 10, .deviceName = 3, .onDevice = true, .timeDeviceOn = 100, .name = "Zhuchka" },
{ .timeFromStart = 21, .deviceName = 2, .onDevice = true, .timeDeviceOn = 210, .name = "Koshka" },
{ .timeFromStart = 13, .deviceName = 3, .onDevice = true, .timeDeviceOn = 130, .name = "Myshka" }
};
//
// Размер элемента и количество элементов
//
constexpr size_t nElementSize = sizeof(commandLine);
constexpr size_t nElements = sizeof(formovka) / nElementSize;
//
// Печать массива структур до всякой сортировки
//
Serial.println("No Sorting");
for (size_t i = 0; i < nElements; i++) printCommandLine(i, formovka[i], Serial);
Serial.println();
//
// Сортировка по полю name по возрастанию и печать массива структур
//
qsort(formovka, nElements, nElementSize, compare1);
Serial.println("Sort by name ascending");
for (size_t i = 0; i < nElements; i++) printCommandLine(i, formovka[i], Serial);
Serial.println();
//
// Сортировка по полю name по убыванию и печать массива структур
//
qsort(formovka, nElements, nElementSize, compare2);
Serial.println("Sort by name decending");
for (size_t i = 0; i < nElements; i++) printCommandLine(i, formovka[i], Serial);
Serial.println();
//
// Сортировка по полю timeFromStart по возрастанию и печать массива структур
//
qsort(formovka, nElements, nElementSize, compare3);
Serial.println("Sort by timeFromStart ascending");
for (size_t i = 0; i < nElements; i++) printCommandLine(i, formovka[i], Serial);
Serial.println();
//
// Сортировка по полю timeFromStart по убыванию и печать массива структур
//
qsort(formovka, nElements, nElementSize, compare4);
Serial.println("Sort by timeFromStart decending");
for (size_t i = 0; i < nElements; i++) printCommandLine(i, formovka[i], Serial);
Serial.println();
}
void loop() { }
}
Результат её работы в мониторе порта
No Sorting
cL[0]: timeFromStart: 17; deviceName: 2; onDevice: 1; timeDeviceOn: 170; name: Dedka
cL[1]: timeFromStart: 8; deviceName: 3; onDevice: 1; timeDeviceOn: 88; name: Babka
cL[2]: timeFromStart: 5; deviceName: 2; onDevice: 1; timeDeviceOn: 55; name: Vnuchka
cL[3]: timeFromStart: 10; deviceName: 3; onDevice: 1; timeDeviceOn: 100; name: Zhuchka
cL[4]: timeFromStart: 21; deviceName: 2; onDevice: 1; timeDeviceOn: 210; name: Koshka
cL[5]: timeFromStart: 13; deviceName: 3; onDevice: 1; timeDeviceOn: 130; name: Myshka
Sort by name ascending
cL[0]: timeFromStart: 8; deviceName: 3; onDevice: 1; timeDeviceOn: 88; name: Babka
cL[1]: timeFromStart: 17; deviceName: 2; onDevice: 1; timeDeviceOn: 170; name: Dedka
cL[2]: timeFromStart: 21; deviceName: 2; onDevice: 1; timeDeviceOn: 210; name: Koshka
cL[3]: timeFromStart: 13; deviceName: 3; onDevice: 1; timeDeviceOn: 130; name: Myshka
cL[4]: timeFromStart: 5; deviceName: 2; onDevice: 1; timeDeviceOn: 55; name: Vnuchka
cL[5]: timeFromStart: 10; deviceName: 3; onDevice: 1; timeDeviceOn: 100; name: Zhuchka
Sort by name decending
cL[0]: timeFromStart: 10; deviceName: 3; onDevice: 1; timeDeviceOn: 100; name: Zhuchka
cL[1]: timeFromStart: 5; deviceName: 2; onDevice: 1; timeDeviceOn: 55; name: Vnuchka
cL[2]: timeFromStart: 13; deviceName: 3; onDevice: 1; timeDeviceOn: 130; name: Myshka
cL[3]: timeFromStart: 21; deviceName: 2; onDevice: 1; timeDeviceOn: 210; name: Koshka
cL[4]: timeFromStart: 17; deviceName: 2; onDevice: 1; timeDeviceOn: 170; name: Dedka
cL[5]: timeFromStart: 8; deviceName: 3; onDevice: 1; timeDeviceOn: 88; name: Babka
Sort by timeFromStart ascending
cL[0]: timeFromStart: 5; deviceName: 2; onDevice: 1; timeDeviceOn: 55; name: Vnuchka
cL[1]: timeFromStart: 8; deviceName: 3; onDevice: 1; timeDeviceOn: 88; name: Babka
cL[2]: timeFromStart: 10; deviceName: 3; onDevice: 1; timeDeviceOn: 100; name: Zhuchka
cL[3]: timeFromStart: 13; deviceName: 3; onDevice: 1; timeDeviceOn: 130; name: Myshka
cL[4]: timeFromStart: 17; deviceName: 2; onDevice: 1; timeDeviceOn: 170; name: Dedka
cL[5]: timeFromStart: 21; deviceName: 2; onDevice: 1; timeDeviceOn: 210; name: Koshka
Sort by timeFromStart decending
cL[0]: timeFromStart: 21; deviceName: 2; onDevice: 1; timeDeviceOn: 210; name: Koshka
cL[1]: timeFromStart: 17; deviceName: 2; onDevice: 1; timeDeviceOn: 170; name: Dedka
cL[2]: timeFromStart: 13; deviceName: 3; onDevice: 1; timeDeviceOn: 130; name: Myshka
cL[3]: timeFromStart: 10; deviceName: 3; onDevice: 1; timeDeviceOn: 100; name: Zhuchka
cL[4]: timeFromStart: 8; deviceName: 3; onDevice: 1; timeDeviceOn: 88; name: Babka
cL[5]: timeFromStart: 5; deviceName: 2; onDevice: 1; timeDeviceOn: 55; name: Vnuchka
Как видите, в каждом из четырёх случаев сортируется именно так, как прописано в функции сравнения.
Всё понятно? Или остались вопросы?
Нет не забыл, просто сегодня у меня было занятие в внучкой, как закончили и она ушла (около 19:20), я занялся этим.
Сегодня она из вот такой головки, горстки резисторов и батарейки делала “омметр” до 10кΩ. Второй день уж расчёт мучила. В прошлую пятницу так и не рассчитала, сегодня, вроде, получилось.
Отчаянно. Батарея же разряжается, за неделю так точно. Надеюсь в норму радиолюбителей (+/-15%) уложилась
Ну, она же не собирается этим прибором реально пользоваться - собрала на макетке, попробовала подсунуть несколько резисторов, убедилась, что работает. На это батарейки хватило.
И да, кстати, Ц-шки всю жизнь так работали (головка-то от Ц-шки) и ничего, “диды пользовались” – меняли батарейки когда надо.
Я почему об этом написал.
Купил весной НОВЫЕ батареи типа «крона». Две штуки. Распечатал, проверил напряжение - на первый было 8.8В, на второй 8.7В. Хорошо. Одну (что 8.8В) отложил, вторую поставил в прибор (пользуюсь по 15-20 секунд в неделю, да даде есть 5 минут). Потребления в простое нет вообще (выключатель полностью разрывающий сразу оба контакта). Прошло время - прибор не запускается. Меряю напряжение - 6.7В (не достаточно прибору). Беру «запасную» - на ней 5.9В …. (((
ЗЫ: Батареи марки «Космос», покупал на озон.
Да, я тоже сталкивался с проблемами с этим брэндом. В последнее время стараюсь брать GP – нормальные и цена не космическая.
А я, видимо дурак, для таких целей 18650 на 2200ма*ч купил и плату к нему (сразу с dc-dc)…)))
Правда еще не монтировал. Только получил сегодня акб. Думаю «большеват», но не выкидывать же?))
Не сказать, что всё понятно. На данный момент достаточно того, что изящно и при этом работает)
Спасибо! Закрываю тему?
Так именно про это я и говорю “рассчитала” и “получилось”. Просто заставить стрелку качаться много ума не надо.
А что это был за прибор? Я головку не узнал…