Go Pointers: 15 Challenges to Master Golang Pointer with Solution

These challenges cover various uses of pointers, such as in functions, structs, maps, and linked lists, giving you a comprehensive understanding of how pointers work in Go.

Here are some programming challenges focused on Golang pointers to help you strengthen your understanding:

Challenge 1: Pointer Basics

Write a program that:

  1. Declares an integer variable and initializes it.
  2. Creates a pointer to the variable and modifies the value of the variable using the pointer.
  3. Prints the address of the variable and verifies the changes.

Code:

package main

import "fmt"

func main() {
    var x int = 10
    var ptr *int = &x

    fmt.Println("Before modification:")
    fmt.Println("Value of x:", x)
    fmt.Println("Address of x:", &x)
    fmt.Println("Pointer ptr:", ptr)

    *ptr = 20 // Modify x through the pointer

    fmt.Println("\nAfter modification:")
    fmt.Println("Value of x:", x)
}

Output:

Before modification:
Value of x: 10
Address of x: 0xc0000120b0
Pointer ptr: 0xc0000120b0

After modification:
Value of x: 20

Challenge 2: Pointer Swap Function

Create a function swap(a, b *int) that:

  1. Takes two integer pointers as arguments.
  2. Swaps the values of the integers they point to.
  3. Test the function with sample values.

Code:

package main

import "fmt"

func swap(a, b *int) {
    *a, *b = *b, *a
}

func main() {
    x, y := 5, 10
    fmt.Println("Before swap:")
    fmt.Println("x =", x, "y =", y)

    swap(&x, &y)

    fmt.Println("\nAfter swap:")
    fmt.Println("x =", x, "y =", y)
}

Output:

Before swap:
x = 5 y = 10

After swap:
x = 10 y = 5

Challenge 3: Pointer to a Struct

Define a struct Person with fields Name (string) and Age (int). Create a pointer to a Person instance and update the fields using the pointer. Print the updated struct.

Code:

package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

func main() {
    p := &Person{Name: "Alice", Age: 25}
    fmt.Println("Before update:", *p)

    p.Age = 30 // Update using the pointer
    fmt.Println("After update:", *p)
}

Output:

Before update: {Alice 25}
After update: {Alice 30}

Challenge 4: Array Pointer Manipulation

Declare an array of integers. Create a pointer to the array.Use the pointer to update the elements of the array. Print the updated array.

Code:

package main

import "fmt"

func main() {
    arr := [3]int{1, 2, 3}
    ptr := &arr

    fmt.Println("Before modification:", arr)

    (*ptr)[0] = 10
    (*ptr)[1] = 20

    fmt.Println("After modification:", arr)
}

Output:

Before modification: [1 2 3]
After modification: [10 20 3]

Challenge 5: Pointer to Pointer

Create an integer variable and a pointer to it. Create a pointer to the pointer. Modify the integer’s value using the pointer-to-pointer and print the changes.

Code:

package main

import "fmt"

func main() {
    x := 42
    ptr := &x
    ptrToPtr := &ptr

    fmt.Println("Value of x:", x)
    fmt.Println("Address of x:", ptr)
    fmt.Println("Pointer to pointer:", ptrToPtr)

    **ptrToPtr = 100 // Modify x through the pointer-to-pointer
    fmt.Println("\nValue of x after modification:", x)
}

Output:

Value of x: 42
Address of x: 0xc0000120b0
Pointer to pointer: 0xc00000e028

Value of x after modification: 100

Challenge 6: Dynamic Memory Allocation

Use the new function to create an integer pointer dynamically.Assign a value to the dynamically allocated memory.Print the value and free the memory using nil.

Code:

package main

import "fmt"

func main() {
    ptr := new(int) // Dynamically allocate memory
    *ptr = 42       // Assign value

    fmt.Println("Value:", *ptr)
    fmt.Println("Address:", ptr)

    ptr = nil // Free the memory
}

Output:

Value: 42
Address: 0xc0000120b0

Challenge 7: Slicing with Pointers

Create a slice of integers and a pointer to the slice. Write a function updateSlice(slice *[]int) that appends a new value to the slice using the pointer. Print the slice before and after the function call.

Code:

package main

import "fmt"

func updateSlice(slice *[]int) {
    *slice = append(*slice, 99)
}

func main() {
    nums := []int{1, 2, 3}
    fmt.Println("Before update:", nums)

    updateSlice(&nums)

    fmt.Println("After update:", nums)
}

Output:

Before update: [1 2 3]
After update: [1 2 3 99]

Challenge 8: Pointer Receiver in Methods

Define a struct Rectangle with fields Length and Width. Implement a method Scale(factor float64) with a pointer receiver that scales the rectangle dimensions by the given factor. Demonstrate the use of the method.

Code:

package main

import "fmt"

type Rectangle struct {
    Length, Width float64
}

func (r *Rectangle) Scale(factor float64) {
    r.Length *= factor
    r.Width *= factor
}

