2013-07-21 70 views
1

我有一個數據結構,鏈表,它看起來像傳遞一個指針的指針VS傳遞一個指針初始化用C

struct listitem { 
    void* data; 
    struct listitem* next; 
}; 
typedef struct listitem listitem; 
typedef struct { 
    listitem* head; 
    pthread_rwlock_t lock; 
} linkedlist; 

我用一個指針到void *的數據,因爲我想使數據結構具有多態性,以便我可以將它用於幾個不同的應用程序。

要初始化列表(分配內存並初始化rw鎖),我將它傳遞給函數 init_list(..)。當我通過指針如下列表中,該程序掛起,每當我試圖名單上執行任何進一步的操作(如推一個項目的話):

int init_list(linkedlist* list /* borrowed - list to initialise (probably unallocated) */) { 
    list = (linkedlist*)calloc(1, sizeof(linkedlist)); // clear the memory, so that head is a null pointer 
    printf("Allocated memory\n"); 
    if (list == 0) { 
     perror("calloc failed on allocating memory for list"); 
     return 1; 
    } 
    printf("Initialising lock\n"); 
    pthread_rwlock_init(&list->lock, NULL); 
    return 0; 
} 
... 
linkedlist* ll; 
init_list(ll); 

這是我的理解是,上述清除ll指向的內存,並適當地初始化鎖的內存位置。然而,當我將指針傳遞給列表指針時,它一切正常(即,當我嘗試執行進一步的操作(例如獲取鎖並將項目推送到列表中)時,程序不會掛起)。我不明白爲什麼添加這個額外的間接層使其工作。無論我如何引用它們,我都認爲在實際內存位置上的操作是相同的?

即以下工作,而第一種方法不會:

int init_list(linkedlist** list /* borrowed - list to initialise (probably unallocated) */) { 
    *list = (linkedlist*)calloc(1, sizeof(linkedlist)); // clear the memory, so that head is a null pointer 
    printf("Allocated memory\n"); 
    if (list == 0) { 
     perror("calloc failed on allocating memory for list"); 
     return 1; 
    } 
    printf("Initialising lock\n"); 
    pthread_rwlock_init(&(*list)->lock, NULL); 
    return 0; 
} 
... 
linkedlist* ll; 
init_list(&ll); 

我無法解釋爲什麼第二個方法效果先不時。

就一般風格而言,這種方式常見嗎?或者有更好的,更常見的方式來初始化C中的數據結構?我是一個相對較新的C程序員,來自面向對象的語言,我期望在構造函數中做這樣的初始化,而且我很善良 - 試圖用C來複制這種風格,考慮它 - 可能不一定是合乎邏輯的?

回答

0

在第一種情況下,您將指針(ll)的副本壓入堆棧。你的代碼分配內存,我認爲sizeof(slinkedlist)是一個錯字,用0填充它,然後丟棄該副本。你的調用者永遠不會獲得更新的指針。初始化後打印ll的值。在第二個中,你將一個指針指向指針,指針被分配/初始化,當你返回你的調用者可以愉快地使用它。如果不是返回0或1,而是返回ll,並將返回值分配給調用方中的變量,則可以使用第一個版本。那將是一種功能風格。

+0

謝謝!我已更新我的代碼以返回指向已初始化鏈接列表的指針,而不是像當前那樣返回0或1。 – Froskoy

0

在第一個版本中,您正在做的是分配一個新內存,將其歸零並將其複製到list參數(由於C通過值發送參數,因此不會更改ll)。第二個版本有*list,其中列表是指向ll的指針,這意味着當您更改*list時,實際上您更改ll(與第一個版本不同)。