上一篇我們假設有這幾個函數:
void free_all_register_address(void);
void register_address(void *address);
void new_1d(void *ptr, int length, int type_side);
free_all_register_address(void)
是給 atexit() 註冊的,
用來釋放 free() 所有曾經分配空間的地址。register_address(void *address)
是用來註冊、記錄,是標記地址的函數,
曾經分配空間的地址。new_1d(void **ptr, int length, int type_side)
是取替 malloc()
用的,
上一篇弄了一個很粗略的實現:
void new_1d(void **ptr, int length, int type_side){
/*分配記憶體*/
*ptr = malloc(length * type_side);
/*紀錄地址*/
register_address(*ptr);
/*註冊 atexit() */
/*僅在程序第一次執行時呼叫 atexit() */
static int first_process = 1;
if (first_process) {
atexit(&free_all_register_address); //此函數只會被呼叫一次
first_process = 0; //第一次執行的標記
}
}
分三個部分,
第一,分配記憶體。
第二,紀錄 已經分配的記憶體空間 的地址。
第三,用 atexit() 進行註冊,僅一次。
有不少問題,但是完善它不是今天的目標。
今天要完善的是標記地址的函數,
即 void register_address(void *address);
標記地址需要空間,一個類型為void*
的陣列:
void (*address_pool)[];
而需要標記的地址不只一個,不可以宣告一個固定長度的陣列,必須動態:
void **address_pool = NULL;
int index = 0; //索引,指向目前可以儲存地址的空間
為了方便起見,目前 address_pool
被宣告為全域變數。
register_address
的結構void register_address(void *address){
/*擴大、重新分配用於儲存記憶體地址的空間*/
void **temp_ptr = NULL; //中轉指標
temp_ptr = (void**)realloc(address_pool, (index + 1) * sizeof(void*)); //擴大空間
/*對realloc分配記憶體的錯誤檢測*/
if (temp_ptr == NULL) {
/*錯誤處理*/
}
/*成功建立的空間分配給address_pool*/
address_pool = temp_ptr; //取得中轉指標的地址
/*註冊記憶體地址*/
address_pool[index] = address;
index++; //空間擴大、索引移位
}
第一,擴大空間。
擴大儲存地址的空間,用 中轉指標 + realloc() 。 可參看 Days 9
第二,檢測錯誤。
檢測 realloc() 的回傳,進行錯誤處理。
第三,分配成功建立的空間。
檢測沒有錯誤,把成功建立的空間(中轉指標)的地址分配給 address_pool 。
第四,註冊地址。
把傳入的參數 address,放入新擴大的空間( address_pool[index] )中,
索引 + 1,指向新的儲存地址的空間。
register_address( /*某個地址*/ );