func main() {
    rect := &Rectangle{Length: 5, Width: 3}
    fmt.Println("Before scaling:", *rect)

    rect.Scale(2) // Scale dimensions
    fmt.Println("After scaling:", *rect)
}

Output:

Before scaling: {5 3}
After scaling: {10 6}

Challenge 9: Pointer Arithmetic Simulation

Simulate pointer arithmetic by iterating through an array using an index and a pointer. Write a function that prints the elements of an array using only pointers.

Code:

package main

import "fmt"

func printArray(arr *[5]int) {
    for i := 0; i < len(arr); i++ {
        fmt.Printf("Element %d: %d\n", i, (*arr)[i])
    }
}

func main() {
    arr := [5]int{10, 20, 30, 40, 50}
    printArray(&arr)
}

Output:

Element 0: 10
Element 1: 20
Element 2: 30
Element 3: 40
Element 4: 50

Challenge 10: Function Pointers

Declare a function double(x int) int that doubles a given integer.Declare a function pointer to the double function. Use the function pointer to call the function and print the result.

Code:

package main

import "fmt"

func double(x int) int {
    return x * 2
}

func main() {
    var funcPtr func(int) int
    funcPtr = double

    value := 10
    result := funcPtr(value)
    fmt.Println("Value:", value)
    fmt.Println("Doubled value:", result)
}

Output:

Value: 10
Doubled value: 20

Challenge 11: Safe Dereferencing

Write a function safeDeref(ptr *int) that safely dereferences a pointer.If the pointer is nil, return a default value (e.g., 0). Test the function with a valid and a nil pointer.

Code:

package main

import "fmt"

func safeDeref(ptr *int) int {
    if ptr == nil {
        return 0
    }
    return *ptr
}

func main() {
    var a int = 42
    var ptr1 *int = &a
    var ptr2 *int = nil

    fmt.Println("Safe dereference (valid pointer):", safeDeref(ptr1))
    fmt.Println("Safe dereference (nil pointer):", safeDeref(ptr2))
}

Output:

Safe dereference (valid pointer): 42
Safe dereference (nil pointer): 0

Challenge 12: Linked List with Pointers

Implement a simple singly linked list using struct and pointers.Define a Node struct with Value (int) and Next (*Node).Write functions to:

  • Insert a value at the end of the list.
  • Print all the values in the list.

Demonstrate the implementation with sample inputs.

Code:

package main

import "fmt"

type Node struct {
    Value int
    Next  *Node
}

type LinkedList struct {
    Head *Node
}

func (ll *LinkedList) Insert(value int) {
    newNode := &Node{Value: value}
    if ll.Head == nil {
        ll.Head = newNode
    } else {
        current := ll.Head
        for current.Next != nil {
            current = current.Next
        }
        current.Next = newNode
    }
}

func (ll *LinkedList) Print() {
    current := ll.Head
    for current != nil {
        fmt.Printf("%d -> ", current.Value)
        current = current.Next
    }
    fmt.Println("nil")
}

func main() {
    ll := LinkedList{}
    ll.Insert(10)
    ll.Insert(20)
    ll.Insert(30)

    ll.Print()
}

Output:

10 -> 20 -> 30 -> nil

Challenge 13: Pointer to Map

Create a map of string to int.Write a function updateMap(mp *map[string]int) that adds a new key-value pair to the map using its pointer. Test the function with a sample map.

Code:

package main

import "fmt"

func updateMap(mp *map[string]int) {
    (*mp)["newKey"] = 99
}

func main() {
    myMap := map[string]int{"existingKey": 1}
    fmt.Println("Before update:", myMap)

    updateMap(&myMap)
    fmt.Println("After update:", myMap)
}

Output:

Before update: map[existingKey:1]
After update: map[existingKey:1 newKey:99]

Challenge 14: Pass by Pointer

Write a function increment(ptr *int) that increments the value of the integer the pointer points to. Call the function with a variable and verify the incremented value.

Code:

package main

import "fmt"

func increment(ptr *int) {
    *ptr++
}

func main() {
    x := 5
    fmt.Println("Before increment:", x)

    increment(&x)
    fmt.Println("After increment:", x)
}

Output:

Before increment: 5
After increment: 6

Challenge 15: Circular References

Create two structs A and B. Each struct should contain a pointer to the other. Initialize these structs and ensure no runtime errors occur.

Code:

package main

import "fmt"

type A struct {
    Value int
    BRef  *B
}

type B struct {
    Value int
    ARef  *A
}

func main() {
    a := A{Value: 10}
    b := B{Value: 20}

    a.BRef = &b
    b.ARef = &a

    fmt.Println("A's value:", a.Value, "B's value through A:", a.BRef.Value)
    fmt.Println("B's value:", b.Value, "A's value through B:", b.ARef.Value)
}

Output:

A's value: 10 B's value through A: 20
B's value: 20 A's value through B: 10