指针与结构体
【1】、指针
变量是一个占位符,底层指向是一个内存地址。
&:取地址符 &a:取出a变量的地址
1、指针的概念
b内存地址 0x11111111111, 值:500 var b int = 500
a指针变量,指向了一个内存地址 0x11111111111
变量a持有了变量b的地址。这个就是a指向了b
package main
import "fmt"
func main() {
// 指针
var a int = 10
// b存储的就是a的地址
// * 取出指向的地址的值
var b = &a
fmt.Println("a的地址", &a)
fmt.Println("b指向的地址:", b)
fmt.Println("b自己的地址:", &b)
fmt.Println("b指向的地址的值:", *b)
//a的地址 0xc0000a6058
//b指向的地址: 0xc0000a6058
//b自己的地址: 0xc0000ca018
//b指向的地址的值: 10
*b = 20
fmt.Println("a的值:", a) // a的值:20
}
2、指针如何使用
package main
import "fmt"
/*
1、定义指针变量
2、为指针变量赋值 &
3、访问指针变量中地址所指向的值 *
* :在指针类型前面加上 * 号,就是来获取指针所指向的地址的值
*/
func main() {
// 声明普通变量
var a int = 10
fmt.Printf("a 变量的值:%d\n", a) // 10
fmt.Printf("a 变量的地址:%p\n", &a) // 0x
// 声明 指针变量,指向a, 指针其实就是一个特殊的变量而已。,ptr命名 p
// 定义变量格式 var ptr *类型
var p *int
p = &a // 指针变量赋值
fmt.Printf("p 变量存储的指针地址:%p\n", p) // a 的地址
fmt.Printf("p 变量自己的地址:%p\n", &p) // p 变量自己的地址
fmt.Printf("p 变量存储的指针地址指向的值%d\n", *p) // a的值
// 改变a的值 *p 和 a 其实是同一个地址
a = 20
fmt.Printf("a:%d\n", a)
fmt.Printf("*p的值:%d\n", *p)
// 通过指针改变a的值
*p = 40
fmt.Printf("a:%d\n", a)
// 指针的套娃,指针指向指针 , 指针类型 第一个*指针类型, *int是这个指针对应的类型
// 如何理解多个符号,第一个取出来后,后面就是它的类型 *(*(int))
var ptr **int
ptr = &p
fmt.Printf("ptr指向的地址:%p\n", ptr)
fmt.Printf("ptr的地址:%p\n", &ptr)
fmt.Printf("*ptr变量存储的地址:%p\n", *ptr)
fmt.Printf("**ptr存储的值:%d\n", **ptr)
// 修改a的值
**ptr = 100
fmt.Println(a)
}
3、数组指针
数组指针:首先应该是一个指针,指向了一个数组
package main
import "fmt"
func main() {
// 数组指针
arr1 := [5]int{1, 2, 34, 5, 6}
fmt.Println("arr1:", arr1) //arr1: [1 2 34 5 6]
fmt.Printf("arr1的地址:%p\n", &arr1) //arr1的地址:0xc00000e3c0
// 创建一个指针,指向这个数组的地址,通过指针来操作数组
var p1 *[5]int
p1 = &arr1
fmt.Printf("p1指向的地址%p\n", p1)
fmt.Printf("p1自己的地址%p\n", &p1)
fmt.Println("p1指向的地址的值:", *p1)
// 操作指针控制数组
// 指向了谁,这个指针就可以代表谁。
// p1 = arr1
(*p1)[0] = 100
fmt.Println(arr1) // [100 2 34 5 6]
fmt.Println(*p1) // [100 2 34 5 6]
p1[2] = 300 // 在程序中,我们更多时候是这样在使用指针的
fmt.Println(arr1) // [100 2 300 5 6]
fmt.Println(*p1) // [100 2 300 5 6]
}
指针数组
package main
import "fmt"
func main() {
a := 1
b := 2
c := 3
d := 4
// 创建一个指针数组
arr1 := [4]*int{&a, &b, &c, &d}
fmt.Println(arr1)
fmt.Println(*arr1[0]) // 1
fmt.Println(arr1[0]) // 0xc00001a0b8
fmt.Println(&a) // 0xc00001a0b8
*arr1[0] = 100
fmt.Println(a) // 100
}
4、指针函数
首先需要是一个函数,这个函数的返回值是一个指针。
package main
import "fmt"
func main() {
ptr := f5()
fmt.Println("ptr:", ptr)
fmt.Printf("ptr类型:%T\n", ptr)
fmt.Println("ptr的地址:\n", &ptr)
fmt.Println("ptr地址中的值:\n", *ptr)
}
// 返回数组指针
func f5() *[4]int {
arr := [4]int{1, 2, 3, 4}
return &arr
}
5、指针作为函数参数
package main
import "fmt"
func main() {
// 值传递
a := 10
fmt.Println("a:", a) // 10
fmt.Println("a addr:", &a) // 0xc00000e0a8
f6(&a)
fmt.Println("a:", a) // 20
fmt.Println("a addr:", &a) // 0xc00000e0a8
}
// 指针当做函数的参数
func f6(ptr *int) {
fmt.Println("ptr:", ptr) // 0xc00000e0a8
fmt.Println("ptr 指针的地址中的值", *ptr) // a = 10
*ptr = 20
}
补充:什么时候定义的变量会销毁,没有任何东西再指向它的时候,垃圾回收(GC)会回收。
【2】、结构体
变量:解决生活中问题(定义名字)
判断:解决生活中问题(分支:true false)
循环:解决生活中问题(循环:多次操作 for)
面向对象编程思维 OOP:将世界上的所有东西,抽象成一个个的类(属性、方法)
我想用一个变量来定义一个人的信息: map[string]string slice(,,,,,,)
人:属性(name、sex、age) 动作( 吃 eat() 工作 work() sleep() )
1、定义一个结构体
定义变量 var
定义结构体 type User struct {}
package main
import "fmt"
type User struct {
name string
age int
sex string
}
func main() {
// 通过结构体创建对象,以前的类型都是用的基本类型,自己定义类型了type,Struct
// 定义了结构体对象,不赋值,默认都是这个结构体的零值 {"",0,""}
var user1 User
user1.name = "zhangsan"
user1.sex = "girl"
user1.age = 18
fmt.Println(user1.name, user1.age, user1.sex)
// 获取名字
fmt.Println(user1.name)
// 创建对象的方式二
user2 := User{}
user2.name = "aaa"
user2.sex = "男"
user2.age = 18
fmt.Println(user2.name)
// 创建对象的方式三
user3 := User{
name: "sss",
age: 19,
sex: "男",
}
fmt.Println(user3)
fmt.Println(user3.name)
// 创建对象的方式四
user4 := User{"ccc", 12, "男"}
fmt.Println(user4)
fmt.Println(user4.name)
}
2、结构体指针
package main
import (
"fmt"
)
type User2 struct {
name string
age int
sex string
}
func main() {
user1 := User2{"qqq", 18, "男"}
// 结构体类型 包.struct名
fmt.Printf("%T,%p\n", user1, &user1) // main.User2,0xc00011e4b0
// 结构体是值类型的
user2 := user1
fmt.Printf("%p,%p\n", &user1, &user2)
fmt.Println("user2:", user2)
user2.name = "hahaha"
fmt.Println("user2:", user2)
fmt.Println("user1:", user1)
// 指针解决值传递的问题
var ptr_user *User2
ptr_user = &user1
fmt.Printf("%T,%p\n", ptr_user, &ptr_user) // *main.User2,0xc0000ca020
fmt.Println(*ptr_user)
(*ptr_user).name = "ggg"
fmt.Println(*ptr_user) // {ggg 18 男}
fmt.Println(user1) // {ggg 18 男}
ptr_user.age = 13
fmt.Println(user1) // {ggg 13 男}
// 内置方法new 创建对象 new 关键字创建的对象,都返回指针,而不是结构体对象。
user3 := new(User2)
fmt.Println(user3) // &{ 0 }
user3.name = "hhhh"
fmt.Println(*user3) // {hhhh 0 }
fmt.Println(user3) // &{hhhh 0 }
user3.age = 19
user3.sex = "女"
fmt.Println(user3)
updateUser(user3)
fmt.Println(*user3) // {hhhh 10000000000 女}
}
func updateUser(user *User2) {
user.age = 10000000000
}
3、匿名结构体
package main
import "fmt"
type Student struct {
name string
age int
}
func main() {
// 匿名结构体
s1 := Student{"jjj", 18}
fmt.Println(s1.name, s1.age)
// 匿名结构体,直接可以在函数内部创建出来,创建后就需要赋值使用
s2 := struct {
name string
age int
}{
name: "qqq",
age: 9898,
}
fmt.Println(s2) // {qqq 9898}
// 匿名字段
t1 := Teacher{"qqq", 55}
// 如何打印这个匿名字段,默认使用数据类型当做字段名称
fmt.Println(t1.string, t1.int)
}
// 结构体中的匿名字段,没有名字的字段,这个时候属性类型不能重复
type Teacher struct {
string
int
}
4、结构体嵌套
package main
import "fmt"
type Person struct {
name string
age int
address Address
}
type Address struct {
city, state string
}
// 结构体是可以嵌套:我们就可以定义很多复杂的对象,来进行拼接了,构成一个更大的对象
func main() {
// 一个结构体可能包含一个字段,而这个字段又是一个结构体:结构体嵌套
var pre = Person{}
pre.name = "ggg"
pre.age = 66
pre.address = Address{
city: "tianjin",
state: "zh",
}
fmt.Println(pre)
fmt.Println(pre.name)
fmt.Println(pre.age)
fmt.Println(pre.address.city)
fmt.Println(pre.address.state)
}
5、结构体导出
public 公开的,所有地方都可以使用 、priavte私有的,只能自己使用
结构体:结构体名字,属性名字 。大写字母,可以导出使用,小写字母,不能导出使用。
如果结构体名称首字母小写,则结构体不会被导出。这时,即使结构体成员字段名首字母大写,也不会被导出。不能再其他包中只用
如果结构体名称首字母大写,则结构体可被导出,但只会导出大写首字母的成员字段,那些小写首字母的成员字段不会被导出。可以在其他包中使用
如果存在嵌套结构体,即使嵌套在内层的结构体名称首字母小写,外部也能访问到其中首字母大写的成员字段。
标签:fmt,指针,地址,Println,main,ptr,结构 From: https://www.cnblogs.com/xuruizhao/p/18544838