2012-01-27 44 views
12

我正在嘗試使用雙void指針,但我對使用情況有點困惑。 我有一個struct包含一個void **陣列。如何正確使用void **指針?

struct Thing{ 
    void ** array; 
}; 

struct Thing * c = malloc (sizeof(struct Thing)); 
c->array = malloc(10 * sizeof(void *)); 

所以如果我想不同的對象分配給每個指針,並嘗試檢索值

// Option 1 
*(c->array + index) = (void *) some_object_ptr; 

// Option 2 
c->array[index] = (void *) some_object_ptr; 

然後,我還有一個功能,讓(void *) item指向每一個細胞,而不是some_object_ptr

如果我要找回它通過some_object_ptr指向值,
應該怎麼做

function return type is 'void *' and takes argument 'void *' 
// Option 3 
return (void**) item 

// Option 4 
return *((void**)item)? 

奇怪的是,當我使用數組的數組下標方法我不能使用選項4,只有選項3;當我使用*(c->array + index)時,我只能使用opt.4。而不是opt.3。 ..

任何人都可以請告訴我這個嗎?如果我做出任何無效的假設,那麼請你糾正我?

+1

你爲什麼用'無效*'工作?更糟糕的是,'void **'? – Kevin 2012-01-27 22:27:06

+10

也許他需要它? – 2012-01-27 22:29:21

+0

另外,選項3和4不一樣,3返回'void **',4返回'void *'。 '物品'究竟是什麼? – Kevin 2012-01-27 22:30:58

回答

18

A void **只是指向指向未指定類型內存的指針。您只能解除引用一次(因爲您無法取消引用void *)。但是,除此之外,它基本上與其他指針類型一樣。如果它對您有幫助,請使用與int *相同的方式來思考。

所以,在你的具體情況,我們有:

void** array; 
int arrayLen = 10; 
array = (void**)malloc(arrayLen * sizeof(void*)); 

some_type_t* some_object_ptr;  
// The following two assignment are equivalent since in C, 
// array[index] <=> *(array + index) 
array[index] = (void*)some_object_ptr; 
*(array + index) = (void*)some_object_ptr; 

然後array是指向整個陣列,而*array是指向第一個元素,因爲它相當於array[0]

+0

的單元格,然後當我返回時,我應該使用opt 3或選擇4?我有點困惑.. – 2012-01-27 22:36:03

+0

它取決於你想要返回。你想返回數組或數組中的第一個元素嗎?如果你有一個'int *數組;',你會'返回數組;'或'返回數組[0];'?這在這裏也是一樣的。 – 2012-01-27 22:38:52

+0

我想返回單元格中的內容,我認爲它是指向另一個對象的空指針,並且返回的部分處於不知道索引的不同函數中。相反,它被賦予void *項,它指向包含void指針的單元格 – 2012-01-27 22:42:18

1

你正在與void*void**工作的事實並不重要,指針運算仍然正常,所以你寫的兩個選項都是正確的。

下面是一個例子:

struct Thing 
{ 
    void ** array; 
}; 

struct Object 
{ 
    int i; 
    char c; 
}; 

int main() 
{ 

    struct Thing * c = malloc (sizeof(struct Thing)); 
    c->array = malloc(10 * sizeof(void*)); 

    struct Object * o = malloc (sizeof(struct Object)); 
    o->i = 2; o->c = 'a'; 

    *(c->array + 2) = o; 

    printf("Object: i = %d, c = %c\n", ((Object*)c->array[2])->i, ((Object*)c->array[2])->c); 

    free(o); 
    free(c->array); 
    free(c); 
    return 0; 
} 

因爲它是void*你可以把有指針什麼的,只是不要忘了使用它之前轉換爲原始類型;)

+2

您不必投射malloc()的返回值。 C標準明確指出void *與任何*指針類型兼容。一些尊敬的C程序員,例如Linus Torvalds,以及像GNU這樣的企業都反對這種鑄造方式,並認爲這是不好的做法,因爲它降低了可讀性。 – 2012-01-27 22:38:07

+0

另外,指針運算與整數不一樣。 AFAIK GCC假定void *是一個字節ptr,例如在32位系統上,int是4個字節,所以(int *)ptr + 1將給出與(void *)ptr不同的存儲地址+ 1會。 – 2012-01-27 22:41:35

+0

對不起,我已經習慣於使用微軟Visual Studio,即使我用C編寫代碼。編譯器不會讓我寫malloc而不會將其轉換爲返回值...我編輯了我的答案 – LihO 2012-01-27 22:45:04

2

一個快速地暗示指針:如果你投了它,你可能做錯了什麼。

至於你的問題。我不確定item是什麼在你的問題。在你的第一部分中,你已經發現瞭如何訪問數組中的成員。你可以簡單地使用它:

void *get_item(Thing *c, int index) 
{ 
    return *(c->array + index); // or return c->array[index]; 
} 

如果在索引需要的指針的地址:

void **get_item_cell(Thing *c, int index) 
{ 
    return c->array + index; // or return &c->array[index]; 
} 

在第二部分中,你不取消引用指針(對於+選項),或取數組結果的地址,因爲它會自動解引用它。


編輯: 我想我現在知道你想要什麼。你有類似我上面的第二個中的功能,但它是:

void *get_item_cell(Thing *c, int index) 
{ 
    return (void *)(c->array + index); 
} 

你想取消引用這個函數返回的值,並訪問對象。在這種情況下,您只能安全使用選項4。既然你沒有索引,你不能移動到任何其他的單元格(你不知道你是否在數組的末尾,或者在開始時 - 因此沒有增加或減少)。您只能修復上述功能的錯誤:投射到void **,然後解除引用:*(void **)item。這會給你一個void *。如果要訪問此單元格指向的對象,則需要將其轉換爲正確的類型:some_object_ptr *obj = *(void**)item

+0

哦,所以返回的部分是在不同的函數中,它不知道索引和void * item指向單元格數組 – 2012-01-27 22:38:29

+0

只有我對你想要做的事情有所瞭解。如果你有指針對象(數組中的一個對象),並且想要返回到數組的索引或單元格,則必須循環遍歷每個單元格,檢查指針是否與你想要的那個,然後返回相關信息。如果這是你想要的,我可以將其添加到我的答案中。 – vhallac 2012-01-27 22:40:54

-1

全能推!

any_type x ; 
void * v = * (void * *) & x ; 

全能拉!

void * v ; 
any_type x = * (any_type *) & v ; 

提防輸球/獲得數字

+0

void * v = *(void **)&x;'超越'void * v =&x;'發揮了什麼作用? '&x'的轉換和解引用什麼都不做。*內存地址*沒有類型開始。 – 2016-03-06 10:30:08

+0

「*'any_type' *」當然?我只會說指針類型。 – alk 2016-03-06 10:58:03

+0

@ DavidC.Rankin:可以繞過C的限制,不允許將函數指針的值賦給「空」指針。 – alk 2016-03-06 10:59:26