2013-03-27 89 views
3

我正在編寫一些C代碼來實現像push,pop等基本的棧數據結構操作。 我使用堆棧的鏈表實現。 在這個實現中,每次我將一個值推入卡住時,我創建一個新節點,並將其設置爲我的鏈接列表的頭節點。所以這涉及到改變頭節點的引用。爲什麼我們在C中傳遞Structure參數時使用雙指針?

void push(stack **t, int ele) 
{ 
stack *new, *temp; 
temp=*t; 
new=(stack *)malloc(sizeof(stack)); 
if(new==NULL) 
{ 
    printf("\n stack overflow"); 
    return; 
} 
new=(stack *)malloc(sizeof(stack)); 
new->val=ele; 
new->next=*t; 
*t=new; 

} 

如果我是寫使用單個指針類似的代碼,那麼它會是這樣

void push(stack *t, int ele) 
{ 
stack *new, *temp; 
temp=t; 
new=(stack *)malloc(sizeof(stack)); 
if(new==NULL) 
{ 
    printf("\n stack overflow"); 
    return; 
} 
new=(stack *)malloc(sizeof(stack)); 
new->val=ele; 
new->next=t; 
t=new; 

} 

在功能方面,頭節點(**噸)出現在賦值的RHS在所有步驟中,但這

*t=new; 

基本上所述第一代碼分配「新」到的**噸的指針,也就是* T,和第二代碼受讓人「新」到的* T的指針,也就是噸。 兩者似乎都只需要指向頭節點的單指針指定爲「新」,但只有第一個代碼有效,而第二個實際上並不修改頭節點值。

這是怎麼發生的?爲什麼第二個代碼的工作方式與第一個類似?

+1

您需要修改指向傳遞給'push()'的第一個堆棧元素的指針,因此您需要一個指向指針類型的指針參數。在第二個函數中,賦值給't'在函數外部是不可見的。 – 2013-03-27 18:52:56

+0

在第二個代碼中,函數是否簡單地將指針複製到堆棧,並且該函數執行的所有更改僅應用於副本? – 2013-03-27 18:57:22

+2

請注意,請不要使用名爲'new'(或'this'或'delete')的變量。你可能會認爲你永遠不會將你的代碼轉換成C++,但是如果發生這種情況,你現在可以通過避免使用C++的關鍵字來讓事情變得更容易。 – mah 2013-03-27 18:57:37

回答

3

因爲C中的所有內容都是按值傳遞的。因此,如果您需要爲函數的參數分配新值,則必須添加一個間接級別。如果你不是簡單地接收本地副本,那麼分配給該副本的任何值都將僅在該函數本身中可見。

請注意,不要在C中返回malloc的返回值。這是不必要的,您編碼的混亂,並且可以隱藏允許默認int的編譯器的錯誤。

在..另一個方面說明,而不是寫是這樣的:

new_stack = malloc(sizeof(stack)); 

使用這個代替:

new_stack = malloc(sizeof(*new_stack)); 

現在你沒有問題,如果的new_stack不斷變化的類型。

+0

謝謝!是的,海灣合作委員會編譯器似乎檢測到鑄造錯誤,但是是替代代碼是肯定似乎更好 – 2013-03-27 19:21:32

2

在單指針的情況下,說

int addInBeginning(int *s) 
{ 
... // add a node in the beginning of the linked list 
} 

int main() 
{ 
int *t; 
... // make t point to a linked list say t ---> 1 -> 2 -> 3 
f(t); 
} 

最初,s和t都指向同一個列表。但是,當我們在開始時添加節點時,s指向新節點,而t仍指向它先前指向的節點。當push返回時,新節點不能從t訪問。

0 -> 1 -> 2 -> 3 
^ ^
| | 
s t 

在雙指針的情況下,s將指向t,然後指向該列表。所以所有指針操作都發生在原始指針t上。

s ----> t ----> 0 -> 1 -> 2 -> 3 
相關問題