2015-09-22 42 views
2

我有這樣是否將「指向結構的指針」傳遞給函數在C中創建它的本地副本?

struct node 
{ 
    int data; 
    struct node* next; 
}; 

我用創造單鏈表的結構。

我創建其他功能,如

int push(struct node* head,int element); 

其推動到數據使用節點結構創建的堆棧。

功能,然後嘗試更新struct node* head通過使用代碼它(它其他的東西也一樣)

head=(struct node*)malloc(sizeof(struct node)); 

呼叫作出這樣

struct node* stack; 
push(stack,number); 

它看起來像這樣的代碼創建傳遞給它的指針副本。於是,我只好功能改變

int push(struct node** head,int element) 

*head=(struct node*)malloc(sizeof(struct node)); 

呼叫作出這樣

struct node* stack; 
push(&stack,number); 

所以我的問題是,什麼是早期的功能幹嘛?如果我想更新指針的原始值或者我的方法錯誤,是否有必要將struct node**傳遞給該函數?

對不起,我不能提供完整的代碼,因爲它是一項任務。

+0

C傳遞值,即使傳遞的值是對其他東西的引用。 –

+0

@JohnColeman:澄清:C不支持引用(這個術語在編程中有明確的含義)。你可能意思是「地址」。 – Olaf

+0

@Olaf指針是C實現引用的方式。你爲什麼認爲'*'被稱爲* dereference *操作符?我不想陷入術語中,但維基百科關於計算機科學參考文獻的文章提到指針是參考類型的一個例子:https://en.wikipedia.org/wiki/Reference_(computer_science)。但是 - 你可能是正確的,來自不同語言的人可能會誤解我的意思。 –

回答

5

C始終傳遞值。要更改傳遞給函數的變量,而不是傳遞變量本身,則傳遞引用(其地址)。

比方說,你正在使用的舊簽名

int push(struct node* head,int element); 

struct node *actual_head = NULL; 
push(actual_head, 3); 

調用你的函數調用現在推前,您的變量actual_head會有價值NULL

在推功能中,新變量head將被推送到堆棧。它將具有與傳遞給它的值相同的值,即NULL

然後,當您撥打head = malloc(...)時,您的變量head將獲得您想要的新值而不是actual_head

爲了緩解上述情況,你必須給你的函數的簽名更改爲

int push(struct node** head,int element); 

struct node *actual_head = NULL 
push(&actual_head, 3); 

現在,如果你仔細注意的actual_headNULL,但這個指針也存儲的地方,那某處是它的地址&actual_head。我們把這個地址作爲1234

現在推送功能裏面,你的變量head可容納一個指針的地址(注意兩個*),將有1234

值現在,當你做*head = malloc(...),你實際上改變存在於位置1234的對象的值,這是您的actual_head對象。

0

功能

int push(struct node* head,int element) { 
    head=(struct node*)malloc(sizeof(struct node)); 
} 

分配一些存儲器和把它扔掉(原因內存泄漏)。

將「指向結構的指針」傳遞給函數可以創建它的本地副本。

如果要更新指針的原始值,則必須將struct node**傳遞給函數。 (使用全局變量通常被認爲是一個壞主意)

1

代碼沒有做你認爲的事情,但不是因爲它創建了節點的副本,它創建了指針的副本。

嘗試打印

fprintf(stdout, "Address of head: %p\n", (void *) head); 

兩個,裏面push()並在調用函數。

你在傳遞指針和參數在不同的內存地址,儘管它們都指向同一個地址,存儲malloc()結果在它不funcion返回之後仍然存在。

您需要將指針傳遞到指針這樣

int push(struct node **head, int element) 
{ 
    /* Ideally, check if `head' is `NULL' and find the tail otherwise */ 
    *head = malloc(sizeof(**head)); 
    if (*node == NULL) 
     return SOME_ERROR_VALUE; 
    /* Do the rest here */ 
    return SOME_SUCCESS_VALUE_LIKE_0; 
} 

,並呼籲它,只是

struct node *head; 
head = NULL; 
push(&head, value); 
/* ^take the address of head and pass a pointer with it */ 
當然

,在push()實施應該是非常differente,但我想你會明白了。

+0

其實我使用類似的printf語句發現了問題。 –

+0

像這樣檢查數據有時候比使用調試器有時更有幫助,有時候也是如此。 –

2

是的。

程序的第一個版本是按值傳遞指針。雖然它通過了一個地址(由pointer to struct持有),但它沒有通過pointer's address - 更新該值所必需的。

無論何時您想要更新變量的值您必須通過變量的地址。要傳遞指針地址,需要參數pointer to pointer to type

對你而言,pointer to pointer to struct node

4

C 總是按值傳遞參數(即通過複製它)。這甚至適用於指針,但在這種情況下,它是被複制的指針本身。大多數情況下,你使用指針,這很好,因爲你有興趣操作指針指向的數據。但是,在你的情況下,你想修改指針本身,所以你確實必須使用指向指針的指針。

+0

@iharob:夠公平的;我編輯了開幕。 –

0

當你通過stack給你的函數push(struct node* head,int element)

,做

head=(struct node*)malloc(sizeof(struct node)); 

指針head將更新至malloc()stack分配的內存不知道該內存就像你剛纔傳遞的值。 (這裏未初始化)

當你傳遞地址時,你有一個指向指針的指針,它使內部的改變將被反映在stack

1

每個人都說過的話在你的問題上是絕對正確的。不過,我認爲你也應該考慮設計。你的問題的一部分是你將堆棧本身與存儲數據所需的內部結構混合在一起。你應該有一個堆棧對象和一個節點對象。即

struct Node 
{ 
    int data; 
    struct Node* next; 
} 

struct Stack 
{ 
    struct Node* head; 
} 

然後你的推送函數可以把一個指針指向堆棧而沒有任何雙重間接。另外,沒有將某些東西推到堆棧中間的節點上的危險。

void push(struct Stack* stack, int value) 
{ 
    struct Node* node = malloc(sizeof node); 
    node->data = value; 
    node->next = stack->head; 
    stack->head = node; 
} 
0

所以我的問題是,什麼是早期的功能幹嘛?

您之前的函數被定義爲接收指向對象的指針。您將函數傳遞給未初始化的結構節點指針。函數不能對代表未初始化指針的值做任何事情。所以你的函數被通過了垃圾,但沒有造成任何損害,因爲你的函數立即忽略它,並用指向已分配內存的指針覆蓋。你的函數沒有使用你現在除了臨時本地存儲以外的任何值。從你的函數返回後,你的函數參數被拋棄(它們只是副本),並且你的棧變量的值與以前一樣,仍然是未初始化的。編譯器通常會在初始化之前警告您使用變量。

順便說一下,函數返回時,分配內存的指針值也被丟棄/丟失。所以現在在內存中會有一個沒有引用的位置,因此無法釋放它,也就是說,你有內存泄漏。

如果我想更新指針的原始值或者我的方法錯誤,是否需要將struct node **傳遞給函數?

是的,有必要傳遞一個變量的地址,你想要被調用的函數填入。它必須被寫爲接受它將提供的數據類型的指針。既然你用一個指針來引用你的對象,並且由於你的函數正在生成一個指向你的對象的指針,所以你必須傳遞一個指向你的對象的指針。

或者,你可以返回一個指針從一個函數的值,例如

struct node * Function() { return (struct node *)malloc(sizeof(struct node)); } 

通話將...

struct node *stack; 
stack = Function(); 
if(stack == NULL) { /* handle failure */ } 

所以,你的方法沒有錯,只是你的實現(和理解)需要工作。

相關問題