簡體   English   中英

帶有void指針的動態數組

[英]Dynamic array with void pointer

所以在C和我學習指針認為,作為一個練習,我可以做一些通用數組,我得到它使用void **這樣:

struct array{
    void **data;
    size_t size, capacity;
};

插入這樣的元素:

void array_append(array *a, void *element){
    if(a->size == a->capacity){
        a->capacity += ARRAY_GROW_CONSTANT;
        a->data = realloc(a->data, sizeof(void*)*a->capacity);
    }
    a->data[a->size++] = element;
}

但這並不是很好。 該數組存儲指向元素的指針,因此當元素的范圍結束時,它變為無效,並且它還使數組的內容分散在整個內存中。 我認為這可以通過分配元素本身來解決

a->data[a->size++] = element;

我會做點什么的

a->data[a->size] = malloc(inserted_element_size);
memcpy(a->data[a->size], &element, inserted_element_size);
size++;

但我認為當使用普通的void *而不是void **時我可以獲得相同的功能

struct array{
    void *start;
    size_t element_size, size;
};

和插入元素

void array_append(array *a, void *element){
    a->size += 1;
    a->data = realloc(a->data, (a->size*a->element_size));
    memcpy(a->data + (a->size - 1)*a->element_size, &element, a->element_size);
}

但這導致了段錯誤,我不知道為什么。 據我所知(顯然我沒有),指針是內存中的地址,所以如果我有一個連續的內存塊,我可以用偏移量存儲任何類型的變量。

編輯:謝謝你的解釋,它確實有幫助。

什么是a->數據初始化為?

我使用函數初始化數組,並將a->data初始化為element_size。

調用者必須將resutl轉換為元素*

我以為我可以使用宏來縮短輸入(我認為這是一件壞事嗎?),但我不知道從void*struct*的類型轉換的性能。

直接創建動態數組元素對我來說更實用。

但這不允許我將數組用作通用數組? 我想要的是定義一個可以用來存儲任何類型的通用數組,比如

array *a1 = create_array(sizeof(int)); // array of int
array *a2 = create_array(sizeof(double)); // array of double
etc...

為什么要將數據存儲在連續的塊中?

因為我認為你需要一個連續的內存塊來使用帶偏移量的memcpy。

什么是a->data初始化為? 為此,在創建(空)數組時應將其設置為NULL。

此外,你解決計算不考慮指針算術。 a->data是一個指針(對於void *),因此(a->size - 1)*a->element_size offset將乘以指針的大小(to void *)。 a->data設置為void *應該會導致編譯器錯誤,因為void沒有大小。

如果你真的想這樣做,最好將a->data聲明為char * ,保證大小為1。

注意:訪問您的數組將需要轉換為( element* )。 這將阻止您使用方括號。
您必須提供一個訪問函數,如void * array_at(size_t index) { return &a->data[index*a->element_size]; } void * array_at(size_t index) { return &a->data[index*a->element_size]; }
然后調用者必須將resutl轉換為element *

直接創建一個動態的element數組似乎對我來說更實用。
如果需要,您仍然可以在其上調用realloc

但是我想到的第一個問題是:為什么要將數據存儲在連續的塊中?

這不像你想象的那樣具有內存效率,因為重復調用realloc()會給內存分配器帶來壓力,浪費時間進行復制,甚至可能使堆碎片甚至超過單個malloc的集合。

使用void *作為數據數組來評論代碼的最后部分。 代碼應該工作,但它有問題:

您正在傳遞元素指針的地址,而不僅僅是指針本身,它已指向正確(希望)數據。

你也不能在void上做指針算術,但是某些編譯器允許它。

memcpy的正確版本將是

memcpy ( ( unsigned char* )a->data + (a->size - 1)*a->element_size, element, a->element_size);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM