一文看懂!编程语言访问变量指针和复制值

1 简介

当使用允许访问指针值的编程语言(如 Java、C#、C/C++、Go 等)时,通常必须小心区分按值传递和按引用传递。 本文通过概念和示例说明如何访问指针和复制值。

markdown 复制代码
                按值传递                            按引用传递
        将函数参数的值复制到另一个变量的机制         将实际参数传递给函数的机制
        在函数中所做的更改不会反映在原始值中        在函数中所做的更改反映在原始值
        复制实际参数                       实际参数的地址传递给函数
        函数获取实际内容的副本                 函数访问原始变量的内容
        需要更多内存                         需要较少内存
        需要更多时间,因为它涉及复制值           由于没有复制,因此需要的时间更少

分别看看结构体和指针数组在按值和按引用传递时的区别。Go 语言里这两个类型都有明显的行为差异,非常适合用来理解这个概念。

csharp 复制代码
	按值传递:使用按值传递时,函数参数的值将复制到内存中的另一个位置。在该函数中,仅访问或修改变量的副本。因此,原始值不受影响。
	Passing by reference:使用按引用传递时,将向该函数提供内存地址。换句话说,该函数可以访问 real 变量。

2 结构体(struct)

  • 按值传递结构体

函数接收的是结构体的副本。修改不会影响原始结构体。

go 复制代码
		package main

		import "fmt"

		type Person struct {
		    name string
		    age  int
		}

		func changePerson(p Person) {
		    p.age = 99
		    p.name = "Changed"
		}

		func main() {
		    p := Person{name: "Tom", age: 30}
		    changePerson(p)
		    fmt.Println("main:", p) // 输出: main: {Tom 30}
		}
  • 按引用传递结构体(传指针)

函数接收的是结构体的地址。修改会影响原始结构体。

css 复制代码
		func changePersonByRef(p *Person) {
		    p.age = 99
		    p.name = "Changed"
		}

		func main() {
		    p := Person{name: "Tom", age: 30}
		    changePersonByRef(&p)
		    fmt.Println("main:", p) // 输出: main: {Changed 99}
		}

2 针数组(数组中存的是指针)

这是一个有点绕的场景,但也非常常见。我们来仔细看一下。

  • 1 指针数组按值传递(传的是数组副本)

    go 复制代码
     func changeArray(arr [2]*int) {
         x := 100
         arr[0] = &x // 改变了指针指向
     }
    
     func main() {
         a, b := 1, 2
         arr := [2]*int{&a, &b}
         changeArray(arr)
         fmt.Println(*arr[0]) // 输出: 1,未改变原数组内容
     }

虽然修改了 arr[0] 的指针,但只是副本,原数组没变。

    1. 指针数组按引用传递(传指针数组的指针)

      go 复制代码
                 func changeArrayByRef(arr *[2]*int) {
                     x := 100
                     arr[0] = &x // 修改了原始数组中的指针
                 }
      
                 func main() {
                     a, b := 1, 2
                     arr := [2]*int{&a, &b}
                     changeArrayByRef(&arr)
                     fmt.Println(*arr[0]) // 输出: 100,改变了原数组内容
                 }
             
    1. 修改指针数组中指向的值(不改指向,只改值)

      css 复制代码
         func modifyPointedValue(arr [2]*int) {
             *arr[0] = 999
         }
      
         func main() {
             a, b := 1, 2
             arr := [2]*int{&a, &b}
             modifyPointedValue(arr)
             fmt.Println(a) // 输出: 999,值被改变
         }

虽然数组本身是按值传递,但指针指向的是同一个地址,对值的修改仍然生效。

3 小结

按值传递是指将函数参数值复制到另一个变量的机制,而按引用传递是指将实际参数传递给函数的机制。因此,这是按值传递和按引用传递之间的主要区别。

markdown 复制代码
        类型	   是否需要指针来传引用	    修改指针本身	修改指向的值
        结构体  	    ✅	                  ✅	                ✅
        指针数组         ✅(如果改数组内容)  ✅	             不需要
        数组中的指针值	不需要	          ---	             ✅

如果需要处理较大的结构体,推荐用指针传参,减少复制开销。

参考:

ruby 复制代码
https://go.dev/tour/basics/11 https://go.dev/doc/effective_go
相关推荐
天上掉下来个程小白1 小时前
添加购物车-02.代码开发
java·服务器·前端·后端·spring·微信小程序·苍穹外卖
幽络源小助理2 小时前
懒人美食帮SpringBoot订餐系统开发实现
java·spring boot·后端·美食
源码云商4 小时前
基于Spring Boot + Vue的母婴商城系统( 前后端分离)
java·spring boot·后端
还听珊瑚海吗8 小时前
基于SpringBoot的抽奖系统测试报告
java·spring boot·后端
你怎么知道我是队长11 小时前
Go语言标识符
后端·golang
sco528214 小时前
SpringBoot 自动装配原理 & 自定义一个 starter
java·spring boot·后端
海风极客16 小时前
《Go小技巧&易错点100例》第三十三篇
开发语言·后端·golang
养军博客16 小时前
Spring boot 简单开发接口
java·spring boot·后端
计算机学姐18 小时前
基于SpringBoot的在线教育管理系统
java·vue.js·spring boot·后端·mysql·spring·mybatis
有梦想的攻城狮19 小时前
spring中的@Value注解详解
java·后端·spring·value注解