Go指针

Go 语言指针

Go 语言中指针是很容易学习的,Go 语言中使用指针可以更简单的执行一些任务。

接下来让我们来一步步学习 Go 语言指针。

我们都知道,变量是一种使用方便的占位符,用于引用计算机内存地址。

Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。

以下实例演示了变量在内存中地址:

 1 package main
 2
 3 import (
 4     "fmt"
 5 )
 6
 7 func main(){
 8     var name string
 9     name = "demon"
10     fmt.Println("name变量的指针地址:",&name)
11 }

以上代码运行返回的结果:

name变量的指针地址: 0xc420076050

什么是指针

一个指针变量可以指向任何一个值的内存地址它指向那个值的内存地址。

类似于变量和常量,在使用指针前你需要声明指针。指针声明格式如下:

var var_name(变量名) *var_name_type(数据类型)

var_name就是变量的名称,var_name_type是指针的数据类型,*用于指定变量是一个指针,例如以下的指针声明

var name *string            //指向字符串类型的指针
var age  *int                //指向整数型类型的指针

如何使用指针

指针使用流程:

  • 定义指针变量。
  • 为指针变量赋值。
  • 访问指针变量中指向地址的值。

在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。

 1 package main
 2
 3 import (
 4     "fmt"
 5 )
 6
 7
 8 func main(){
 9     //定义局部变量num1 num2
10     var num1 int = 50
11     var num2 *int
12
13     //获取num1变量的内存地址并赋值给num2变量
14     num2 = &num1
15
16     fmt.Println("num1变量的内存地址为:", &num1)
17     fmt.Println("num2变量指针的地址为:", num2)
18
19     //获取变量num1的值
20     fmt.Println("num1变量的值为:", num1)
21     //获取变量num2的值
22     fmt.Println("num2变量的值为:", *num2)
23
24 }

以上代码返回的运行结果:

num1变量的内存地址为: 0xc42006e178
num2变量指针的地址为: 0xc42006e178
num1变量的值为: 50
num2变量的值为: 50

Go 空指针

当一个指针被定义后没有分配到任何变量时,它的值为 nil。

nil 指针也称为空指针。

nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。

一个指针变量通常缩写为 ptr。

查看以下实例:

 1 package main
 2
 3 import (
 4     "fmt"
 5 )
 6
 7 func main(){
 8     //初始化局部变量 ptr s 分别都是空指针
 9     var ptr  *int
10     var s      *string
11     //初始化局部变量num1 num2,因为num1赋值了并且num2的指针指向了num1
12     var num1 float32 = 50.123
13     var num2 *float32
14     num2 = &num1
15
16     //分别输出变量的值
17     fmt.Printf("ptr的空指针的值为:%v\n", ptr)
18     fmt.Printf("s的空指针的值为:%v\n", s)
19     fmt.Printf("num2的值为%v\n", *num2)
20
21     //做判断,如果是空指针的话值就是nil
22     if ptr == nil{
23         fmt.Println("ptr是空指针哦~")
24     }
25
26     if s == nil{
27         fmt.Println("s是空指针哦~")
28     }
29
30     if num2 == nil{
31         fmt.Println("num2的是空指针哦~")
32     }else {
33         fmt.Println("num2的值为:", *num2)
34     }
35
36 }

以上代码返回的运行结果:

ptr的空指针的值为:<nil>
s的空指针的值为:<nil>
num2的值为50.123
ptr是空指针哦~
s是空指针哦~
num2的值为: 50.123

Go 语言指针数组

number为整型指针数组。因此每个元素都指向了一个值。以下实例的三个整数将存储在指针数组中:

 1 package main
 2
 3 import (
 4     "fmt"
 5 )
 6
 7 func main(){
 8     //定义一个blance数组,并且拥有五个元素
 9     var blance = [5] int {1,2,3,4,5}
10     //定义常量MAX为5
11     const MAX int =  5
12     //定义数组指针number
13     var number [MAX] *int
14
15     for i := 0; i< MAX; i++{
16         //分别给number的数组中的每个索引赋值,值是引用blance数组中的每个元素的内存地址
17         number[i] = &blance[i]
18         fmt.Printf("blance[%d] = %d \n", i, blance[i])
19     }
20
21     fmt.Println("----------------------")
22
23     for i := 0; i< MAX; i++{
24         fmt.Printf("number[%d] = %d \n", i, *number[i])
25     }
26
27     fmt.Println("----------------------")
28
29     for i := 0; i< MAX; i++{
30         //如果blance数组与number数组一样,并且里面只的内存地址都一样,则打印两个数组元素的内存地址
31         if blance[i] == *number[i] && &blance[i] == number[i]{
32             fmt.Printf("blance[%d] %v   number[%d]  %v \n",i , &blance[i], i ,number[i])
33
34         }
35     }
36 }

