Pointers in Go

In Go lang, pointers are special variables that are used to store the memory address of other variables and point to their memory address. Pointers also provide ways to access the value of the variable stored in that address.

The * operator: While declaring a pointer, the pointer name is followed by the type of the variable the pointer points to, prefixed with the * sign as shown below. This is also known as dereferencing the pointer variable.

The following declares a pointer variable of int type:

Example: Declare Pointer
var mypointer *int

The above code creates a pointer named mypointer which points to an int type variable. The * operator is used to make a variable as pointer.

The following example demonstrates the use of pointer.

Example: Use Pointers
package main

import "fmt"

func main() {
	//Declare a variable
    var num int = 100

    //Declare a pointer variable
    var intPtr *int
	
    //Assign the address of the variable to the pointer
    intPtr = &num

    fmt.Println(&num)  //prints the address of num variable
    fmt.Println(intPtr)  //prints the address of num variable
    fmt.Println(*intPtr) //prints the value of num variable
}
Output:
0xc0000aa058
0xc0000aa058
100      

In the above example, var intPtr *int declares int type pointer. The intPtr = &num assigns the address of num to the pointer intPtr. The memory address of this variable is derived by prefixing the & sign to the variable name as &num. Now, the pointer intPtr points to the address of num.

The fmt.Println(&num) displays a hexadecimal memory address of the variable num which can be different in different machine/OS. So, &num and intPtr both display the same address.

To access the value in the memory address the pointer is pointing to, use the asterisk (*) sign in front of the pointer name as *intPtr. This prints the value 100.

To summarize the pointer operations:

  1. Pointer variables have to be declared before they can be used.
  2. It is then assigned the address of another variable by using the & operator.
  3. The value of the data in the address is accessed using the * operator.

Nil Pointers

If a pointer variable is not assigned to an address of a variable then it is called nil pointer. Any uninitialized pointer will have <nil> value.

Example: Nil Pointer
package main
import "fmt"

func main() {
	var intPtr *int
	fmt.Println(intPtr) //output: <nil>
}

Passing Pointers to Functions as Arguments

A pointer can be passed as an argument to a function just like passing any other variable. While creating the function, the argument has to be declared as of type pointer.

In the following example, a function is created to accept a pointer as its argument.

Example: Passing Pointer to Function
package main
import "fmt"

func myfunction(pvar *int){
     *pvar = *pvar + 10
}

func main() {
	var x int = 25
	fmt.Println("Before function call: = ", x)

    //Assign the memory address of the variable x to pointer intPtr
    var intPtr *int = &x 

    // call the function pf and pass pointer intPtr as its argument.
    myfunction(intPtr)
	fmt.Println("After function call ", x)

    //passing address of variable as pointer parameter
    myfunction(&x)
    fmt.Println("After passing Address", x)
}
Output:
Before function call: =  25
After function call  35
After passing Address 45

Pointer to a Pointer

A pointer contains the address of a variable. If another pointer is declared pointing to the first pointer which in turn contains the address of a variable, it is called a pointer to a pointer or a double pointer.

Pointer to Pointer in Go

A pointer to a pointer is declared with two asterisks prefixed to the type e.g. var ptrB **int. In the above figure, pointer ptrA contains the address of the variable X and pointer ptrB holds the address of the pointer ptrA. You can get the value of X using *ptrA. To get the the value of X from the double pointer ptrB, use **ptrB.

Example: Pointer to Pointer
package main
import "fmt"

func main() {
	// declare and initialize variable X
	var X int = 100

	// declare pointer and initialize to the address of the variable X
    var ptrA *int = &X
	
    // declare pointer and point to pointer ptrA
    var ptrB **int = &ptrA
	
	fmt.Printf("Value of variable X: %d\n", X)
    fmt.Printf("Address of variable X: %d\n", &X)
    fmt.Printf("Value of pointer ptrA: %d\n", ptrA)
	fmt.Printf("Address of pointer ptrA: %d\n", &ptrA)
    fmt.Printf("Value of pointer ptrB: %d\n", ptrB)
	
    // dereferencing of pointers. Getting the value of X
	fmt.Printf("Value of X from ptrA : %d\n", *ptrA)
	fmt.Printf("Value of X from ptrB : %d\n", **ptrB)
}
Output:
Value of variable X: 100
Address of variable X: 824634286080
Value of pointer ptrA: 824634286080
Address of pointer ptrA: 824634245144
Value of pointer ptrB: 824634245144
Value of X from ptrA : 100
Value of X from ptrB : 100

In the above example, a variable X is declared and assigned a value of 100. A pointer ptrA is declared and initialized with the address of the variable. Another pointer ptrB is declared pointing to the pointer ptrA.

To get the value of the variable from the double-pointer, two asterisks are prefixed to the double pointer name.

Comparing Pointers

In Go programming, two pointers can be compared with each other. The two pointers will be equal if they point to the same memory location and hence have the same value. The == (equal to) and != (not equal to) operators are used for comparison.

Example: Compare Pointers
package main
import "fmt"

func main() {
	// declare and initialize variable X
	var X int = 100

	// declare pointer and initialize to the address of the variable X
    var ptrA *int = &X
	
    // declare pointer and point to pointer ptrA
    var ptrB **int = &ptrA
	
	fmt.Println(ptrA == &X) //true
    fmt.Println(*ptrA == X) //true
	
	fmt.Println(ptrB == &ptrA) //true
    fmt.Println(*ptrB == ptrA) //true
}	

Array of Pointers

In Go, we can create array which stores pointers. The following example shows how to create and use an array of pointers.

Example: Array of Pointers
package main
import "fmt"

func main() {
    arr := []int{10, 20, 30}
    var i int
    var ptrArr [3]*int;
	
    for  i = 0; i < 3; i++ {
        //assign the address of each element of arr to ptrArr. 
        ptrArr[i] = &arr[i] 
    }

    for  i = 0; i < 3; i++ {
	    fmt.Printf("*ptrArr[%d] = %d\n", i,*ptrArr[i] )
    }
}
Output:
*ptrArr[0] = 10
*ptrArr[1] = 20
*ptrArr[2] = 30

In the above example, ptrArr is an array of int type pointers that can store 3 pointers. In the first for loop, the address of each value of arr array is assigned to a member of ptrArr. In the second for loop, the value (*ptrArr) held by the array pointers is printed as output.