此代碼來自Zed Shaw 的Learn C The Hard Way。在練習 34 中,練習題之一是實作一個動態陣列,它只是一個包含在結構體中的指標陣列。
該結構如下所示:
typedef struct DArray {
int end;
int max;
size_t element_size;
size_t expand_rate;
void **contents;
};
要初始化其中之一,我們使用 DArray_create()
DArray *DArray_create(size_t element_size, size_t initial_max)
{
DArray *array = malloc(sizeof(DArray));
array->max = initial_max;
array->contents = calloc(initial_max, sizeof(void *));
array->end = 0;
array->element_size = element_size;
array->expand_rate = 300;
return array;
}
還有一個調整陣列大小的函式:
static inline int DArray_resize(DArray *array, size_t newsize)
{
array->max = newsize;
void *contents = realloc(array->contents, array->max * sizeof(void *));
array->contents = contents;
return 0;
}
還有一些我遺漏的記憶體檢查。
我的問題與方式calloc和realloc使用方式有關。第一個 callocDArray_create()分配給void **contents陣列結構中的雙指標,這對我來說很有意義,因為它是一個 void 指標陣列。
realloc inDArray_resize()然后調整記憶體大小,但使用void *contents單個指標,然后替換原來的雙指標。為什么這樣可以?我已經DArray_resize()使用單指標和雙指標進行了測驗,它們似乎都可以作業。如果原來calloc創建了一個void **指標,為什么可以將其realloc更改為void *指標?
uj5u.com熱心網友回復:
void *是一種特殊的指標。它可以與任何其他型別的資料指標相互轉換。
realloc接受并回傳void *。它不知道您的程式使用哪種指標。void *呼叫者必須在呼叫時將您的指標realloc轉換為 ,并將結果從void *. 這種轉換在 C 語言中非常普遍,它是自動完成的。
考慮對calloc.
array->contents = calloc(initial_max, sizeof(void *)); // <- returns void*
// gets converted to void**
calloc不創建void **指標。它回傳一個void *指標(就像realloc那樣)。呼叫者有責任將其轉換為所需的任何指標型別。轉換發生在賦值時,但如果需要,可以插入顯式轉換:
array->contents = (void **)calloc(initial_max, sizeof(void *));
回到realloc,同樣的事情發生在那里,只是這次使用了一個顯式的中間變數:
void *contents = realloc(array->contents, array->max*sizeof(void*)); // void* returned here
array->contents = contents; // converted to void** here
如果需要,您可以將轉換轉移到realloc呼叫的行。在哪里完成并不重要。
void **contents = realloc(array->contents, array->max*sizeof(void*)); // converted here
array->contents = contents; // assignment, no conversion
呼叫時也有隱式轉換array->contents 。 如果需要,您也可以在此處使用演員表:void*realloc
void **contents = (void**)realloc((void*)array->contents, array->max*sizeof(void*));
...或中間變數,或兩者兼而有之。雖然它并沒有真正增加程式的質量,所以通常不會這樣做。
uj5u.com熱心網友回復:
這是合法的,因為void *有一些特殊的規則。任何型別的物件指標(不是函式指標)T *都可以轉換為void*然后再回傳T*,結果應與原始指標相等。
還要記住,在沒有轉換的情況下realloc回傳。void *void *contents = realloc(...)
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/490435.html
下一篇:結構指標正在取消參考哪個記憶體?
