Understanding Pointer Values and Their Printing in Go

Dec 07, 2025 · Programming · 14 views · 7.8

Keywords: Go language | pointers | parameter passing

Abstract: This article provides an in-depth analysis of pointer values in Go, including their meaning, printing methods, and behavior during function parameter passing. Through detailed code examples, it explains why printing the address of the same pointer variable in different scopes yields different values, clarifying Go's pass-by-value nature. The article thoroughly examines the relationship between pointer variables and the objects they point to, offering practical recommendations for using the fmt package to correctly print pointer information and helping developers build accurate mental models of memory management.

Fundamental Concepts of Pointer Values

In Go, a pointer is a special data type that stores the memory address of another variable. Understanding the meaning of pointer values is crucial for mastering Go's memory management mechanisms. A pointer value essentially serves as an identifier for a memory location, through which data stored at that location can be accessed.

Function Parameter Passing Mechanism

Go strictly adheres to the principle of pass-by-value. This means that when a function is called, the values of all arguments are copied into the function's parameter variables. For pointer-type parameters, what gets copied is the pointer value (i.e., the memory address), not the data pointed to by the pointer.

Consider the following simplified example:

package main

import "fmt"

func byval(q *int) {
    fmt.Printf("3. byval -- q %T: &q=%p q=&i=%p  *q=i=%v\n", q, &q, q, *q)
    *q = 4143
    fmt.Printf("4. byval -- q %T: &q=%p q=&i=%p  *q=i=%v\n", q, &q, q, *q)
    q = nil
}

func main() {
    i := int(42)
    fmt.Printf("1. main  -- i  %T: &i=%p i=%v\n", i, &i, i)
    p := &i
    fmt.Printf("2. main  -- p %T: &p=%p p=&i=%p  *p=i=%v\n", p, &p, p, *p)
    byval(p)
    fmt.Printf("5. main  -- p %T: &p=%p p=&i=%p  *p=i=%v\n", p, &p, p, *p)
    fmt.Printf("6. main  -- i  %T: &i=%p i=%v\n", i, &i, i)
}

The program output clearly demonstrates the pointer passing process:

1. main  -- i  int: &i=0xf840000040 i=42
2. main  -- p *int: &p=0xf8400000f0 p=&i=0xf840000040  *p=i=42
3. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040  *q=i=42
4. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040  *q=i=4143
5. main  -- p *int: &p=0xf8400000f0 p=&i=0xf840000040  *p=i=4143
6. main  -- i  int: &i=0xf840000040 i=4143

Reason for Pointer Address Differences

In the original question, the user observed that printing &s in the main function and in the goroutine yielded different address values: 0x4930d4 and 0x4974d8. This occurs because &s prints the memory address of the pointer variable s itself, not the address of the object that s points to.

In the main function, s is a variable of type *Something, stored at address 0x4930d4. When this variable is passed as an argument to the gotest function, Go creates a new parameter variable (also named s) stored at address 0x4974d8. Although these two variables reside at different memory locations, they contain the same pointer value—both point to the same Something object.

Correct Methods for Printing Pointers

Using println(&s) to print pointer information has limitations, as it prints the address of the pointer variable rather than the address of the object it points to. It is recommended to use the formatting capabilities provided by the fmt package:

fmt.Printf("%v %p %v\n", &s, s, *s)

Where:

Pointers and Object Identity

Go does not provide an object ID concept similar to Java. The unique identifier of an object is its memory address. When two pointer variables contain the same memory address value, they point to the same object. It is important to note that pointer values may change during program execution due to garbage collector relocation of objects, but this is an internal behavior of the runtime system and is transparent to programmers.

Practical Recommendations

  1. Clearly distinguish between the address of a pointer variable and the address of the object it points to
  2. Understand Go's strict pass-by-value mechanism, including the copying of pointer values
  3. Use the fmt package instead of println for debugging output
  4. Avoid using printed pointer values to determine object identity; instead, use object content or business logic for such determinations

By deeply understanding pointer passing mechanisms, developers can better master Go's memory model and write more efficient, reliable concurrent programs.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.