bsearch, bsearch_s

出自cppreference.com
在標頭 <stdlib.h> 定義
void* bsearch( const void *key, const void *ptr, size_t count, size_t size,
               int (*comp)(const void*, const void*) );
(1)
void* bsearch_s( const void *key, const void *ptr, rsize_t count, rsize_t size,
                 int (*comp)(const void *, const void *, void *),
                 void *context );
(2) (C11 起)
/*QVoid*/* bsearch( const void *key, /*QVoid*/ *ptr, size_t count, size_t size,
                    int (*comp)(const void*, const void*) );
(3) (C23 起)
/*QVoid*/* bsearch_s( const void *key, /*QVoid*/ *ptr, rsize_t count, rsize_t size,
                      int (*comp)(const void *, const void *, void *),
                      void *context );
(4) (C23 起)
1)ptr 所指向的數組中尋找等於 key 所指向的元素。該數組含 count 個大小為 size 字節的元素,並且已相對於 key 劃分,也就是說,所有比較小於關鍵目標的元素必須出現於所有比較等於的元素之前,而且所有比較等於關鍵目標的元素要出現於所有比較大於關鍵目標的元素之前。完全排序的數組滿足這些要求。用 comp 所指向的函數比較元素。若數組未依照與 comp 標準相同的相對於 *key 的升序劃分,則行為未定義。
2)(1) ,除了傳遞給 comp 額外狀態參數 context ,並在運行時檢測下列錯誤,並調用當前安裝的約束處理函數:
  • countsize 大於 RSIZE_MAX
  • keyptrcomp 是空指針(除非 count 為零)
同所有邊界檢查函數,bsearch_s(及對應的泛型宏)(C23 起),僅若實現定義 __STDC_LIB_EXT1__ 且用戶在包含 <stdlib.h> 前定義 __STDC_WANT_LIB_EXT1__ 為整數常量 1 才保證可用。
3,4) 分別等價於 (1)(2) 的泛型宏。令 T 為一個無限定的對象類型(包括 void)。
  • ptr 類型為 const T* ,則返回類型為 const void*
  • 否則,若 ptr 類型為 T* ,則返回類型為 void*
  • 否則行為未定義。
若抑制這些泛型函數之一的宏定義以訪問實際函數(例如使用 (bsearch)(bsearch_s) 或函數指針),則實際函數聲明 (1)(2) 變為可見。

若數組包含多個 comp 指示為與欲查找元素相等的元素,則結果返回的具體元素是未指定的。

直接使用實際函數 (1)(2) 是被棄用的。

(C23 起)

參數

key - 指向要查找的元素的指針
ptr - 指向要檢驗的數組的指針
count - 數組的元素數目
size - 數組每個元素的字節數
comp - 比較函數。如果首個參數小於 第二個,那麼返回負整數值,如果首個參數大於 第二個,那麼返回正整數值,如果兩個參數等價,那麼返回零。 將 key 傳給首個參數,數組中的元素傳給第二個。

比較函數的簽名應等價於如下形式:

int cmp(const void *a, const void *b);

該函數必須不修改傳遞給它的對象,而且在調用比較相同對象時必須返回一致的結果,與它們在數組中的位置無關。

context - 比較器的狀態(例如,對照序列),作為第三個參數傳遞給 comp

返回值

1) 指向與 *key 比較相等的指針,在找不到元素時返回空指針。
2)(1) ,除了在運行時約束違規時也返回空指針。
3,4) 分別同 (1)(2) ,除了 cv 限定得到調整。

註解

與名稱無關, C 和 POSIX 標準都未要求此函數用二分查找實現,也未保證任何複雜度。

與其他檢查邊界的函數不同, bsearch_s 不將零大小數組視作運行時約束違規,而是指出找不到元素(另一個接受零大小數組的函數是 qsort_s )。

bsearch_s 之前, bsearch 的用戶通常用全局變量表示比較器的狀態。

示例

#include <stdlib.h>
#include <stdio.h>

struct data {
    int nr;
    char const *value;
} dat[] = {
    {1, "Foo"}, {2, "Bar"}, {3, "Hello"}, {4, "World"}
};

int data_cmp(void const *lhs, void const *rhs) 
{
    struct data const *const l = lhs;
    struct data const *const r = rhs;

    if (l->nr < r->nr) return -1;
    else if (l->nr > r->nr) return 1;
    else return 0;
 
    // return (l->nr > r->nr) - (l->nr < r->nr); // 可行的简洁写法
    // return l->nr - r->nr; // 错误的简洁写法(若给出 INT_MIN 就会失败)
}

int main(void) 
{
    struct data key = { .nr = 3 };
    struct data const *res = bsearch(&key, dat, sizeof dat / sizeof dat[0],
                                     sizeof dat[0], data_cmp);
    if (res) {
        printf("No %d: %s\n", res->nr, res->value);
    } else {
        printf("No %d not found\n", key.nr);
    }
}

輸出:

No 3: Hello

引用

  • C17 標準(ISO/IEC 9899:2018):
  • 7.22.5.1 The bsearch function (第 258 頁)
  • K.3.6.3.1 The bsearch_s function (第 441-442 頁)
  • C11 標準(ISO/IEC 9899:2011):
  • 7.22.5.1 The bsearch function (第 355 頁)
  • K.3.6.3.1 The bsearch_s function (第 608-609 頁)
  • C99 標準(ISO/IEC 9899:1999):
  • 7.20.5.1 The bsearch function (第 318-319 頁)
  • C89/C90 標準(ISO/IEC 9899:1990):
  • 4.10.5.1 The bsearch function

參閱

在一個包含未指定類型的元素的範圍上進行排序
(函數) [編輯]
bsearch 的 C++ 文檔