我試圖實作一種集合庫的形式。在學習一門新語言時,我總是這樣做,因為它教了大部分語言細節。
所以,我從一種“通用”動態陣列開始。好吧,它并不是真正的通用,因為它只是保存指向實際資料的指標。但老實說,我并不完全明白,為什么我需要一個雙空指標。
在我的頭檔案中定義的 Vector 結構(我在頭檔案中宣告了每個方法和#include,但我在這里省略了它以保持代碼可讀性。我還省略了一些邊界檢查)
typedef struct {
size_t capacity; //the allocated capacity
size_t length; //the actual length
void **data; //here I don't fully understand, why I need a double pointer.
} Vector;
這是我的一些方法的實作,當我在結構中使用單個 void 指標時編譯器會抱怨,所以void *data不是void **data.
#include "utils.h"
const size_t INITIAL_SIZE = 16;
//Creates a new empty vector.
Vector *vec_new(void) {
printf("sizeof Vector is: %ld", sizeof(Vector));
Vector *vec = malloc(sizeof(Vector));
vec->length = 0;
vec->capacity = INITIAL_SIZE;
void *data = calloc(INITIAL_SIZE, sizeof(void*));
if(data == NULL) {
free(vec->data);
fprintf(stderr, "Error allocating memory.");
exit(EXIT_FAILURE);
}
vec->data = data;
return vec;
}
//This method appends the specified value at the end of the vector.
void vec_push(Vector *vec, void *data) {
if(vec->length == vec->capacity-1) {
vec_resize(vec);
}
vec->data[vec->length] = data;
vec->length = 1;
}
//gets the value at the specified index or NULL if index is out of bounds.
void *vec_get(Vector *vec, size_t index) {
return vec->data[index];
}
//Resizes the vector to 1.5x its current capacity.
void vec_resize(Vector *vec) {
vec->capacity *= 1.5;
void *data = realloc(vec->data, sizeof(void*) * vec->capacity);
if(data == NULL) {
free(vec->data);
fprintf(stderr, "Error allocating memory.");
exit(EXIT_FAILURE);
}
vec->data = data;
}
似乎這里是魔法發生的地方,我還不明白:
void *data = malloc(...);
vec->data = data;
Malloc/calloc 回傳一個 void 指標,所以我要么必須宣告一個實際型別,要么只使用回傳的 void 指標。所以第一行很清楚。
vec->data是,假設我沒有在結構定義中使用雙指標,(*vec).data據我所知。所以基本上這一行應該將一個 void 指標分配給一個 void 指標。
也許有人可以簡單地向我解釋一下,為什么一個 void 指標在這里是不夠的,或者我可能會誤解某些東西。
uj5u.com熱心網友回復:
但老實說,我并不完全明白,為什么我需要一個雙空指標。
首先是一些背景 - 也許您已經知道:
型別someType *的指標是指向某個型別的變數someType 或型別的變數陣列的指標someType。
型別someType **的指標是指向型別變數的指標someType *- 這意味著:指向型別變數的指標的指標someType。
型別void *的指標是指向任何東西的指標;因為編譯器不知道這個指標指向什么樣的元素,所以不可能直接訪問這樣的元素。
與此相反,已知型別的指標指向什么變數void **:它指向型別的變數void *。
為什么你需要void**在這個位置:
關鍵是以下幾行:
vec->data[vec->length] = data;
...
return vec->data[index];
在這些行中,代碼訪問資料vec->data點。由于這個原因,vec->data不能是但void *它必須是指標指向的資料型別。并且因為指向型別的指標,所以是這樣。xxx *xxxvec->datavec->datavoid *xxxvoid *xxx *void **
vec->data = data;
您的觀察是正確的:vec->datais of the typevoid **并且datais of the type void *。
原因是malloc()回傳一些記憶體并且編譯器不知道該記憶體中存盤了哪種資料。malloc()所以isvoid *和 not回傳的值void **。
在汽車行業中,您將使用這樣的顯式指標轉換:
vec->data = (void **)data;
該運算式(xxx *)y告訴編譯器指標y指向型別的某些資料xxx。所以(void **)告訴編譯器指標指向一個 type 的元素void *。
但是,在桌面應用程式中,您通常不會撰寫(void **).
uj5u.com熱心網友回復:
如果你有一個型別的指標
T *p1;
其中 T 是某個型別說明符,例如 void 然后指向此指標的指標將被宣告為
T **p2 = &p1.
在這個 calloc 的呼叫中
calloc(INITIAL_SIZE, sizeof(void*))
您將分配一個型別為 的指標陣列void *。該函式回傳一個指向已分配陣列的第一個元素的指標。所以你需要寫
void **data = calloc(INITIAL_SIZE, sizeof(void*));
為了更清楚,讓我們假設您需要動態分配一個整數陣列。在這種情況下,您將撰寫
int *data = calloc( INITIAL_SIZE, sizeof( int ) );
data因此,像*data您一樣取消參考指標int將更準確地獲得型別為已分配陣列的第一個元素的物件。
當陣列的元素具有型別時,然后像您必須void *取消參考指標一樣獲取該型別的指標(分配陣列的第一個元素)。因此,要使操作正確,指標應具有型別。data*datavoid *datavoid **
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/417886.html
標籤:
下一篇:需要幫助了解與cmake的鏈接
