<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                首先回顧以下,在array.h中,UNSET類型是一個宏: ~~~ #define DATA_UNSET \ data_type_t type; \ buffer *key; \ int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \ struct data_unset *(*copy)(const struct data_unset *src); \ void (* free)(struct data_unset *p); \ void (* reset)(struct data_unset *p); \ int (*insert_dup)(struct data_unset *dst, struct data_unset *src); \ void (*print)(const struct data_unset *p, int depth) typedef struct data_unset { DATA_UNSET; } data_unset; ~~~ 使用宏DATA_UNSET,這樣可以方便其他類型在定義中直接引用DATA_UNSET宏來模擬繼承。在宏DATA_UNSET中,定義了下面五個函數指針: ~~~ struct data_unset *(*copy)(const struct data_unset *src); void (* free)(struct data_unset *p); void (* reset)(struct data_unset *p); int (*insert_dup)(struct data_unset *dst, struct data_unset *src); void (*print)(const struct data_unset *p, int depth) ~~~ 這些函數指針相當于UNSET的成員函數,其他類型可以通過對這五個指針賦值來實現成員函數的重寫(Overwrite)。每種類型都配有自己特有的初始化函數,在這些初始化函數中,對上面這五個函數指針進行賦值。 作者很巧妙地用面向對象的思想來組織C代碼。 我們可以實例性地看下STRING類型的初始化函數(data_string.c): ~~~ data_string *data_string_init(void) { data_string *ds; ds = calloc(1, sizeof(*ds)); //分配的空間會自動清零 assert(ds); /* 初始化數據成員,buffer_init用來分配內存空間 */ ds->key = buffer_init(); ds->value = buffer_init(); /* 成員函數,對函數指針賦值 */ ds->copy = data_string_copy; ds->free = data_string_free; ds->reset = data_string_reset; ds->insert_dup = data_string_insert_dup; ds->print = data_string_print; ds->type = TYPE_STRING; return ds; } ~~~ array.h中,各個數據類型的標志的定義: ~~~ typedef enum { TYPE_UNSET, /* 數據的類型未設置, 這幾種數據類型使用了面向對象的設計思想, 這個類型相當于父類型 */ TYPE_STRING, /* 字符串類型 */ TYPE_COUNT, /* COUNT類型 */ TYPE_ARRAY, /* 數組類型 */ TYPE_INTEGER, /* 整數類型 */ TYPE_FASTCGI, /* FASTCGI類型 */ TYPE_CONFIG /* CONFIG類型 */ } data_type_t; ~~~ 除了UNSET類型,其他類型的操作函數的實現都在文件data_XXX.c中。這七個類型構成了通用數組所要處理的類型。 為何叫做通用數組呢? 因為在數組的定義和實現中只使用UNSET類型,基于上面的定義,通用數組可以不用關心數組中存儲的到底是哪種具體的類型,只需將其按照UNSET類型來處理就可以了,所以說是通用的。 下面這個定義是通用數組的核心定義: ~~~ typedef struct { /* UNSET類型的指針型數組,存放數組中的元素 */ data_unset **data; /* 按 data 數據的排序順序保存 data 的索引 */ size_t *sorted; size_t used; /* data中已經使用了的長度,也就是數組中元素個數 */ /* data的大小。data的大小會根據數據的多少變化,會為以后的數據預先分配空間 */ size_t size; /* 用于保存唯一索引,初始為 0,之后遞增 */ size_t unique_ndx; /* 比used大的最小的2的倍數。也就是離used最近的且比used大的2的倍數 ,用于在數組中利用二分法查找元素*/ size_t next_power_of_2; /* data is weakref, don't bother the data */ /* data就是一個指針,不用關系其所指向的內容 */ int is_weakref; } array; ~~~ sorted(圖中僅展示data_unset中的key): ![這里寫圖片描述](https://box.kancloud.cn/2016-02-25_56ceaefa62429.jpg "") 還有一個定義: ~~~ typedef struct { DATA_UNSET; array *value; } data_array; ~~~ 它定義了一個array類型的數據,也就是說,通用數組中存放的數據可以是通用數組,這樣可以形成多維的通用數組。 在array.h中定義了如下的通用數組操作函數: 1、array *array_init(void); 初始化數組,分配空間。 2、array *array_init_array(array * a); 用數組a來初始化一個數組。也就是得到一個a的深拷貝。 3、void array_free(array * a); 釋放數組。釋放所有空間。 4、void array_reset(array * a); 重置data中的所有數據(調用UNSET類型數據中的reset函數),并將used設為0。相當于清空數組。 5、int array_insert_unique(array * a, data_unset * str); 將str插入到數組中,如果數組中存在key與str相同的數據,則把str的內容拷貝到這個數據中。 6、data_unset *array_pop(array * a); 彈出data中的最后一個元素,返回其指針,data中的最后一個位置設為NULL。 7、int array_print(array * a, int depth); 打印數組中的內容。depth參數用于在打印多維數組時,實現縮進。 8、a_unset *array_get_unused_element(array * a, data_type_t t); 返回第一個未使用的數據,也就是used位置的數據,這個數據不在數組中,返回這個數據指針后,將data[unsed]設為NULL。可能返回NULL。 9、data_unset *array_get_element(array * a, const char *key); 根據key值,返回數組中key值與之相同的數據 10、data_unset *array_replace(array * a, data_unset * du); 如果數組中有與du的key值相同的數據,則用du替換那個數據,并返回那個數據的指針。如果不存在,則把du插入到數組中。(調用data_insert_unique函數) 11、 int array_strcasecmp(const char *a, size_t a_len, const char *b, size_t b_len); 這個函數并沒實現,僅僅給出了上面的定義。 12、void array_print_indent(int depth); 根據depth打印空白,實現縮進。 13、size_t array_get_max_key_length(array * a); 返回數組中最長的key的長度。 下面看看array_get_index函數: ~~~ /* * sorted數組是個下標數組,存放的是排好序的輸入元素的下標(見前面的圖), * 相當于一個排好序的數組。 * 利用sorted數組進行二分查找。 * 若找到,返回元素在data數組中的位置,并通過rndx返回 * 其在sorted數組中的位置。 * 若沒有找到,通過rndx返回此元素在sorted中的位置,并返回-1 */ static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) { int ndx = -1; int i, pos = 0; /* pos中存放的是元素在數組data中的位置 */ if (key == NULL) return -1; /* * 當data的空間不夠時,通用數組每次為data增加16個空間,第一次初始化時, * data的長度為16。因此,size始終是16的倍數。 * 而next_power_of_2是大于used最小的2的倍數,如used=5,那么 * next_power_of_2就等于8。 * 這樣,used始終大于等于next_power_of_2的1/2。 * * next_power_of_2類似于一個標桿,利用這個標桿進行二分搜索 * 可以減少很多出錯的幾率,也使程序更加易懂。 */ /* try to find the string */ for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) { int cmp; if (pos < 0) { pos += i; } else if (pos >= (int)a->used) { pos -= i; } else { /* 比較兩個元素的key值 */ cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used); if (cmp == 0) { /* found */ ndx = a->sorted[pos]; break; } else if (cmp < 0) { pos -= i; /* 所找數據在前半部分 */ } else { pos += i; /* 所找數據在后半部分 */ } } if (i == 0) break; } if (rndx) *rndx = pos; return ndx; } ~~~ 本數據結構的實現中,二分查找是一個特色,然后用sorted數組只對data中的數據的下標排序,也是一個很有用的技巧。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看