zoukankan      html  css  js  c++  java
  • Go语言基础之指针

    1 指针

    1.1 Go语言中指针介绍

    指针是程序载入到内存中的所对应的地址,为了保存数据在内存中对应的地址,就有了指针变量。指针在内存中的示意图如下:

    Go语言中的指针不能进行偏移和运算,是安全指针。在Golang中只有&(取址)和*(取值)两个操作。

    1.2 指针和地址的区别

    地址:是内存地址(用字节来描述的内存地址)

    指针:指针存储执行类型数据在内存空间中对应的地址。比如说string类型的指针,其只能存储string变量类型的指针

    1.3 指针和指针类型

    如同上面所说,指针是地址,但是地址不是指针,因为指针有其对应的类型,如*intfloat64*string等。

    取变量指针的语法如下:

    ptr := &v	// v的类型为T
    
    • v:代表被取地址的变量,类型为T
    • ptr:用于接收地址的变量,ptr的类型就是*T,称其为T的指针类型

    代码演示:

    func main()  {
    	var a int
    	fmt.Println(a)		//0
    	b := &a  // 取变量a的内存地址
    	fmt.Printf("b=%v
    ", b)			//b=0xc00000a0c0
    	fmt.Printf("type b:%T
    ", b)	//type b:*int
    
    	c := "tom"
    	// b = &c  //go语言是静态类型,变量只能存储一种类型的地址
    	// golang中的地址只能读不能操作
    	fmt.Printf("&c=%v
    ", &c)	//&c=0xc0000321f0
    
    	d := 100
    	b = &d
    	fmt.Println(b)		//0xc00000a0d8
    	// *取地址对应的值
    	fmt.Println(*b)		//100
    	// 指针可以做逻辑判断
    	fmt.Println(b == &d)	//true
    }
    
    

    对于上述代码的说明:

    • b := &a在内存中的示意图:

    • 语法糖:因为go语言中的指针不支持地址的修改,所以编译器会默认修改指针对应的值。也就是说,如果有一个指针类型的变量ptr,对其进行一些运算(加法运算),在使用的过程中*ptr + 2等价于ptr + 2

    1.4 指针的使用场景

    指针通常会在函数之间的传参时使用。函数在传参时是通过值传参的,比如参数是数组,在传参的过程中形参会对实参的值拷贝一份存储在形参变量中,如果这个数组很大时,那么这个过程就很浪费内存,这时就可以使用指针进行传参,不论数组有多大,传参过程中所耗费的内存空间都是固定的。

    指针传值示例:

    func modify1(x int) {
    	x = 100
    }
    
    func modify2(x *int) {
    	*x = 100
    }
    
    func main() {
    	a := 10
    	modify1(a)
    	fmt.Println(a) // 10
    	modify2(&a)
    	fmt.Println(a) // 100
    }
    

    2 new和make

    在Go语言中对于值类型的声明不需要分配内存空间,因为它们在声明的时候已经默认分配好了内存空间;而对于引用类型的以下变量,不仅要声明它,还需对其进行内存空间的分配,比如:

    var a *int的意思是a是一个int类型的指针,但是在内存中没有其存放的地方,应当声明其存放的地址,以及该地址对应的值(初始化)。

    Golang中的newmake都是内建函数,主要用来分配内存。

    2.1 new

    new函数主要给一些值类型(int系列,数组)的指针分配内存空间,其函数签名如下:

    func new(Type) *Type
    

    其中,

    • Type表示类型,new函数只接受一个参数,这个参数是一个类型
    • *Type表示类型指针,new函数返回一个指向该类型内存地址的指针

    new函数不太常用,使用new函数得到的是一个值类型的指针,并且该指针对应的值为该类型的零值。如下示例:

    func main() {
    	a := new(int)
    	b := new(bool)
    	fmt.Printf("%T
    ", a) // *int
    	fmt.Printf("%T
    ", b) // *bool
    	fmt.Println(*a)       // 0
    	fmt.Println(*b)       // false
    }
    

    在声明了一个指针变量后,需要对其进行初始化。按照如下方式使用new函数对a进行初始化以及赋值操作:

    func main() {
    	var a *int
    	a = new(int)
    	*a = 10
    	fmt.Println(*a)
    }
    

    2.2 make

    make函数主要给一些引用类型(slice,map,channel)进行初始化,该函数返回的类型就是引用类型本身,而不是指针类型。因为其本身就是引用类型,所以就没有必要返回指针。

    make的函数签名如下:

    func make(t Type, size ...IntegerType) Type
    

    make函数使用示例:

    func main() {
    	var b map[string]int	//声明了一个map类型的变量b
    	b = make(map[string]int, 10)	//开辟存储长度为10的map类型
    	b["age"] = 20
    	fmt.Println(b)
    }
    

    2.3 new和make的区别

    • 二者都是用来做内存的分配
    • make用于对引用类型的初始化,返回的是引用类型的本身
    • new用于值类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针
  • 相关阅读:
    HUD 问题
    嵌入式面试
    网上某人面试经验总结
    C中prngtf是从右到左压栈的
    哈希表
    做事原则
    学习单片机的步骤
    C#预处理器命令
    CWinApp类CMultiDocTemplate类CDocument类CView类的关系
    Windows消息大全
  • 原文地址:https://www.cnblogs.com/dabric/p/12348619.html
Copyright © 2011-2022 走看看