以上代码返回的运行结果:

blance[0] = 1
blance[1] = 2
blance[2] = 3
blance[3] = 4
blance[4] = 5
----------------------
number[0] = 1
number[1] = 2
number[2] = 3
number[3] = 4
number[4] = 5
----------------------
blance[0] 0xc4200141e0   number[0]  0xc4200141e0
blance[1] 0xc4200141e8   number[1]  0xc4200141e8
blance[2] 0xc4200141f0   number[2]  0xc4200141f0
blance[3] 0xc4200141f8   number[3]  0xc4200141f8
blance[4] 0xc420014200   number[4]  0xc420014200 

来来来来,用Python来嘲讽一波golang的数组引用赋值~

 1 #!/usr/bin/env python3
 2 # _*_coding:utf-8_*_
 3
 4 __author__ = ‘demon‘
 5
 6 #声明列表l1
 7 l1 = [‘demon‘,‘18‘,‘beijing‘,"python","golang","linux"]
 8 #浅拷贝列表l1中的每个元素
 9 l2 = l1[:]
10
11 l1_len = len(l1)
12
13 for i in range(l1_len):
14     #判断列表中每个元素的内存地址是否一致
15     if id(l1[i]) == id(l2[i]):
16         #打印两个列表中给的每个元素及内存地址
17         print("l1[{}]   {:10}   l2[{}]  {:10} at {memory}".format(i,l1[i],i,l2[i],memory=id(l1[i])))

以上代码返回的运行结果:

l1[0]   demon        l2[0]  demon      at 4302152624
l1[1]   18           l2[1]  18         at 4330894536
l1[2]   beijing      l2[2]  beijing    at 4330894200
l1[3]   python       l2[3]  python     at 4329981408
l1[4]   golang       l2[4]  golang     at 4330894984
l1[5]   linux        l2[5]  linux      at 4329974728

Go 语言指向指针的指针

如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。

当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址:

指向指针的指针变量声明格式如下:

var ptr **int;

以上指向指针的指针变量为整型。

访问指向指针的指针变量值需要使用两个 * 号,如下所示:

 1 package main
 2
 3 import (
 4     "fmt"
 5 )
 6
 7 func main() {
 8
 9     var a int
10     var ptr *int
11     var pptr **int
12
13     a = 3000
14
15     //指针ptr地址
16     ptr = &a
17
18     //指向指针ptr地址
19     pptr = &ptr
20
21     //*获取pptr的值
22     fmt.Printf("变量 a = %d\n", a )
23     fmt.Printf("指针变量 *ptr = %d\n", *ptr )
24     fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)
25 }

以上代码返回的运行结果:

变量 a = 3000
指针变量 *ptr = 3000
指向指针的指针变量 **pptr = 3000

Go 语言指针作为函数参数

Go 语言允许向函数传递指针,只需要在函数定义的参数上设置为指针类型即可。

以下实例演示了如何向函数传递指针,并在函数调用后修改函数内的值:

 1 package main
 2
 3 import (
 4     "fmt"
 5 )
 6
 7 //可以接收指针作为参数的自定义函数
 8 func person(name *string,age *int) string {
 9     //修改指针指向的name变量的值,影响了name的值
10     *name = "大佬"
11     fmt.Println("person函数内部的name的内存地址:", name)
12     fmt.Printf("person函数内部的修改后name变量值:%s", *name)
13     return  ""
14
15 }
16
17 func swap(x ,y int) string{
18     //修改x,y的值,x,y作为局部变量传递进来,因为没有使用指针,所以不会影响函数外部的x,y变量值
19     x, y = 50,100
20     fmt.Println("swap函数内部的x变量值:", x)
21     fmt.Println("swap函数内部的y变量值:", y)
22     return ""
23 }
24
25 func main() {
26     //初始化局部变量
27     var name string = "demon"
28     var    age     int = 18
29     var x int = 10
30     var y int = 20
31
32     fmt.Println("person函数内部的修改后name变量值:", name)
33     fmt.Println("person函数外部的name的内存地址:", &name)
34     fmt.Println(person(&name, &age))
35     fmt.Printf("person函数外部的修改后name变量值:%s \n",name)
36
37     fmt.Println("--------------------------------------------")
38     fmt.Println(swap(x,y ))
39     fmt.Println("swap函数外部的x变量值:", x)
40     fmt.Println("swap函数外部的y变量值:", y)
41
42 }

以上代码返回的运行结果:

person函数内部的修改后name变量值: demon
person函数外部的name的内存地址: 0xc42006e1a0
person函数内部的name的内存地址: 0xc42006e1a0
person函数内部的修改后name变量值:大佬
person函数外部的修改后name变量值:大佬
--------------------------------------------
swap函数内部的x变量值: 50
swap函数内部的y变量值: 100

