2017-03-01 61 views
0

雖然對於簡單類型(simple types: int, char..)我們直接使用指針(their address)作爲函數的參數來永久更改它們在主程序中的值,有人可以向我解釋爲什麼對於結構我們需要一個指向Structure pointer的指針,而不僅僅是一個指針?爲什麼我們需要指向結構指針的指針來更改成員值?

struct someStruct 
{ 
    int field1; 
    int field2; 
} 

void initializeFields(struct someStruct** foo) 
{ 
    //changing fields 
} 

//while 
void initializeFields(struct someStruct* foo) //does not work ? 

回答

2

要僅更改結構的成員,您不需要那樣。但要將實際指針更改爲,您需要模擬的結構通過使用指向結構的指針的參考傳遞。

例如,只改變一員,這是不夠

void initializeFields(struct someStruct* foo) 
{ 
    foo->field1 = 1; 
    foo->field2 = 2; 
} 

int main(void) 
{ 
    struct someStruct bar; 
    initializeFields(&bar); 
    printf("field1 = %d\n", bar.field1); 
    printf("field2 = %d\n", bar.field2); 

    return 0; 
} 

但是,如果你比如要動態分配結構中的功能,你需要通過參考效仿通:

void initializeFields(struct someStruct** foo) 
{ 
    // The difference is this assignment 
    *foo = malloc(sizeof(struct someStruct)); 

    (*foo)->field1 = 1; 
    (*foo)->field2 = 2; 
} 

int main(void) 
{ 
    struct someStruct* bar; 
    initializeFields(&bar); 
    printf("field1 = %d\n", bar->field1); 
    printf("field2 = %d\n", bar->field2); 

    return 0; 
} 

另外兩個示例顯示按值傳遞和仿真通過引用之間的區別。

考慮下面的程序:

#include <stdio.h> 

void foo(int y) 
{ 
    y = 5; 
} 

int main(void) 
{ 
    int x = 1; 
    printf("1: x = %d\n", x); 
    foo(x); 
    printf("2: x = %d\n", x); 

    return 0; 
} 

上述程序將打印

 
1: x = 1 
2: x = 1 

這是因爲複製x價值被傳遞給函數foo。在foo中修改本地副本不會修改main中的原始變量x

現在參照效仿通:

#include <stdio.h> 

void foo(int *y) 
{ 
    *y = 5; 
} 

int main(void) 
{ 
    int x = 1; 
    printf("1: x = %d\n", x); 
    foo(&x); 
    printf("2: x = %d\n", x); 

    return 0; 
} 

該程序將打印出

 
1: x = 1 
2: x = 5 

這是因爲我們不改變功能foo裏面的指針變量y,但我們改變它指向的值的位置,這恰好是main函數中的變量x

+0

我明白了,但爲什麼在第二種情況下,我們需要指向返回malloc'd內存的指針?爲什麼我們不能只傳遞一個指向foo的指針? – Bionix1441

+1

這是一個很好的做法嗎?我的意思是,返回一個分配在initializeFields中的結構指針聽起來比分配一個指針的指針更好,並且不返回任何內容,甚至在malloc失敗的情況下也不會返回錯誤代碼。 – PanzerKadaver

+2

@ Bionix1441因爲C只具有所謂的*按值傳遞*,這意味着爲傳遞的參數創建了一個副本。修改副本當然不會修改原始內容。如果你有一個接受'int'參數的函數,並且在你修改參數的函數中,你會期望你傳遞給調用函數的值被修改嗎? –

3

struct someStruct* foo很好,你不需要struct someStruct** foo。不知道你從哪裏得到這個想法,但這是不正確的。

1

有一些非常特殊的情況,你需要指向結構指針的指針(主要是結構指針的數組)。

否則,指向結構體的指針就足夠了。

struct someStruct 
{ 
    int field1; 
    int field2; 
} 

void initializeFields(struct someStruct* foo) 
{ 
    foo->field1 = 42; 
    foo->field2 = -1; 
}