Я сделаю определенное предположение (на основании обоснованного предположения, которое я бы сказал):
nmemb
- это число членов массива width
- эторавно sizeof(array[0])
base
указывает на первый член массива, т.е. , base == array[0]
- массив отсортирован (от наименьшего к наибольшемузначение)
Обратите внимание, что сдвиг вправо по сути представляет собой целочисленное деление (отбрасывает остаток, например , 3 >> 1 == 1
).
Функция принимаетследующие аргументы:
key
, указатель на const void base
, указатель на const void nmemb
, переменная size_t width
, переменная size_t compar
, (указатель) на функцию с двумя аргументами (2x указатель на const void
), которая возвращает int
Тот факт, что используются указатели на void
, позволяет функции быть независимой от размера элементов массива (и, следовательно, быть универсальной).
Теперь давайте построчно.
Цикл for
инициализирует nremain
как nmemb
и повторяется до nremain != 0
(или return
). И в конце цикла он делит nremain
на 2, округляя результат вниз (смещение вправо на 1).
p
объявляется как указатель на void
setпри базовом смещении на половину nremain
(количество рассматриваемых элементов массива) умноженное на width
. Таким образом, p
будет указывать на конец левой половины массива. Например, если в массиве 7 элементов, на первой итерации p
будет указывать на 4-й элемент. Приведение (char *) base
просто гарантирует, что добавлено правильное количество байтов, при условии, что width == sizeof(array[0])
, поскольку sizeof(char) == 1
.
compar
затем сравнивает p
с key
и в случае успеха p
возвращается.
Если p < key
, то base
устанавливается для следующего члена после элемента, на который указывает p
и 1 вычитаетсяот nremain
. Вот объяснение, связанное с Eric Postpischil : «Предыдущее присваивание p
эффективно разбивает массив на три части: элемент, на который указывает p
, элементы ранее, и элементы после этогоЧисло элементов ранее nremain>>1
, число точно в p
равно 1
, а число после него (nremain-1)>>1
. Например , если nremain
равно 12, частиимеют 6, 1 и 5 элементов. Вычитая 1 из nremain
в этот момент, вы гарантируете, что он будет правильно установлен шагом nremain >>= 1
для следующей итерации. "
Повтор.
Если мы не найдем значение и не выйдем из цикла for
(обратите внимание, что когда nremain == 1
в конце цикла nremain >> 1 == 0
), верните NULL
.
Возможно, я ошибаюсь в некоторых предположениях, поэтому вы захотите отработать код, изменив их;). Надеюсь, это поможет!