本章中強調序列是本書中最有用的adt(abstact data type)之一,儘管序列的規格相對簡單,但可以用作陣列、鍊錶、棧、佇列和雙端佇列,實現這些資料結構的adt所需的設施通常都包含在序列中。前面這些基本是書中的原話,話不多說,上**。
seq.h
#ifndef seq_included
#define seq_included
#define t seq_t
typedef struct t *t;
extern t seq_new(int hint);
extern t seq_seq(void *x, ***);
extern
void seq_free(t *seq);
extern
int seq_length(t seq);
extern
void *seq_get(t seq, int i);
extern
void *seq_put(t seq, int i, void *x);
extern
void *seq_addlo(t seq, void *x);
extern
void *seq_addhi(t seq, void *x);
extern
void *seq_remlo(t seq);
extern
void *seq_remhi(t seq);
#undef t
#endif
seq.c
#include
#include
#include
#include "assert.h"
#include "seq.h"
#include "array.h"
#include "arrayrep.h"
#include "mem.h"
#define t seq_t
struct t
;t seq_new(int hint)
arrayrep_init(&seq->array, hint, sizeof(void *),
alloc(hint*sizeof(void *)));
return seq;
}t seq_seq(void *x, ...)
va_end(ap);
return seq;
}void seq_free(t *seq)
int seq_length(t seq)
void *seq_get(t seq, int i)
void *seq_put(t seq, int i, void *x)
void *seq_remhi(t seq)
void *seq_remlo(t seq)
void *seq_addhi(t seq, void *x)
if(--seq->head < 0)
seq->length++;
return ((void **)seq->array.array)[(seq->head+i)%seq->array.length]=x;
}static
void expand(t seq)
}
這本書在介紹資料結構這塊的介面設計基本類似,所以我覺得我們在學習的時候需要注意總結,看別人的**介面是如何設計的,引數設計成什麼樣,返回值是什麼型別。
我在做開發的時候,需求很明確,但是如何在實現需求的同時,寫出良好的**和實現清晰的設計邏輯,是個很大的問題,用超生游擊隊小品(暴露年齡了,哈哈)的話說「憋三天憋四天,憋出個海南島吐魯番」,到最後功能是實現了,但**實現混亂,冗餘,可讀性差,甚至自己都不想再看寫過的東西,這些都是缺乏設計的表現。
現在主要針對上面的截圖說一下我的理解
函式說明
t seq_new(int
hint)
arrayrep_init(&seq->array, hint, sizeof(void *),
alloc(hint*sizeof(void *)));
return seq;
}
建立乙個seq_t* 變數seq, 並分配hint*sizeof(void *)大小的單元格,如果hint=0,則預設建立16個單元格,即上圖中的結構,此時seq->length=0,seq->head=0, seq->array.length=16,seq->array.size=sizeof(void *), seq->array.array為alloc返回的首位址。
t seq_seq(void *x, ...)
va_end(ap);
return seq;
}
往已建立的seq裡面寫資料,採用可變引數形式va_list實現,用seq_addhi在seq尾部填充資料,seq->head值不變,seq->length長度遞增,比如書中的例子
name=seq_seq(「c」, 「ml」, 「c++」, 「icon」, 「awk」, null);
void seq_free(t *seq)
釋放序列,seq有seq_t *型別強制轉換為array_t*型別,然後通過array_free函式來釋放,我們看看為什麼seq可以轉換為array_t*來釋放,先看array_free的實現
// t 為array_t
void array_free(t *
array)
可以看到seq_t只比array_t多兩個非指標變數int length和 int head,上面函式中「1」可以將seq->array陣列釋放掉,」2」可以將seq釋放掉。
有必要說一下**片段seq[i] 127
((void
**)seq->
array
.array)[(seq->head+i)%seq->
array
.length]
;
這裡的void ** 是二級指標,從順序結構上看直接作用於最後的array,是將array轉換為void *型別的陣列,我們知道陣列位址可以賦值給指標變數,比如int a, int *b; b=a; 所以void ** 是void *型別的陣列,將array這段記憶體空間轉換為陣列後,可以直接用陣列序號來定位某個元素。
理解了之前圖中的資料結構,對於元素的增減就比較好理解了
void * seq_remlo(t seq);
void * seq_remhi(t seq);
void * seq_addlo(t seq, void * x);
void * seq_addhi(t seq, void * x);
最後說明一下expand函式,**如下
// 在add函式中有呼叫,當seq->length == seq->array.length時
// 證明已占用單元格數量與開闢的單元格數量相等,即所有單元格已全部占用,無剩餘空間,
// 如需要再加入資料,需要重新申請更大的空間
演化結構如下圖所示
c語言介面與實現
分類 程式設計 2006 04 13 21 57 7392人閱讀收藏 舉報 語言c 資料結構 c lua exception 書中對atom,list,stack,hashtable,set,ring,exception等都作了 相信看過這邊書後,你使用c程式設計的功力會大為提高。也許使用c 的朋友...
C語言介面與實現 Atom
原子 atom 這一資料結構的工作原理基本類似於拉鍊式雜湊表,每個原子對應唯一的字串,不同的原子對應的字串內容不同 用數學語言講就是在原子和字串之間建立了雙射 原子的特點有三個 其一,每個原子對應的字串是不可變的 其二,相同內容的字串只會儲存一次,節省了儲存空間 其三,比較兩個字串是否相同時不必知道...
《c語言介面與實現》讀後感
書中對atom,list,stack,hashtable,set,ring,exception等都作了 相信看過這邊書後,你使用c程式設計的功力會大為提高。也許使用c 的朋友會認為這些c 的標準模板庫都可以實現,因此對c封裝這些不屑一顧。但是即使是c 程式設計師,我相信你看過本書後,就不會這麼認為了...