Это похоже на ошибку в книге - она действительно объявляет новые переменные внутри l oop. (Подсказка: прежде чем публиковать книги по программированию, хотя бы сначала скомпилируйте код ...)
Но даже с исправленной ошибкой код написан наивно. Вот еще ошибки:
- Всегда
const
квалифицировать параметры массива, которые не изменены. - Всегда использовать
stdint.h
во встроенных системах. - Никогда не использовать маги c цифры, такие как
255
. В этом случае используйте UINT8_MAX
.
Выше приведен консенсус отраслевого стандарта. (Также требуется MISRA- C et c.)
Кроме того, наиболее правильным является использование size_t
вместо int
для размера массивов, но это больше проблема стиля примечание.
Кроме того, лучший алгоритм состоит в том, чтобы указатели указывали на минимальное и максимальное значения, найденные в массиве, а это означает, что мы получаем не только значения, но и их расположение в контейнере данных. Поиск местоположения является очень распространенным вариантом использования. Это примерно та же скорость выполнения, но мы получаем больше информации.
Так что, если мы попытаемся переписать это в какой-нибудь код, достойный книги, это будет выглядеть примерно так:
void find_min_max (const uint8_t* data, size_t size, const uint8_t** min, const uint8_t** max);
Немного сложнее для чтения и использования с указателями на указатели, но более мощный.
(Обычно мы бы микрооптимизировали указатели одного типа с restrict
, но в этом случае все указатели могут в конечном итоге указывать на один и тот же объект, поэтому это невозможно.)
Полный пример:
#include <stddef.h>
#include <stdint.h>
void find_min_max (const uint8_t* data, size_t size, const uint8_t** min, const uint8_t** max)
{
*min = data;
*max = data;
for(size_t i=0; i<size; i++)
{
if(**min > data[i])
{
*min = &data[i];
}
if(**max < data[i])
{
*max = &data[i];
}
}
}
Пример использования для P C: (обратите внимание, что int main (void)
и stdio.h
не должны использоваться во встроенных системах.)
#include <stdio.h>
#include <inttypes.h>
int main (void)
{
const uint8_t data[] = { 1, 2, 3, 4, 5, 4, 3, 2, 1, 0};
const uint8_t* min;
const uint8_t* max;
find_min_max(data, sizeof data, &min, &max);
printf("Min: %"PRIu8 ", index: %d\n", *min, (int)(min-data));
printf("Max: %"PRIu8 ", index: %d\n", *max, (int)(max-data));
return 0;
}
Разборка этого алгоритма поиска для ARM g cc -O3:
find_min_max:
cmp r1, #0
str r0, [r2]
str r0, [r3]
bxeq lr
push {r4, lr}
add r1, r0, r1
.L5:
mov lr, r0
ldr ip, [r2]
ldrb r4, [ip] @ zero_extendqisi2
ldrb ip, [r0], #1 @ zero_extendqisi2
cmp r4, ip
strhi lr, [r2]
ldr r4, [r3]
ldrbhi ip, [r0, #-1] @ zero_extendqisi2
ldrb r4, [r4] @ zero_extendqisi2
cmp r4, ip
strcc lr, [r3]
cmp r1, r0
bne .L5
pop {r4, pc}
Не самый эффективный код, очень интенсивный переход. Я думаю, что есть много возможностей для дальнейшей оптимизации, если целью является код библиотечного качества. Но тогда это еще и специализированный алгоритм, позволяющий находить как минимальные, так и максимальные значения и соответствующие им индексы.
Для небольших наборов данных, возможно, было бы разумнее сначала просто отсортировать данные, а затем просто извлечь минимальное и максимальное значения из отсортированы самые маленькие и самые большие показатели. Если вы планируете искать данные для других целей в другом месте кода, то сначала определенно отсортируйте их, чтобы можно было использовать двоичный поиск.