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:
Table of Contents
Challenge 1: Pointer Basics
Write a program that:
- Declares an integer variable and initializes it.
- Creates a pointer to the variable and modifies the value of the variable using the pointer.
- 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:
- Takes two integer pointers as arguments.
- Swaps the values of the integers they point to.
- 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