GO与C比较:指针函数返回局部变量地址的不同

原地址:https://blog.csdn.net/linuxandroidwince/article/details/79113398

GO与C比较:指针函数返回局部变量地址的不同

C语言函数中如何返回变量与指针?

在C语言中,一个函数可以直接返回函数中定义的局部变量,其实在函数返回后,局部变量是被系统自动回收的,因为局部变量是分配在栈空间,那为什么还可以返回局部变量,其实这里返回的是局部变量的副本(拷贝)。

#include <stdio.h>

int fun()
{
    int a = 10;
    return a; //返回的是a的副本
}

int main()
{
    int b;
    b = fun();
    printf("%d\n", b);
}
$ ./a.out
10

如果将上面这个例子改成下面:

#include <stdio.h>

int *fun() //指针函数 (返回值是一个地址)
{
    int a = 10;
    return &a;  //返回变量a的地址
}

int main()
{
    int *b = NULL;
    b = fun();
    printf("%d\n", *b);
}
编译时会有警告:
main.c:14:12: warning: function returns address of local variable [-Wreturn-local-addr]
$ ./a.out 
Segmentation fault (core dumped) //运行发生段错误

这里之所以发生段错误,是因为函数返回后,系统自动回收了函数里定义的局部变量,所以运行时去访问一个被系统回收后的地址空间,一定就会发生段错误,这是C/C++语言的特点。当然,也有办法让其不产生段错误,前面说过,函数里的给变量分配的空间是在栈上面,只要让其实间变为堆上,这样函数返回后系统就不会回收。办法是有的,就是用关键字static声明一下,于是将上面程序改为如下:

#include <stdio.h>

int *fun() //指针函数 (返回值是一个地址)
{
    static int a = 10;
    return &a;  //返回变量a的地址,此时的地址是在堆上,即使fun返回,这个地址空间还在堆上,系统不会回收,直到程序退出。
}

int main()
{
    int *b = NULL;
    b = fun();
    printf("%d\n", *b);
}
$./a.out
10

GO函数中返回变量,指针

下面先看一个例子:

package main

import "fmt"

func fun() *int { //int类型指针函数
    var a := 1
    return &a  //这里也返回了局部变量a的地址
}

func main() {
    var p *int
    p = fun()
    fmt.Printf("%d\n", *p) //这里不会像C,返回段错,而是成功返回变量V的值1
}
$go run main.go
1

这里就是GO与C/C++不同的地方,GO中没有关键字static,但有比static还灵活的用法,下面来看下官方的解释:

When possible, the Go compilers will allocate variables that are local to a function in that function's stack frame. However, if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must allocate the variable on the garbage-collected heap to avoid dangling pointer errors.
  • 1

以上的解释说明如下: 
GO编译器会自动检查函数中的局部变量,在函数外面有没有人使用,如果有人使用,编译器会将局部变量放到GO的垃圾回收堆上,也就是说,将局部变量升级为堆上的变量,这与C中的static是一回事,但GO比C强大,这个变量你不用担心它会不会导致memory leak,因为GO有强大的垃圾回收机制。

猜你喜欢

转载自blog.csdn.net/idwtwt/article/details/80323500
今日推荐