企业网站广告图片轮播代码,全国公共信息服务平台,企业运营包括哪些环节,东莞建设网站官网指针在编程中#xff0c;一个内存地址用来定位一段内存。通常地#xff0c;一个内存地址用一个操作系统原生字#xff08;native word#xff09;来存储。 一个原生字在32位操作系统上占4个字节#xff0c;在64位操作系统上占8个字节。 所以#xff0c;32位操作系统上的理…指针在编程中一个内存地址用来定位一段内存。通常地一个内存地址用一个操作系统原生字native word来存储。 一个原生字在32位操作系统上占4个字节在64位操作系统上占8个字节。 所以32位操作系统上的理论最大支持内存容量为4GB1GB 230字节64位操作系统上的理论最大支持内存容量为264Byte即16EBEB艾字节1EB 1024PB, 1PB 1024TB, 1TB 1024GB。内存地址的字面形式常用整数的十六进制字面量来表示比如0x1234CDEF。在Go中一个无名指针类型的字面形式为*T其中T为一个任意类型。类型T称为指针类型*T的基类型base type。 如果一个指针类型的基类型为T则我们可以称此指针类型为一个T指针类型。虽然我们可以声明具名指针类型但是一般不推荐这么做因为无名指针类型的可读性更高。如果一个指针类型的底层类型是*T则它的基类型为T。如果两个无名指针类型的基类型为同一类型则这两个无名指针类型亦为同一类型。*int // 一个基类型为int的无名指针类型。
**int // 一个多级无名指针类型它的基类型为*int。type Ptr *int // Ptr是一个具名指针类型它的基类型为int。
type PP *Ptr // PP是一个具名多级指针类型它的基类型为Ptr。如何获取一个指针值有两种方式来得到一个指针值我们可以用内置函数new来为任何类型的值开辟一块内存并将此内存块的起始地址做为此值的地址返回。 假设T是任一类型则函数调用new(T)返回一个类型为*T的指针值。 存储在返回指针值所表示的地址处的值可被看作是一个匿名变量为T的零值。我们也可以使用前置取地址操作符来获取一个可寻址的值的地址。 对于一个类型为T的可寻址的值t我们可以用t来取得它的地址。t的类型为*T。一般说来一个可寻址的值是指被放置在内存中某固定位置处的一个值但放置在某固定位置处的一个值并非一定是可寻址的。 目前我们只需知道所有变量都是可以寻址的但是所有常量、函数返回值和强制转换结果都是不可寻址的。 当一个变量被声明的时候Go运行时将为此变量开辟一段内存。此内存的起始地址即为此变量的地址。对于基类型为T的指针类型的一个指针值p我们可以用*p来表示地址p处的值。 此值的类型为T。*p称为指针p的解引用。解引用是取地址的逆过程。解引用一个nil指针将产生一个panic。package mainimport fmtfunc main() {p0 : new(int) // p0指向一个int类型的零值fmt.Println(p0) // 打印出一个十六进制形式的地址fmt.Println(*p0) // 0x : *p0 // x是p0所引用的值的一个复制。p1, p2 : x, x // p1和p2中都存储着x的地址。// x、*p1和*p2表示着同一个int值。fmt.Println(p1 p2) // truefmt.Println(p0 p1) // falsep3 : *p0 // p3 : (*p0)// p3 : p0// p3和p0中存储的地址是一样的。fmt.Println(p0 p3) // true*p0, *p1 123, 789fmt.Println(*p2, x, *p3) // 789 789 123fmt.Printf(%T, %T \n, *p0, x) // int, intfmt.Printf(%T, %T \n, p0, p1) // *int, *int
}在Go中所有的赋值包括函数调用传参过程都是一个值复制过程。 所以在上面的double函数体内修改的是变量a的一个副本而没有修改变量a本身。当然我们可以让double函数返回输入参数的两倍数但是此方法并非适用于所有场合。package mainimport fmtfunc double(x *int) {*x *xx nil // 此行仅为讲解目的
}func main() {var a 3double(a)fmt.Println(a) // 6p : adouble(p)fmt.Println(a, p nil) // 12 false
}通过将double函数的输入参数的类型改为*int传入的实参a和它在此函数体内的一个副本x都引用着变量a。 所以对*x的修改等价于对*p也就是变量a的修改。 换句话说新版本的double函数内的操作可以反映到此函数外了。当然在此函数体内对传入的指针实参的修改x nil依旧不能反映到函数外因为此修改发生在此指针的一个副本上。 所以在double函数调用之后局部变量p的值并没有被修改为nil。在Go中返回一个局部变量的地址是安全的Go是支持垃圾回收的所以一个函数返回其内声明的局部变量的地址是绝对安全的。func newInt() *int {a : 3return a
}Go指针的一些限制施加限制Go指针保留了C指针的好处同时也避免了C指针的危险性。在Go中指针是不能参与算术运算的。比如对于一个指针p 运算p和p-2都是非法的。如果p为一个指向一个数值类型值的指针*p将被编译器认为是合法的并且等价于(*p)。 换句话说解引用操作符*的优先级都高于自增和自减--操作符。一个指针值不能和其它任一指针类型的值进行比较Go指针值是支持使用比较运算符和!比较的。 但是两个指针只有在下列任一条件被满足的时候才可以比较这两个指针的类型相同。其中一个指针可以被隐式转换为另一个指针的类型。换句话说这两个指针的类型的底层类型必须一致并且至少其中一个指针类型为无名的考虑结构体字段的标签。其中一个并且只有一个指针用类型不确定的nil标识符表示。一个指针类型的值不能被随意转换为另一个指针类型在Go中只有如下某个条件被满足的情况下一个类型为T1的指针值才能被显式转换为另一个指针类型T2类型T1和T2的底层类型必须一致忽略结构体字段的标签。 特别地如果类型T1和T2中只要有一个是无名类型并且它们的底层类型一致考虑结构体字段的标签则此转换可以是隐式的。 类型T1和T2都为无名类型并且它们的基类型的底层类型一致忽略结构体字段的标签。Go指针的限制是可以被打破的unsafe标准库包中提供的非类型安全指针unsafe.Pointer机制可以被用来打破上述Go指针的安全限制。 unsafe.Pointer类型类似于C语言中的void*。 但是通常地非类型安全指针机制不推荐在Go日常编程中使用。