2017-10-10 67 views
0

對不起,如果這已經被問過,但我有點混淆傳入和賦值給結構。將結構傳遞給一個函數並分配它

typedef struct test { 
    int x; 
    int y; 
} test_t; 

void func(test_t * test) 
{ 
    test_t second; 
    second.x = 2; 
    second.y = 3; 

    *test = second; 
} 

void main() 
{ 
    test_t first; 
    func(&first); 
} 

這是有效的嗎?如果我沒有記錯的話,沒有在func()內部結構化malloc,你不應該把func()中的指針* test指定給struct second,因爲它的作用域主要在func()內部,並且一旦函數返回就會丟失。但是,在main()中打印出來的值是正確的。

有什麼不同的方法來實現這個結果?這只是爲了澄清一些混亂和健忘的記憶。

編輯:

的什麼,我試圖做的是這方面的一個更清楚的例子:

typedef struct args 
{ 
    int status; 
    int id; 
    unsigned long long start_address; 
    unsigned long long end_address; 
    unsigned long long size; 
} args_t; 

void ioctl_call(args_t *args) 
{ 
    args_t params; 

    /* get values */ 
    ioctl(fd, cmd, params); 

    *args = params; 
} 

void main() 
{ 
    args_t args; 
    iotcl_call(&args); 
    printf("%d\n", args.id); 
} 
+1

爲什麼創建'second',然後踩着'test'呢?爲什麼不直接操作'test'呢? – tadman

+0

@tadman這是示例代碼。這並不意味着有用;它的意思是指出一些東西。 – HTNW

+0

我的問題依然存在。在什麼情況下不會直接操縱它是更好的選擇? – tadman

回答

4
void func(test_t * test) 
{ 
    test_t second; 
    second.x = 2; 
    second.y = 3; 

    *test = second; 
} 

此代碼是完全有效的,儘管低於最佳。

返回地址second是違法的,但這不是發生了什麼事。當您說*test = second時,您將second分配給解除引用的指針。編譯器將生成代碼以複製該結構的每個元素

它不理想的原因是因爲該副本。相反,請考慮:

void func(test_t * test) 
{ 
    test->x = 2; 
    test->y = 3; 
} 

通過這種方式,編譯器將直接指定指向結構的字段。

+0

感謝您的快速回復!出於某種原因,我過度思考,並擔心第二個將會出現在堆棧中,一旦函數調用結束,這些值將變成垃圾。 – chewboy8

0

參數test位於函數func的本地,並且在函數外部更改其值不可見。

但是,您不會更改test的值。你是解除引用它指向的內存位置並寫入該位置。在這種情況下,test包含main中變量first的地址。

所以,當你分配給*testfunc你實際上是在main分配給first。這就是爲什麼你可以看到功能以外的結果。

因此,此代碼將按照您的預期工作,雖然它不是最優的。正如在另一個答案中提到的,相反,將值分配給結構的本地實例,然後將其分配給解除引用的指針,您可以直接解引用指針並直接寫入每個字段。

void func(test_t * test) 
{ 
    test->x = 2; 
    test->y = 3; 
} 
+0

感謝您的解釋!我正在考慮經典的「返回一個函數內部聲明的數組」,以及這些值是如何變成垃圾的。這就是爲什麼我擔心這個例子。 – chewboy8

相關問題