swap函数外部的x变量值: 10
swap函数外部的y变量值: 20
时间: 2024-11-04 01:34:31

Go指针的相关文章

[c/c++] programming之路(17)、高级指针

一.二级指针 二级指针的作用:1.函数改变外部变量指针2.外挂改变一个指针的值 1 #include<stdio.h> 2 #include<stdlib.h> 3 4 void main(){ 5 int a = 10; 6 int b = 20; 7 int *p1 = &a; 8 int *p2 = &b; 9 int **pp = &p1; 10 printf("%d,", **pp); 11 printf("\n%x,

C++学习笔记----2.4 C++引用在本质上是什么,它和指针到底有什么区别

从概念上讲.指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变. 而引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量). 在C++中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的: 指针传递参数本质上是值传递的方式,它所传递的是一个地址值.值传递过程中,被调

【转】父类子类指针相互转换问题

1.当自己的类指针指向自己类的对象时,无论调用的是虚函数还是实函数,其调用的都是自己的: 2.当指向父类对象的父类指针被强制转换成子类指针时候,子类指针调用函数时,只有非重写函数是自己的,虚函数是父类的: 3.当指向子类对象的子类指针被强制转换成父类指针的时候,也就是父类指针指向子类对象,此时,父类指针调用的虚函数都是子类的,而非虚函数都是自己的. 将上面三句话总结成一句话就是:当父类子类有同名非虚函数的时候,调用的是转换后的指针类型的函数: 当父类子类有同名虚函数的时候呢,调用的是指针转换前指

C++ Primer 学习笔记与思考_7 void和void*指针的使用方法

(一)void的含义 void的字面意思是"无类型",void差点儿仅仅有"凝视"和限制程序的作用,由于从来没有人会定义一个void变量,让我们试着来定义: void a; 这行语句编译时会出错.提示"illegal use of type 'void'".只是.即使void a的编译不会出错.它也没有不论什么实际意义. void真正发挥的作用在于: (1) 对函数返回的限定: (2) 对函数參数的限定. int f(void); equal t

当this指针成为指向之类的基类指针时,也能形成多态

this指针: 1)对象中没有函数,只有成员变量 2)对象调用函数,通过this指针告诉函数是哪个对象自己谁. 1 #include<iostream> 2 using namespace std; 3 class Shape 4 { 5 public: 6 //void cal_display(Shape* this) 7 void cal_display(){ 8 display(); 9 this->display(); 10 } 11 private: 12 virtual vo

指针x(超简单的x)

指针! 1 #include<cstdio> 2 #include<iostream> 3 4 using namespace std; 5 6 /* 7 相加或者相乘 8 */ 9 10 int main() 11 { 12 int a,b,s,t; 13 cin>>a>>b; 14 int *p; 15 p=&a; 16 int *q; 17 q=&b; 18 s=(*p)+(*q); 19 t=(*p)*(*q); 20 printf(

二重指针实现排序

1 //双指针对十个数排序 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #define N 8 6 //2017.3.5 7 int main() 8 { 9 //初始化数组 赋值N个数 用指针数组指向 10 int num[N]; 11 int *pNum[N]; 12 int **p = NULL; 13 for (int i = 0; i < N; i++) 14 { 15 num[i] = rand() % 100;/

c指针-专题

六---指针 内存和地址怎么理解呢? 机器中有一些位置,每一个位置被称为[字节]/byte,许多现代机器上,每个字节包含8个位.更大内存单位[字],通常包含2个或4个字节组成. 一个字包含4个字节,它的地址是什么? 他仍然只有一个地址,是最左边还是最右边的那个字节的位置,取决于机器. 机器事实-关于整型的起始位置: 在要求边界对齐(boundaryalignment)的机器上,整型存储的起始位置只能是某些特定的字节,通常是2或4的倍数. 变量名和地址关系? 所有高级语言的特性之一,就是通过名字而

智能指针的原理和简单实现

什么是智能指针? 智能指针实质上是一个类,定义一个类来封装资源的分配和释放.这个类的构造函数中传入一个指针,完成资源的分配和初始化.在析构函数中释放传入的该指针,完成资源的释放. 为什么要用智能指针? 智能指针就是智能,自动化的管理指针所指向的动态资源. 例如以下情况:代码中经常会忘记释放动态开辟的内存资源,导致内存泄露. // case1 void Test2() {  int* p1 = new int(2);  bool isEnd = true;  //...  if (isEnd)  

单继承与多继承中的虚函数表和虚函数指针

首先,我们了解一下何为单继承,何为多继承?? 单继承:一个子类只有一个直接父类. 多继承:一个子类有两个或多个直接父类. 单继承中的虚函数表分析: 示例程序: #include <iostream> using namespace std; typedef void(*FUNC)(); class Base { public: virtual void func1() { cout << "Base::func1()" << endl; } virt