到目前為止有三個主要函數。
void free_all_register_address(void); // 釋放
void register_address(void *address); // 標記
void new_1d(void **ptr, int length, int type_side); // 分配
分別負責 釋放、標記、分配 這三個部分。
它們可以構成最基礎的需求,但這並不足夠。
我們需要加入更多的功能,去滿足更多的需求。
先想一下使用者(程式員)還有什麼需求。
透過 new_1d
分配後,地址被記錄並在程式結束後自動釋放,
若果自行加入 free()
,被記錄地址依舊會在結束後再次被釋放,
觸發雙重釋放的問題。
所以我們需要在手動釋放時,在 address_pool
中刪除被記錄地址。
即 register_address
的相反行為 —— 註銷地址。
void deregist_address(void *address) {
/*用於取得記憶體地址池的資料*/
void ***address_pool = NULL;
int *index;
/*取得記憶體地址池的資料*/
connect_address_pool(&address_pool, &index);
/*遍歷 address_pool 的空間*/
for (int i = 0; i < *index; i++) {
/*具體註銷工作*/
if ((*address_pool)[i] == address) { //尋找對應的記憶體地址
(*address_pool)[i] = NULL; //註銷註冊
break; //減少迴圈開支
}
}
}
如果之前的文章都有看的話,絕對會明白,不廢話了。
void early_free(void *address) {
deregist_address(address);
free(address);
}
代碼很短,就是 釋放 和 註銷。(次序不影響)
以上同理,如果自行調用 realloc()
去改變空間大小,
返回的地址若果不相同,會同時造成 內存洩漏 及 雙重釋放 。
洩漏了新地址,雙重釋放了舊地址。
這裏牽涉到 realloc()
的特性,
可參看 Days 9: 動態記憶體分配:malloc()、calloc()、realloc()、free(),內存洩露。
void re_1d(void **ptr, int length, int type_side){
/*重新分配記憶體*/
void *temp_ptr = NULL; //中轉指標
temp_ptr = realloc(*ptr, length * type_side);
/*對realloc分配記憶體的錯誤檢測*/
if (temp_ptr == NULL) { //內存不足,記憶體分配失敗
/*錯誤處理*/
}
/*分配後地址不相同*/
if (temp_ptr != *ptr) {
deregist_address(*ptr); //註銷註冊
register_address(temp_ptr); //重新登記
}
/*成功建立的空間分配給ptr*/
*ptr = temp_ptr; //取得中轉指標的地址
}
分配後地址不相同,就註銷 舊地址,註冊 新地址。
int *ptr = NULL;
new_1d(&ptr, 5, sizeof(int));
re_1d(&ptr, 10, sizeof(int));
early_free(ptr);