Go 指针与地址

可能是java写多了, 总觉得所有新一代高级语言都应该跟java差不多

不过越来越觉得Go就是一个不用写析构函数自带垃圾回收的C , 连Cpp都算不上

  • 它没有class的概念
  • 它没有private,protected,friendly和public, 虽然可以通过首字母大小写来区分私有还是公有
  • 它可以在windows和linux平台上直接编译可执行二进制文件
  • 指针和地址 都可以用, 包括指向指针的指针

Go的new实际上是一个内建函数,而不是关键字, 它会分配内存然后返回一个地址(java的new是关键字,返回一个引用)

下面是一个例子


    stringAddress := new(string);
    fmt.Println(stringAddress);
    fmt.Println(*stringAddress);
    intAddress := new(int);
    fmt.Println(intAddress);
    fmt.Println(*intAddress);
    boolAddress := new(bool);
    fmt.Println(boolAddress);
    fmt.Println(*boolAddress);

上面这部分代码会输出

0xc042008220

0xc042008260
0
0xc042008270
false

然后我们通过经典的swap函数来看看go的指针和地址, 感觉跟 C语言 差不多

声明两个整型变量,然后输出一下地址


    i:=3;
    j:=4;
    
    fmt.Println("these are original addresses:",&i,&j);

可以得到

these are original addresses: 0xc042008278 0xc042008280

然后如果你直接使用swap(a,b)这样的函数是无法交换的, 形参实参什么的概念又来了, 说白了a,b不过是原值的拷贝

func swap(a int , b int ){
    fmt.Println("these are copied parameters addresses",&a,&b);
    tmp:=a;
    a=b;
    b=tmp;
}

从输出可以看出, &a 和 &b 的地址跟原地址并不一致

these are copied parameters addresses 0xc0420082a8 0xc0420082b0

然后试试使用指针, 语法跟C有些不同,C语言类型在前 int *a , Go的话类型在后 a *int

swapByAddress(&i,&j);

func swapByAddress(a *int, b *int){
    fmt.Println("these are input original addresses",a,b);
    tmp:=*a;
    *a=*b;
    *b=tmp;
}

上面代码会得到

these are input original addresses 0xc042008278 0xc042008280

你会发现a,b的地址跟传入i,j 是一模一样的

如果你对C语言的指针不熟悉的话可以这样理解

指针就是一个存放地址的变量, 所以主函数里传入的是地址, 接收参数的是指针, 

直接获取指针的话例如 a 会得到 这个指针变量中存储的地址值

使用 *a 的话可以得到 指针变量a中存储的地址里存储的真实值

所以你也可以理解&符号是取地址符号, *是取值符号

如果把这个函数改成

func swapByAddress(a *int, b *int){
    fmt.Println("these are input original addresses",a,b);
    tmp:=a;
    a=b;
    b=tmp;
}

会得到 无法交换 的结果, 这是因为你只是把指针变量a中存储的地址和指针变量b中存储的地址做了一个交换, 但是地址里的值还是原来的值

只不过之前 地址0xc042008278被放在指针变量a中,现在换成了b, 这样毫无意义

而使用 *a 和 *b 才是 “交换 指针变量a 中存储的地址里的数据 和 指针变量b中存储的地址里的数据”

这里我要感谢谭浩强老爷爷… 😛

这个东西甚至连指向指针的指针都跟C一样

    //声明一个整型变量
    var tmp int = 100;
    //声明一个指向整型变量的指针
    var pointer *int = &tmp;
    //声明一个指向 "整型变量的指针" 的指针 (2级指针)
    var poi2poi **int = &pointer;
    
    fmt.Println(pointer,*pointer);
    //第二个值是poi2poi指向的地址,也就是上一行代码pointer的值
    fmt.Println(poi2poi,*poi2poi,**poi2poi);

输出

0xc0420082f8 100
0xc042004030 0xc0420082f8 100

完整代码如下

package main 

import (
    "fmt"
)

func main() {
    
    stringAddress := new(string);
    fmt.Println(stringAddress);
    fmt.Println(*stringAddress);
    intAddress := new(int);
    fmt.Println(intAddress);
    fmt.Println(*intAddress);
    boolAddress := new(bool);
    fmt.Println(boolAddress);
    fmt.Println(*boolAddress);
    
    i:=3;
    j:=4;
    
    fmt.Println("these are original addresses:",&i,&j);
    
    i,j = swapByReturn(i,j);
    fmt.Println(i,j);
    
    swap(i,j);
    fmt.Println(i,j);
    
    //传入i和j的地址
    swapByAddress(&i,&j);
    fmt.Println(i,j);
    
    //声明一个整型变量
    var tmp int = 100;
    //声明一个指向整型变量的指针
    var pointer *int = &tmp;
    //声明一个指向 "整型变量的指针" 的指针 (2级指针)
    var poi2poi **int = &pointer;
    
    fmt.Println(pointer,*pointer);
    //第二个值是poi2poi指向的地址,也就是上一行代码pointer的值
    fmt.Println(poi2poi,*poi2poi,**poi2poi);
}

func swap(a int , b int ){
    fmt.Println("these are copied parameters addresses",&a,&b);
    tmp:=a;
    a=b;
    b=tmp;
}

//参数为两个地址 如 0xc042036228 0xc042036230
func swapByAddress(a *int, b *int){
    fmt.Println("these are input original addresses",a,b);
    tmp:=*a;
    *a=*b;
    *b=tmp;
}

func swapByReturn(a int, b int)(int,int){
    tmp:=a;
    a=b;
    b=tmp;
    
    return a,b;
}