2014-01-06 102 views
3

用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 *的時候可以得到相同的的funcionality,而不是無效**

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->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。

回答

0

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

此外,您的地址計算不考慮指針算術。 a->data是一個指針(void *),因此(a->size - 1)*a->element_size偏移量將乘以指針的大小(void *)。 由於void沒有大小,因此將a->data設置爲void *會導致編譯器錯誤。

如果你真的想這樣做,更好的聲明a->data作爲char *,這是保證有一個大小爲1

當心:訪問您的陣列將需要強制轉換爲(element*)。這會阻止你使用方括號。
您將不得不提供一個訪問函數,如 void * array_at(size_t index) { return &a->data[index*a->element_size]; }
然後調用者必須將resutl投射到element *

創建一個動態數組element s直接對我來說似乎更實際。
如果需要,您仍然可以撥打realloc

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

這並不像您想象的那樣節省內存,因爲反覆調用realloc()會強調內存分配程序,浪費時間進行復制,甚至可能會碎片化堆,甚至比個別的集合還要多。

0

使用void *作爲數據數組註釋代碼的最後部分。代碼應該可以工作,但它有問題:

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

你也無法對void進行指針運算,但某些編譯器允許它。

的memcpy的正確版本將

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