2013-08-22 60 views
0

我有一個關於將c中的數組傳遞給函數的問題。在c中傳遞數組

當我運行這個程序,它給了我一個分段錯誤

int main() 
{ 

    char **ptr= NULL; 
    test(ptr); 
    printf("%s", ptr[0]); 
    return 0; 
} 

void test(char **ptr) 
{ 
    ptr = (char **) malloc(sizeof(char *)); 
    ptr[0] = (char *) malloc(sizeof(char)*5); 
    strcpy(ptr[0], "abc"); 
    return; 

} 

但這只是正常工作

int main() 
{ 

    char **ptr= NULL; 
    test(&ptr); 
    printf("%s", ptr[0]); 
    return 0; 
} 

void test(char ***ptr) 
{ 
    *ptr = (char **) malloc(sizeof(char *)); 
    *ptr[0] = (char *) malloc(sizeof(char)*5); 
    strcpy(*ptr[0], "abc"); 
    return; 

} 

有人能解釋一下爲什麼?

+3

因爲你至少需要三顆星才能在公共場合編程? –

+0

第一個片段通過值傳遞指針指針,因此設置sans-deference的值等價於修改局部變量等等。建議您在C中傳遞參數by-address,這是您的第二個片段正在做的事情。 (注意:第二個代碼片段中的第一個sizeof在技術上是錯誤的,它應該是'sizeof(char **)',或者更容易記住'sizeof(* ptr)'。(和@KerrekSB,+1,這真棒)。 – WhozCraig

+0

你基本上正在修改'test()'函數中的'ptr'。做一個拇指規則 - 如果你正在修改一個函數中的變量,那麼在那裏傳遞變量的地址,因此'char *在這裏通過'char ***'。 –

回答

3

您正在通過值傳遞參數ptr;形式參數ptrtest不同對象來自main的實際參數ptr,因此更改test::ptr的值不會反映在main::ptr中。

因此,你需要一個指針傳遞給ptrtest,並test需要取消引用該指針寫入正確的對象。

對於任何類型的T,如果你想修改函數參數的值,你需要做到以下幾點:

void foo(T *param) 
{ 
    *param = ...; 
} 

void bar() 
{ 
    T obj; 
    foo(&obj); 
} 

在這種特定情況下,Tchar **

1

這是因爲你期望你的函數不返回一個值,而是修改你已經在另一個範圍內創建的變量。

你期望的那樣,從功能,通過ptr和結構如下結束:

ptr -> b -> [] 

其中b是指向數組[]

在第一個示例中,您不是修改函數內部的外部ptr,而是修改它的副本。在這種情況下,爲了獲得所需的結構,你需要函數返回一個char **,以便返回分配的指針。你不需要傳遞原始的ptr。

在第二示例中,在另一方面,要傳遞的指針外PTR,所以該函數將被修改外PTR使用相同的存儲器空間。

我希望這可以幫助一點。

0

考慮下面的代碼understandling

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
void test(char **ptr); 

int main() 
{ 
    char *ptr= NULL; 
    test(&ptr); 
    printf("%s\n", ptr); 
    return 0; 
} 

void test(char **ptr) 
{ 
    *ptr = malloc(sizeof(char *)); 
    strcpy(*ptr, "abc"); 
    return; 
} 

無論在功能上的定義做在主要功能進行反映。因此,如果要在ptr變量中進行更改,則必須通過ptr變量的地址。

ptr是單指針(char ptr)變量,我們需要通過指針(&ptr)變量的地址。

在函數定義中,我們正在接收指針變量的地址,所以參數必須是雙指針的類型。

該概念與通過引用的調用類似。

類似的事情發生在你的代碼中。

您需要通過雙指針的地址,以使指針變量的變化。

雙指針的地址必須由函數定義中的三指針取得。

2

在C中,當您傳遞數組的函數,陣列「衰變」的指針。該函數接收一個指向數組的第一個元素的指針。它不接收數組本身。在調用函數中對指針賦值所做的任何更改都不會反映在調用函數中。

在你的第一個例子,test()接收字符串數組,並在函數內部,它改變什麼指針指向。所以ptr本地副本,這是NULL,被分配在函數內部的內存一樣,ptr[0]。但是,這些更改在test()的本地。它們沒有反映在調用函數中。當test()執行完畢並返回,則ptr在調用函數的值仍然NULL。你有內存泄漏,因爲沒有辦法訪問在test()分配的內存。

爲了在調用函數中反映更改,必須將指針傳遞給字符串數組:因此調用中的&ptr和定義test()中的三級指針。另外,簡單的方法是:

int main() 
{ 

    char **ptr= NULL; 
    ptr = test(); 
    printf("%s", ptr[0]); 
    return 0; 
} 

char** test(void) 
{ 
     char **ptr = (char **) malloc(sizeof(char *)); 
     ptr[0] = (char *) malloc(sizeof(char) * 5); 
     strcpy(ptr[0], "abc"); 
     return ptr; 

} 

澄清一點:我說,「在被調用的函數指針分配所做的任何更改都不會反映在調用函數」這與「數組元素的任何更改未在調用函數中反映」不同。這樣考慮:

int main (void) { 

    int array [] = { 0, 1, 2, 3, 4 }; 

    test1 (array); 
    printf ("%d\n", *array); 

    test2 (array); 
    printf ("%d\n", *array); 

    return 0; 
} 

void test1 (int* array) { 

    int new_array[] = { 3, 4, 5, 6, 7 }; 
    array = new_array; 
    return; 
} 

void test2 (int* array) { 

    array [0] = 5; // or *array = 5 
    array [1] = 6; 
    array [2] = 7; 
    array [3] = 8; 
    array [4] = 9; 

    return; 
} 

輸出:

0 
5 

在這裏,在test1()的變化是其中陣列指針本身指向,這不會在呼叫者中反映出來。所以在調用功能,*test仍然是0。在test2(),變化到陣列元件,其反映在呼叫者。因此,輸出差異:*test現在是5.所有這些都使用靜態而不是動態內存分配,但原理是相同的。

0

擴展@rcrmn的答案。

這是一個很好的程序設計,讓數據通過調用結構「向上」。在這種情況下,main()需要釋放它從測試中收到的存儲空間。

請注意,此代碼避免了原始問題中的所有雙指針,並且仍然符合要求。這是良好編程的本質,寫出清晰,簡單,完成工作的代碼。

#include <stdio.h> 
char *test(); 
int main() 
{ 
    char *ptr = test(); 
    printf("%s", ptr); 
    free(ptr); 
    return 0; 
} 

char *test() 
{ 
    char *ptr = (char *) malloc(sizeof(char) * 5); 
    strncpy(ptr, "abc", 3); 
    return ptr; 
}