2017-07-26 193 views
2

在以下示例中,函數func()返回本地指針變量的地址爲main()函數。它在GCC中工作正常。因此,它是明確的行爲?將本地指針變量的地址返回給main()函數

#include <stdio.h> 
#include <stdlib.h> 

int *func(void); 

int *func(void) 
{ 
    int *p; 
    p = malloc(sizeof *p); 
    *p = 10; 
    return p; 
} 

int main() 
{ 
    int *ptr = func(); 
    printf("%d\n",*ptr); 
    return 0; 
} 
+9

是的。是什麼讓你覺得它不是?它不返回但「*值的指針變量*」(其中,當然,是一個地址)「的指針變量的地址」。 –

+0

@FelixPalmen在func()和main()函數內部打印指針的地址。參見http://ide.geeksforgeeks.org/sULNzy – rsp

+0

您打印的內容不是指針**的**地址,而是* *指針**的值。指針**的**地址將在'func'中爲'&p'。 'main'中的'&ptr'。當然,指針**的**值**是一個地址**(但是指針指向的對象的地址)。 –

回答

2

內部func()p是指向存儲器由malloc()分配(或潛在地分配的內存,因爲malloc()可以失敗,返回一個空指針;這應該被選中)。如果成功,該內存分配將一直持續到明確free d。

p值在這種情況下返回給調用函數,main()p要麼是一個指針,指向一個成功的分配,或者是一個空指針,然後返回的值(這是暫時的,並且不是左值)被分配給ptr。因此,分配的存儲空間可以通過ptr進行訪問,這是p舉行func()返回前值的副本,雖然的p本身的使用壽命已經現在func()返回結束。

當不再需要避免內存泄漏時,ptr應該是free d。而且,有潛在的不確定的行爲在這裏如果malloc()失敗,從此ptr是一個空指針。

9

不,你不返回一個指針(地址)的局部變量。這將會像

int i = 10; 
return &i; 

而是您返回一個指向堆中分配的對象的指針。

雖然你確實有內存泄漏,因爲你沒有free內存任何地方。撥打free應該通過代碼呼叫您的功能(除非它又返回指針,其中責任繼續在他的呼叫鏈上)。

+4

再次重申,在OP被返回** **值的指針的,而不是**局部變量的**地址。 –

+1

爲了完整性,可能希望提到 - 在OP的例子中,'main()'(或者'printf()'語句之後調用的某個其他函數)需要調用'free(ptr)'。如果在'func()'中釋放了malloced內存,則在'main()'中訪問'* ptr'將會有未定義的行爲。 – Peter

1

這是完全有效的。

什麼是不能保證的是一旦函數返回並且堆棧幀縮小,棧幀上的變量會發生什麼。

你要返回的是一個地址malloc ed內存和而不是一個局部變量的地址(分配在堆棧上)。這與strdup()的工作原理非常相似。這是從here取得的strdup()的實現。這

char * 
strdup(str) 
    const char *str; 
{ 
    size_t len; 
    char *copy; 

    len = strlen(str) + 1; 
    if (!(copy = malloc((u_int)len))) 
     return (NULL); 
    bcopy(str, copy, len); 
    return (copy); 
} 

一個明顯的缺點(如「有些程序員花花公子」提到)是free ING的責任轉嫁到主叫方。

1

這是一個有效且正確的代碼,雖然有點令人困惑。

func分配int大小的內存。分配是通過取消引用int類型的指針變量來完成的。

改變分配的整數值10在內存中設置。 10應該設置爲整數(可以取決於編譯器)。但絕對不會大於整數的大小,所以應該是安全操作。

之後,函數返回指針值。

在main()中,返回的指針被設置爲另一個整型指針。這指向由malloc()分配的原始內存。

之後,在printf()語句中打印取消引用的整數指針。這將打印值10.

缺少的是free()調用,這在這裏不是很好的行爲。

這可能是一個很好的學習練習爲孩子們。

+1

「*分配是通過取消引用int類型的指針變量來完成的。*」no,「sizeof'僅對錶達式的* type *進行操作。此處不會發生取消引用。 –