2011-09-27 58 views
0

我目前正在試驗C,並且我很難理解如何在函數中使用指針。我明白當初始化一個指針然後解引用它時會發生什麼,但是當我必須在函數中使用它們時,我有點困惑,如下所示:何時返回指針,傳遞指針作爲參數還是根本不使用它們?

我在這裏有三個函數,但我不知道何時使用哪個。我還是比較新的C.

int returnSomething(int a, int b) 
int returnSomething(int *ptrA, int *ptrB) 
int* returnSomething(int *ptrA, int *ptrB); 

編輯:

有三個之間的主要區別?

+2

如果沒有關於要求的更多細節,實在沒有辦法做出決定。 –

回答

6

您需要根據每種情況調整您的使用情況。

第一種情況,您將兩個int按值作爲參數並返回一個int。由於您的參數是按值計算的,因此應用於它們的所有更改都只有函數範圍。

例如:

int returnSomething(int a, int b) 
{ 
    a = 0; 
    b = 0; 
    return 0; 
} 

//.... 

int x = 3; 
int y = 4; 
returnSomething(a,b); 
// x will still be 3, y will still be 4 

在第二種情況下,因爲你傳遞參數作爲指針,你將能夠改變這些值。

int returnSomething(int* a, int* b) 
{ 
    *a = 0; 
    *b = 0; 
    return 0; 
} 

//.... 

int x = 3; 
int y = 4; 
returnSomething(&a,&b); 
// x and y will be 0 here 

第三種情況,除了通過指針傳遞參數外,還返回一個指向int的指針。這意味着在函數內部,您必須分配內存並在完成時釋放內存。我不建議使用這個,通常有解決方法來做到這一點。

int* returnSomething(int* a, int* b) 
{ 
    int* x = malloc(sizeof(int)); 
    *x = 1; 
    return x; 
} 

//.... 

int x = 3; 
int y = 4; 
int* z = returnSomething(&a,&b); 
free(z); 

答案是,這取決於你想要做什麼。如果您需要更改方法中的參數值,請按引用或指針傳遞。我不會推薦使用最後一種方法。

此外,這適用,因爲你正在處理POD類型。如果你有自己的結構體,那麼通過指針或者返回一個指針來傳遞它會更高效,因爲不需要創建新的副本。

+0

哇,這真的有助於清理事情!我將盡快創建結構,所以很可能我必須使用第三種方法。謝謝! – diesel

+0

既然你在堆上分配了它,它會保留它在函數中賦值的值,所以1.也有可能在free(z)之後它仍然包含1,因爲free會基本上告訴系統它可以重用該內存,而不是刪除它。但它可能:) –

+0

由於3和4被傳入函數,因爲你沒有做任何事情,只分配1到x,int * z只包含1?假設你做了int * x = malloc(sizeof(int * a)),然後返回x,現在的值是3嗎? – diesel

0

讓我們首先解釋通過引用給你;處理起來要複雜得多。

假設你有:

int increment(int &a) 
{ 
    a = a + 1; 
    return a; 
} 

increment(foo); // foo = foo + 1; 

注:爲了便於理解,我已經犧牲了一些 '正確'。)

這做了兩兩件事:

  • 第三行增加a1。但請注意 - 我們在函數聲明中放入了&a。這意味着通過引用傳遞給increment()的值也會增加1。換句話說,foo增加1,就像a一樣。
  • 第四行返回a值 - 一個數字,如1242-21

一兩件事:通過引用傳遞是C++;你不能在C中使用它,但在開始弄亂指針之前學習它是一個很好的概念。


傳遞指針基本上只是路過值 ...除非你在存儲器中的(0x12345678)的位置,而不是實際的foo

int pincrement(int *p) 
{ 
    *p = *p + 1; 
    return *p; 
} 

pincrement(&foo); // foo = foo + 1; 

這和我們的第一個程序是一樣的 - 它增加了foo的值。

  • &foo告訴你的foo地址在內存中。該信息被傳遞給p。所以:

    p = &foo; 
    
  • 在第三行,價值指向*p遞增。換句話說,foo增加了1

  • 第四行返回foo值 - 一個數字,如1242-21

回訪指針,你可以用它們來返回string s:

char *HelloWorld() 
{ 
    return "Hello, World!"; 
} 
+1

'c' – balki

+0

沒有參考文獻好的。假設我使用int a而不是參考&a,這會產生什麼不同? – diesel

+0

@balki Err ...是的,它說。 –

-2

對於int,除非無法這樣做,否則總是按價值傳遞。 即int returnSomething(int a, int b)

當您傳遞一些自定義大struct時,傳遞它並將其作爲指針返回,除非無法這樣做。

+0

如果你想改變參數的值怎麼辦? –

+0

是的,這將是無法這樣做的情況之一。 – balki

+0

我的回答有什麼問題?爲什麼downvote? – balki

0

您的問題的答案更多地與內存方面的考慮和良好的代碼設計有關,例如您是否想節省資源,以及是否知道代碼在任何時候都發生了什麼。 1)當按值傳遞(int returnSomething(int a, int b))時,每個參數都是副本,並且對它們所做的任何更改都不會影響函數外部的原始變量(參數具有函數作用域),並且該函數返回一個值,然後您可以使用該值初始化一個變量。

2)當你路過的指針,你傳遞一個地址,一個內存位置所以請記住,由於良好的代碼設計的問題,你必須通過另一個外部絕緣反對修改該位置(鎖定語義)處理。這尤其適用於您提供的例子:

int returnSomething(int *ptrA, int *ptrB) 
int* returnSomething(int *ptrA, int *ptrB); 

其中函數退出後的函數內*ptrA and *ptrB所做的更改仍然存在。兩者之間的唯一區別是其中一個函數返回一個值,然後您可以使用該值初始化一個變量(int returnSomething(int *ptrA, int *ptrB)),另一個將另一個地址返回到內存中可能會發生更改和/或垃圾頭痛的位置,具體取決於您的程序設計(在函數中爲返回類型創建內存並將該地址分配給指針變量,指針變量本身可以任意更改爲指向內存中的另一個位置等)。我將通過添加以下內容來擴展Luchian的最後一個示例:想象一下代碼中的某個其他位置,您將* z變量傳遞給另一個函數,然後嘗試使用該地址指向的內存,您現在有一個指向變量的指針變量沒有什麼你然後嘗試使用。這一切歸結爲良好的代碼設計。如果你瞭解指針的優缺點並正確使用它們,那麼你就沒有問題了。

0

Luchian Grigore上面寫了一些很好的描述。我想給你一個小小的想法來進一步簡化你的思維。

當你將參數傳遞給C中的一個函數時,試着去思考棧到底是什麼(在情況1中,實際的整數變量被壓入堆棧,並且在這種情況下,這些整數變量的地址得到推動),現在結合這一事實,只要控制從功能和堆棧展開返回,堆棧上的變量所做的更改就會消失。

因此,簡單來說,如果您打算更改在函數內部傳遞的varibales,並希望稍後使用這些更改,請考慮傳遞這些變量的地址,否則只需傳遞變量。

相關問題