2011-01-07 178 views
3

看來我是被卡住了一些基礎知識。有人可以解釋我爲什麼下面的代碼:指針,指向函數的字符串

 
#include <stdlib.h> 

void Test1(char *t) 
{ 
    t = (char *)malloc(11); 
    strcpy(t, "1234567890"); 
} 

void Test2(char **t) 
{ 
    *t = (char *)malloc(11); 
    strcpy(*t, "1234567890"); 
} 

void Test3(char *t) 
{ 
    strcpy(t, "1234567890"); 
} 

char * Test4(char *t) 
{ 
    t = (char *)malloc(11); 
    strcpy(t, "1234567890"); 
    return t; 
} 

int main() 
{ 
    char *t1 = NULL; 
    Test1(t1); 
    printf("\nTest1: %s\n", t1); 

    char *t2 = NULL; 
    Test2(&t2); 
    printf("\nTest2: %s\n", t2); 

    char *t3 = (char *)malloc(11); 
    Test3(t3); 
    printf("\nTest3: %s\n", t3); 

    char *t4 = NULL; 
    t4 = Test4(t4); 
    printf("\nTest4: %s\n", t4); 

    return 0; 
} 

給出了這樣的輸出:

 
Test1: (null) 

Test2: 1234567890 

Test3: 1234567890 

Test4: 1234567890 

這有什麼錯Test1的功能?爲什麼Test4與Test1幾乎相似? 更一般的問題:在函數中創建字符串並返回指針的正確方法是什麼?

+2

您已經標記了C++和C,而這取決於在C++中,你應該使用`std :: string`(除非有一些迫切需要!),在C中,除了第一種方法都是可能的。 – Nim 2011-01-07 14:52:33

+0

是的,我可以使用字符串類,但我想了解核心,這就是爲什麼我在這裏使用char *。 – clumpter 2011-01-07 15:46:23

+0

在C中,do * NOT *強制轉換了`malloc()`的結果。在這裏閱讀推理:http://stackoverflow.com/a/605858/1701799(基本上,這是因爲一個`void *`會自動安全地升級到適當的類型)。我知道這被標記爲C/C++,但沒有這樣的語言「C/C++」。如果這是C++,那麼您將使用`#include `而不是`#include `。我認爲這應該只是被標記爲C.在C++中,你幾乎不會使用`malloc()```free()`,而是使用`new/delete`,或者更好的智能指針/ etc .. – RastaJedi 2016-02-22 05:35:12

回答

0

考慮你的Test1執行以下行爲:

char * x1 = NULL; 
Test1 (x1); 

Test1的是以下中完成:

void test1 (char * t)// t -> x1 -> null 
{ 
    t = (char *) malloc (11); 
    // t now points a different place (the memory allocated), and the reference of x1 continues pointing to null 
    strcpy (t, "1234567890"); // t value is "1234567890" but x1 continues pointing to null 
    // Error, the memory that is pointed by t is never released 
} 
printf ("\nTest1:%s \n", t1);// Print the value of x1 (null) and the reference of t is lost 
1

因爲你寫的:

void Test1(char *t) 

更改爲:

void Test1(char* &t) 

將在C++中唯一的工作。示範這裏:http://www.ideone.com/OYNQo

+2

只有在C++請。 – Benoit 2011-01-07 14:40:13

6

函數參數不工作,你的思考方式。你的價值路過的「價值」,而不是「參考」,這裏面的功能意味着一旦,這些值的任何變化都只是侷限於該功能,所以當函數退出的局部變化被扔掉。

要解決此問題,請將指針傳遞給指針(char ** t),或者通過引用傳遞指針(char & *)並更改要匹配的函數代碼。

2

考慮函數:

 
void Test1(char *t) 
{ 
    t = (char *)malloc(11); 
    strcpy(t, "1234567890"); 
} 

現在,t是函數內的一個局部變量。它包含什麼?指針值。最初那個指針值指向NULL,因爲你把它叫做Test1(NULL);

然而第一行,t = (char *)malloc(11),所述局部變量t重新分配給新malloc分配一塊存儲器。

當函數返回時您main()變量t1仍然指向NULL,因爲記得我之前說的,在Test1函數採用指針的值的副本。在任何時候,t1變量都不會被Test1修改。

但是,如果你編碼的功能等:

 
void Test1(char **t) { 
    *t = (char *)malloc(11); 
    strcpy(*t, "1234567890"); 
} 

int main(void) { 
    ... 
    Test1(&t1); 
    ... 
} 

..things會有所不同。

2

當傳遞一個指針作爲參數傳遞給功能時,指針由值來傳遞。因此,您可以更改指向的對象,但是如果修改函數中的指針,調用者將不會知道它。

0
void Test1(char*& t) ; // This is a possible method signature. 
1

在測試1中,線

t = (char *)malloc(11); 

分配給變量T,這是在功能測試1本地。main()中的變量t1沒有改變,所以傳遞給printf的NULL指針。 Test4可以工作,因爲你在main()中改變了t4。

在函數中創建字符串的「正確」方法是Test4(但不需要提供t作爲參數)或Test2(如果您更喜歡或需要out參數)。在這兩種情況下,主叫方都必須隨後釋放該字符串。 Test3也可以工作,但調用者必須確保緩衝區足夠大 - 爲了防止未定義的行爲和內存泄漏,緩衝區大小應作爲參數傳遞給Test3。使用Test3的優點是可以將緩衝區分配到堆棧中,消除了內存泄漏的風險。

2

Test1中,您將變量t傳遞給您的函數,該函數是一個指針。 傳遞給函數的參數存在於堆棧中,當函數完成時,堆棧會丟失。你main()中的t爲NULL的原因是你將malloc的結果存儲在堆棧中,並且該堆棧不再存在。

3

您已經定義了T1作爲 char* t1 = NULL; 和調用功能 Test1(t1); 傳遞指針變量T1(而不是它的地址)。

功能的Test1期待一個char * void Test1(char *t)

這裏t是一個局部變量只Test1功能。在函數內部進行的任何修改都不會在函數的外側顯示,因爲您實際上並未修改main函數的變量t1,而是本地變量t