2013-04-26 30 views
1

我有點困惑於如何通過引用傳遞函數指針?你如何傳遞C中的結構指針?

舉例來說,這裏的一些代碼,我已經寫了 (我沒有複製整個功能,只是它的一部分是相關的)

metadata * removeBlock(metadata *first) 
{ 

    metadata *temp = first; 
    if(first == NULL || first -> prev == NULL) 
     { 
      first -> in_use = 1; 
      first = NULL; 
      return temp; 
     } 
} 

我要的是,當函數返回,傳入的原始值應該設置爲NULL。 這裏是我如何調用函數,(這行代碼將從堆中的區域中拉出元數據結構,它工作正常,我已經調試並確保在此之後,結構實際上指向有效的元數據結構)

metadata *strct = ((metadata *)ptr - sizeof(metadata)); 
removeBlock(strct); 

但是,在此方法返回後,strct仍然是我在函數中傳遞它之前的值。我嘗試傳遞& strct,但這只是拋出了一個無效的轉換異常。傳遞結構作爲參數的最佳方式是什麼?

謝謝。

+1

C根本沒有'傳遞引用',它只有'傳值'。即使在傳遞指針時,它本質上也是'傳遞值'。 – 2013-04-26 01:22:52

+1

您的功能有問題。例如,如果'first == NULL',那麼繼續並嘗試設置'first-> in_use'來解引用NULL指針。 – Blastfurnace 2013-04-26 01:25:55

+0

我沒有任何情況下,當用戶傳入一個NULL,雖然這是一個好主意,以消除檢查,以便它永遠不會發生。謝謝。 – iamseiko 2013-04-26 01:38:45

回答

2

我不認爲你想要的是一個好的設計 - 如果你的函數的用戶希望指針設置爲空(爲什麼?),使用函數的返回值重置該值是有意義的。

無論如何,你會想要一個指針到一個指針,像這樣:

metadata* removeBlock(metadata** first) { 

    metadata* temp = *first; 
    if(temp == NULL) return temp; 

    if(temp->prev == NULL) { 
     temp->in_use = true; 
     *first = NULL; 
    } 
    return temp; 
} 

metadata* strct = ((metadata*)ptr - sizeof(metadata)); 
removeBlock(&strct); 
+1

這是怎麼回事?不是'first = NULL',其中'first'是與'* first = NULL'相同的指針,其中'first'是指向指針的指針? – 2013-04-26 01:32:46

+0

我嘗試使用像你說的雙指針,它完全按照它應該做的。謝謝。 – iamseiko 2013-04-26 01:33:11

+1

@SheerFish不,它更深一層。 '* first = NULL'其中'first'是一個指向指針的指針,它保持原來的狀態。它是指向*的東西(這也是一個指針)。 – 2013-04-26 01:41:18

1

正如@SheerFish說,所有我們在C是通過按值。但是,可以使用指針模擬傳遞引用。

void func(struct foo **fooptr) { *fooptr = 0; } 
int main(int argc, char **argv) { struct foo *fooptr; func(&fooptr); } 

這是一個指針傳遞ptr爲變量的值(從不介意那個數值的指針),使功能與*ptr原值玩。這種技術有時被稱爲傳遞地址,並且是最靠近的C必須通過引用。

+0

謝謝,我做到了,它工作。 – iamseiko 2013-04-26 01:35:08

1

如果您通過'C中的引用',則需要記住通過 - >/**和*引用和引用。這是我寫的代碼位可以幫助你有點

int delete_node(struct node** head, int target) 
    { 

     if(*head == NULL) 
      return 0;              
    if((*head)->data == target) 
     { 
      temp = *head; 
      *head = (*head)->next; 
      free(temp); 
      return 1; 
     }              
} 

函數調用:

delete_node(&head, data) 

你與直接內存指針操作工作。你在內存中拋出結構的位置,引用它,然後改變該內存位置的值。

+0

這個'delete_node'從哪裏來? (不是我的投票) – Shoe 2013-04-26 01:30:22

+1

我更新它來糾正這一點。忘了說明這是底層的函數調用。這只是我爲C鏈接列表編寫的示例代碼片段。 – TheCodingArt 2013-04-26 01:33:02

+0

我的數據不是一個整數,這是一個雙向鏈表的一部分,沒有任何數據。它只是位於堆中的位置引用,位於數據塊旁邊,因此不會刪除任何要刪除的數據。但是,正如你所建議的那樣,使用雙指針起作用。謝謝。 – iamseiko 2013-04-26 01:34:49

1

我沒看過所有的細節,但是這部分跳出來是不正確的:

(metadata *)ptr - sizeof(metadata) 

指針運算的類型的單位進行,而sizeof爲您提供測量以字節爲單位。

所以我懷疑你想要說的是:

(metadata *)(((char*)ptr) - sizeof(metadata)) 

這也使得有關你的機器上運行,即一些假設可能需要填充metadata以確保字段正確對齊以供此用途。如果sizeof(metadata)不是字大小的倍數,則在很多體系結構上都會失敗。 (但是x86會讓它滑動,儘管性能成本和原子操作在某些領域不起作用)。

+0

爲什麼不''(元數據*)ptr - 1'? – Elazar 2013-04-26 01:34:23

+0

@Elazar - 第一個問題:應該是一樣的,但我想要更明確一些。第二個問題:它絕對不是*無關緊要的事情,編譯器不保證以你的名義添加任何填充。 – asveikau 2013-04-26 01:36:44

+0

不完全。在我的堆中,元數據結構停留在數據塊旁邊的堆中。所以,當用戶參考該數據塊時,我試圖通過減去大小來找到該元數據結構。它的工作原理,我沒有專門投它,但我想你的方式更合理和萬無一失。 – iamseiko 2013-04-26 01:37:06

1

指針按值傳遞。 任何東西在c是通過值。所以爲了改變傳遞給函數的指針,它應該得到metadata **first

此外,你應該使用

metadata *strct = ((metadata *)ptr - 1); 

爲指針運算用的sizeof(* P)的整數倍進行。所以這相當於

metadata *strct = ((metadata *)((char*)ptr - sizeof(metadata)));