# 2. References

It's possible to define an empty pointer. For example, an empty pointer to an integer:

```go
var p *int

fmt.Printf("value of p: %v\n", p)
// value of p: <nil>
```

Its zero value is `nil`, which means it doesn't point to any memory address. Empty pointers are also called "nil pointers".

Instead of starting with a nil pointer, it's common to use the `&` operator to get a pointer to its operand:

```go
myString := "hello"      // myString is just a string
myStringPtr := &myString // myStringPtr is a pointer to myString's address

fmt.Printf("value of myStringPtr: %v\n", myStringPtr)
// value of myStringPtr: 0x140c050
```

A pointer is a variable that stores the **memory address** of another variable, rather than storing a value directly.

Think of it like this:

* A normal variable is like a box that contains a value
* A pointer is like a box that contains the **address** of another box

### Creating a Pointer

#### Method 1: Nil Pointer (Empty)

```go
var p *int
```

* `*int` means "pointer to an integer"
* `p` doesn't point to anything yet
* Its value is `nil` (nothing)

```go
fmt.Println(p)  // <nil>
```

#### Method 2: Get Address with `&`

```go
myString := "hello"
myStringPtr := &myString
```

* `myString` is a regular variable containing `"hello"`
* `&myString` gets the **address** of `myString`
* `myStringPtr` now stores that address

```go
fmt.Println(myString)     // "hello"
fmt.Println(myStringPtr)  // 0x140c050 (memory address)
```

### The `&` Operator: "Address Of"

`&` means "give me the address of this variable"

```go
x := 42
pointerToX := &x

fmt.Println(x)          // 42 (the value)
fmt.Println(pointerToX) // 0x... (the address where 42 is stored)
```

### The `*` Operator: Two Uses

The `*` symbol does two different things depending on context:

#### Use 1: Declare a Pointer Type

```go
var p *int
    ^
    └─ "p is a pointer to an int"
```

#### Use 2: Dereference (Get the Value)

```go
*p = 100
^
└─ "Go to the address stored in p and change the value there to 100"
```

### Dereference

The `*` operator dereferences a pointer to get the original value.

```go
*myStringPtr = "world"                              // set myString through the pointer
fmt.Printf("value of myString: %s\n", *myStringPtr) // read myString through the pointer
// value of myString: world
```

Unlike C, Go has no pointer arithmetic (which is covered in our [Learn Memory Management course](https://www.boot.dev/courses/learn-memory-management) if you haven't taken it already).

**Dereferencing** means "follow the pointer to get the actual value"

```go
myString := "hello"
myStringPtr := &myString  // myStringPtr stores the address of myString

// Read through the pointer
value := *myStringPtr
fmt.Println(value)  // "hello"

// Write through the pointer
*myStringPtr = "world"
fmt.Println(myString)  // "world" - myString was changed!
```

### Complete Example

{% code title="main.go" %}

```go
package main

import "fmt"

func main() {
    // Create a normal variable
    age := 25
    
    // Get a pointer to it
    agePtr := &age
    
    fmt.Println("age:", age)           // age: 25
    fmt.Println("agePtr:", agePtr)     // agePtr: 0x... (address)
    fmt.Println("*agePtr:", *agePtr)   // *agePtr: 25 (value at that address)
    
    // Change the value through the pointer
    *agePtr = 30
    
    fmt.Println("age:", age)           // age: 30 (changed!)
    fmt.Println("*agePtr:", *agePtr)   // *agePtr: 30
}
```

{% endcode %}

### Visual Representation

```
Memory:
Address    Value
0x1000     25      ← age variable lives here
0x2000     0x1000  ← agePtr lives here, contains address 0x1000

age          = 25
&age         = 0x1000 (address of age)
agePtr       = 0x1000 (stores the address)
*agePtr      = 25 (follow the pointer to get the value)
```

### Why Use Pointers?

#### Reason 1: Modify Variables in Functions

Without pointers:

```go
func tryToChange(x int) {
    x = 100  // Only changes the copy
}

func main() {
    age := 25
    tryToChange(age)
    fmt.Println(age)  // Still 25 (didn't change)
}
```

With pointers:

```go
func actuallyChange(x *int) {
    *x = 100  // Changes the original
}

func main() {
    age := 25
    actuallyChange(&age)
    fmt.Println(age)  // 100 (changed!)
}
```

#### Reason 2: Efficiency with Large Data

Copying a pointer is cheaper than copying a large struct:

```go
type HugeStruct struct {
    // lots of fields
}

// Copies the entire struct (slow)
func process(data HugeStruct) {
}

// Only copies the pointer (fast)
func processPtr(data *HugeStruct) {
}
```

### Key Syntax Summary

| Symbol     | Meaning                   | Example         |
| ---------- | ------------------------- | --------------- |
| `*int`     | Type: pointer to int      | `var p *int`    |
| `&x`       | Get address of x          | `ptr := &x`     |
| `*ptr`     | Dereference: get value    | `value := *ptr` |
| `*ptr = 5` | Set value through pointer | `*ptr = 5`      |

### Common Pattern

{% stepper %}
{% step %}

### Create a variable

```go
x := 10
```

{% endstep %}

{% step %}

### Get its address

```go
ptr := &x
```

{% endstep %}

{% step %}

### Read through pointer

```go
fmt.Println(*ptr)  // 10
```

{% endstep %}

{% step %}

### Write through pointer

```go
*ptr = 20
```

{% endstep %}

{% step %}

### Original variable changed

```go
fmt.Println(x)  // 20
```

{% endstep %}
{% endstepper %}

### What "No Pointer Arithmetic" Means

In C, you can do:

```c
int arr[5];
int *p = arr;
p++;  // Move pointer to next element
```

Go doesn't allow this. You can't do math on pointers. If you want to work with multiple elements, use slices instead.

### Practice Understanding

```go
a := 5
b := &a
*b = 10

fmt.Println(a)  // What prints? 10
fmt.Println(b)  // What prints? (address, like 0x...)
fmt.Println(*b) // What prints? 10
```

### Assignment

Complete the `removeProfanity` function.

It should use the [strings.ReplaceAll](https://pkg.go.dev/strings#ReplaceAll) function to replace all instances of the following words in the input `message` with asterisks.

| Word  | Replacement |
| ----- | ----------- |
| fubb  | \*\*\*\*    |
| shiz  | \*\*\*\*    |
| witch | \*\*\*\*\*  |

## Solution

```go
package main

import (
	"strings"
)

func removeProfanity(message *string) {

	*message = strings.ReplaceAll(*message, "fubb", "****")
	*message = strings.ReplaceAll(*message, "shiz", "****")
	*message = strings.ReplaceAll(*message, "witch", "*****")
}
```

### Dynamic Solution

```go
package main

import (
	"strings"
)

func removeProfanity(message *string) {

	badWords := map[string]string{
		"fubb":  "****",
		"shiz":  "****",
		"witch": "*****",
	}

	for word, replacement := range badWords {
		*message = strings.ReplaceAll(*message, word, replacement)
	}
}
```

### Dynamic Replacement (Count the Letters)

If you want to automatically create the right number of asterisks:

```go
func removeProfanity(message *string) {
    badWords := []string{"fubb", "shiz", "witch"}
    
    for _, word := range badWords {
        // Create asterisks equal to word length
        asterisks := strings.Repeat("*", len(word))
        *message = strings.ReplaceAll(*message, word, asterisks)
    }
}
```

#### How `strings.Repeat` Works

```go
strings.Repeat("*", 4)  // "****"
strings.Repeat("*", 5)  // "*****"
strings.Repeat("a", 3)  // "aaa"
```
