Go语言 指针

  • 指针

    Go语言中的指针既简单又有趣。使用指针可以更轻松地执行某些Go编程任务,而如果不使用指针则无法执行其他任务(例如,按引用调用)。因此,有必要学习指针成为理想的Go程序员。如您所知,每个变量都是一个内存位置,并且每个内存位置都定义了其地址,可以使用&运算符(&)进行访问,该地址表示内存中的地址。考虑以下示例,它将打印定义的变量的地址-
    
    package main
    
    import "fmt"
    
    func main() {
       var a int = 10   
       fmt.Printf("Address of a variable: %x\n", &a  )
    }
    
    尝试一下
    编译并执行上述代码后,将产生以下结果-
    
    Address of a variable: c0000a6010
    
    因此,您了解了什么是内存地址以及如何访问它。现在让我们看看什么是指针。
  • 什么是指针?

    指针是一个变量,其值是另一个变量的地址,即存储位置的直接地址。像任何变量或常量一样,必须先声明一个指针,然后才能使用它存储任何变量地址。指针变量声明的一般形式是-
    
    var var_name *var-type
    
    在这里,var-type是指针的基本类型。它必须是有效的C数据类型,并且var-name是指针变量的名称。用于声明指针的星号*与用于乘法的星号相同。但是,在此语句中,星号用于将变量指定为指针。以下是有效的指针声明-
    
    var ip *int        /* pointer to an integer */
    var fp *float32    /* pointer to a float */
    
    所有指针的值的实际数据类型(不管是整数、浮点数还是其他类型)都是相同的,即表示内存地址的长十六进制数。不同数据类型的指针之间的唯一区别是指针所指向的变量或常量的数据类型。
  • 如何使用指针?

    我们经常使用指针执行一些重要的操作:
    • (a)我们定义指针变量,
    • (b)将变量的地址分配给指针,
    • (c)访问指针变量中存储的地址处的值。
    所有这些操作都是使用一元运算符*进行的,该运算符返回位于其操作数指定地址处的变量的值。以下示例演示如何执行这些操作-
    
    package main
    
    import "fmt"
    
    func main() {
       var a int = 20   /* actual variable declaration */
       var ip *int      /* pointer variable declaration */
    
       ip = &a  /* store address of a in pointer variable*/
    
       fmt.Printf("Address of a variable: %x\n", &a  )
    
       /* address stored in pointer variable */
       fmt.Printf("Address stored in ip variable: %x\n", ip )
    
       /* access the value using the pointer */
       fmt.Printf("Value of *ip variable: %d\n", *ip )
    }
    
    尝试一下
    编译并执行上述代码后,将产生以下结果-
    
    Address of var variable: 10328000
    Address stored in ip variable: 10328000
    Value of *ip variable: 20
    
  • nil 指针

    如果您没有要分配的确切地址,则Go编译器将Nil值分配给指针变量。这是在变量声明时完成的。分配为nil的指针称为nil指针。nil指针是在几个标准库中定义的值为零的常量。考虑以下程序-
    
    package main
    
    import "fmt"
    
    func main() {
       var  ptr *int
    
       fmt.Printf("The value of ptr is : %x\n", ptr  )
    }
    
    尝试一下
    编译并执行上述代码后,将产生以下结果-
    
    The value of ptr is 0
    
    在大多数操作系统上,不允许程序访问地址0处的内存,因为该内存是由操作系统保留的。但是,存储器地址0具有特殊的意义。它指示指针不旨在指向可访问的存储位置。但是按照惯例,如果指针包含nil(零)值,则假定该指针不指向任何内容。要检查nil指针,可以使用以下if语句-
    
    if(ptr != nil)     /* succeeds if p is not nil */
    if(ptr == nil)    /* succeeds if p is null */
    
  • 指针数组

    在理解指针数组的概念之前,让我们考虑以下示例,该示例使用3个整数的数组-
    
    package main
    
    import "fmt"
     
    const MAX int = 3
     
    func main() {
       a := []int{10,100,200}
       var i int
    
       for i = 0; i < MAX; i++ {
          fmt.Printf("Value of a[%d] = %d\n", i, a[i] )
       }
    }
    
    尝试一下
    编译并执行上述代码后,将产生以下结果-
    
    Value of a[0] = 10
    Value of a[1] = 100
    Value of a2] = 200
    
    在某些情况下,我们需要维护一个数组,该数组可以存储指向int或字符串或任何其他可用数据类型的指针。以下语句声明了一个指向整数的指针的数组-
    
    var ptr [MAX]*int;
    
    这将ptr声明为MAX个整数指针的数组。因此,ptr中的每个元素现在都拥有一个指向int值的指针。以下示例使用三个整数,这些整数将按如下方式存储在指针数组中:
    
    package main
    
    import "fmt"
     
    const MAX int = 3
     
    func main() {
       a := []int{10,100,200}
       var i int
       var ptr [MAX]*int;
    
       for  i = 0; i < MAX; i++ {
          ptr[i] = &a[i] /* assign the address of integer. */
       }
       for  i = 0; i < MAX; i++ {
          fmt.Printf("Value of a[%d] = %d\n", i,*ptr[i] )
       }
    }
    
    尝试一下
    编译并执行上述代码后,将产生以下结果-
    
    Value of a[0] = 10
    Value of a[1] = 100
    Value of a[2] = 200
    
  • 指针指向指针

    指向指针的指针是指针链的一种形式。通常,指针包含变量的地址。当我们定义一个指向指针的指针时,第一个指针包含第二个指针的地址,该地址指向包含实际值的位置,如下所示。
    pointer
    作为指针的指针的变量必须这样声明。这是通过在其名称前面放置一个额外的星号来完成的。例如,以下语句声明一个指向int类型的指针的指针-
    
    var ptr **int;
    
    当指向指针的指针间接指向目标值时,访问该值需要两次应用星号运算符,如以下示例所示-
    
    package main
    
    import "fmt"
    
    func main() {
       var a int
       var ptr *int
       var pptr **int
    
       a = 3000
    
       /* take the address of var */
       ptr = &a
    
       /* take the address of ptr using address of operator & */
       pptr = &ptr
    
       /* take the value using pptr */
       fmt.Printf("Value of a = %d\n", a )
       fmt.Printf("Value available at *ptr = %d\n", *ptr )
       fmt.Printf("Value available at **pptr = %d\n", **pptr)
    }
    
    尝试一下
    编译并执行上述代码后,将产生以下结果-
    将数组传递给函数
    
    Value of var = 3000
    Value available at *ptr = 3000
    Value available at **pptr = 3000
    
  • 指针传递给函数

    Go编程语言使您可以将指针传递给函数。为此,只需将函数参数声明为指针类型。在下面的示例中,我们将两个指针传递给一个函数,并更改该函数内部的值,该值会反映在调用函数中
    
    package main
    
    import "fmt"
    
    func main() {
       /* local variable definition */
       var a int = 100
       var b int = 200
    
       fmt.Printf("Before swap, value of a : %d\n", a )
       fmt.Printf("Before swap, value of b : %d\n", b )
    
       /* calling a function to swap the values.
       * &a indicates pointer to a ie. address of variable a and 
       * &b indicates pointer to b ie. address of variable b.
       */
       swap(&a, &b);
    
       fmt.Printf("After swap, value of a : %d\n", a )
       fmt.Printf("After swap, value of b : %d\n", b )
    }
    func swap(x *int, y *int) {
       var temp int
       temp = *x    /* save the value at address x */
       *x = *y      /* put y into x */
       *y = temp    /* put temp into y */
    }
    
    尝试一下
    编译并执行上述代码后,将产生以下结果-
    
    Before swap, value of a :100
    Before swap, value of b :200
    After swap, value of a :200
    After swap, value of b :100