Golang基础学习笔记03

day03

一、复合类型(指针)

 

1. 指针的基本操作

//第个变量有两层含义:变量的内存,变量的地址

var a int = 10

fmt.Printf("%d\n", a) //变量的内存

fmt.Printf("%v\n", &a) //变量的地址

fmt.Printf("%p\n", &a) //变量的地址

fmt.Println(&a) //变量的地址

 

//保存某个变量的地址,需要指针。 *int 保存int的地址, **int 保存 *int的地址

//定义只是一个特殊的声明

//定义一个变量p,类型为 *int

var p *int

p = &a //指针变量指向谁,就把谁的地址赋值给指针变量

fmt.Println(p)

 

*p = 666 //*p操作的不是p的内存,是p指向的地址的内存(也就是a)

fmt.Println(*p)

fmt.Println(a)

2. 指针不要操作没有合法指向的内存

go语言指针没有指向时是 nil (即默认值 ,C的默认是null)

 

var p *int

// p = nil 可以给他赋值成nil

fmt.Println(p)

 

 

var p *int

// p = nil 可以给他赋值成nil

fmt.Println(p)

*p = 666

//会报错panic: runtime error: invalid memory address or nil pointer dereference

//[signal 0xc0000005 code=0x1 addr=0x0 pc=0x48b523]

//goroutine 1 [running]:

 

3. new函数的使用

new相当于C的动态分配空间,但是C需要手动释放内存,而go有自己的自动gc,不需要手动释放

var p *int

p = new(int) //p为指向的是int的内存地址,所以new(int)开辟了一块新的int内存

fmt.Println(p) //会输出p指导指向的内存地址

fmt.Println(*p) //p所指向的内存为int,默认值 是0,所以0

*p = 666

fmt.Println(*p) //p指向的内存新赋值为666,所以输出666

 

q := new(int) //自动推导

fmt.Println(q)

*q = 777

fmt.Println(*q)

 

4. 值传递

func swap(a, b int) {

a, b = b, a

fmt.Println("内a ", a)

fmt.Println("内b ", b)

}

 

func main() {

a, b := 10, 20

swap(a, b) //因为是值传递,不会改变主函数a,b的值

fmt.Println(a)

fmt.Println(b)

}

 

5. 指针做函数参数(地址传递)

func swap(a, b *int) {

*a, *b = *b, *a

fmt.Println("内a ", a) // 打印出的是内存地址

fmt.Println("内b ", b) // 打印出的是内存地址

}

 

func main() {

a, b := 10, 20

swap(&a, &b) //因为传递过去的是内存地址(指针),会改变主函数a,b的值

fmt.Println(a)

fmt.Println(b)

}

 

二、复合类型(数组)

6. 数组声明

数组是同一类型的集合,声明数组时,数组的个数必须是常量

 

var ids [50]int

//数组的个数为50个 len()

//下标是从0到len()-1

//[数字],是定义数组的个数

// [5]int 和 [10]int 是不同的类型

fmt.Println(len(ids))

//赋值

for i := 0; i < len(ids); i++ {

ids[i] = i + 1

}

 

for _, data := range ids {

fmt.Println(data)

}

 

//数组指针

p := &ids

fmt.Println(p)

//&[1 2 3 ...47 48 49 50]

7. 数组的初始化

 

//全部初始化

var a [5]int = [5]int{1, 2, 3, 4, 5}

fmt.Println(a) // [1 2 3 4 5]

b := [5]int{1, 2, 3, 4, 5}

fmt.Println(b) // [1 2 3 4 5]

 

//部分初始化,没初始化的元素,会有默认值

c := [5]int{1, 2, 3}

fmt.Println(c) // [1 2 3 0 0]

d := [5]int{2: 10, 4: 20} //根据下标赋值

fmt.Println(d)

 

8. 两维数组

有多少个 [ ] 就是多少维数组

有多少个 [ ] 就用多少个循环

 

var a [3][4]int

var k int

for i := 0; i < 3; i++ {

for j := 0; j < 4; j++ {

k++

a[i][j] = k

fmt.Printf("%d ", a[i][j])

}

fmt.Println("")

}

//1 2 3 4

//5 6 7 8

//9 10 11 12

fmt.Println(a) // [[1 2 3 4] [5 6 7 8] [9 10 11 12]]

//全部初始化

b := [3][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}

fmt.Println(b) // [[1 2 3 4] [5 6 7 8] [9 10 11 12]]

 

//部分初始化

c := [3][4]int{{1, 2, 3}, {5, 6, 7, 8}, {9, 10}}

fmt.Println(c) // [[1 2 3 0] [5 6 7 8] [9 10 0 0]]

 

d := [3][4]int{{1, 2, 3}, {5, 6, 7, 8}}

fmt.Println(d) // [[1 2 3 0] [5 6 7 8] [0 0 0 0]]

 

e := [3][4]int{1: {1, 2, 3}}

fmt.Println(e) // [[0 0 0 0] [1 2 3 0] [0 0 0 0]]

 

f := [3][4]int{1: {2: 3}}

fmt.Println(f) // [[0 0 0 0] [0 0 3 0] [0 0 0 0]]

 

9. 数组的比较和赋值

//数组比较

//只支持 == 和 != 而且比较的两个数组类型要一样(比较是不是第一个元素都都一样)

a := [4]int{1, 2, 3, 4}

// b := [3]int{1, 2, 3}

c := [4]int{1, 2, 3, 4}

d := [4]int{1, 2, 3}

 

// fmt.Println(a == b) 类型不一样,比较会报错

fmt.Println(a == c) //true

fmt.Println(a == d) //false

 

//数组赋值

e := a

fmt.Println(e) //[1 2 3 4]

 

10. Go的随机数

//设置种子,只需要一次

// rand.Seed(666)

//如果种了参数一样,每次产生的随机数都是一样的(所以我们有时间)

rand.Seed(time.Now().UnixNano()) //当前系统时间作为种子参数

for i := 0; i < 5; i++ {

//产生随机数

// fmt.Println(rand.Int())

fmt.Println(rand.Intn(100)) //产生100以内的随机数(0-99)

}

 

11. 数组做函数参数

//数组做函数参数是值传递,实参的每一个元素都都会给形参拷贝一份,

//形参的数据是实参数数据的复制品

func modify(a [4]int) {

a[0] = 666

fmt.Println("modify ", a) //modify [666 2 3 4]

}

 

func main() {

a := [4]int{1, 2, 3, 4}

modify(a)

fmt.Println("main ", a) //main [1 2 3 4]

}

 

12. 数组指针传递.go

func modify(a *[4]int) {

//a指向的是数组a的内存地址

(*a)[0] = 666

fmt.Println("modify ", *a) //modify [666 2 3 4]

}

 

func main() {

a := [4]int{1, 2, 3, 4}

modify(&a) //地址传递

fmt.Println("main ", a) //main [666 2 3 4]

 

}

 

三、复合类型(切片slice)

13. 切片说明

数组使用时缺点:大小是固定的,声明时必须指定长度,容量不能扩容,作为函数参数时,会把整个数组都拷贝一遍

切片就是为了弥补数组的缺点,切片不是数组也不是数组的指针(可以理解为可变长的数组)。切片是一种引用类型,底层总是指向一个array,切片的声明也像数组一样,只是不需要长度

 

 

 

14. 切片长度和容量

a := []int{1, 2, 3, 4}

// [low:high:max]

// low: 下标的起点

// high: 下标的终点(不包括些下标)

// leng: 长度 high-low

// cap: 容量 max-low

s := a[1:3:4]

fmt.Println(s) // [2 3]

fmt.Println(len(s)) //切片长度2 3-1

fmt.Println(cap(s)) //切片长度3 4-1

 

15. 数组和切片区别

//数组和切片的区别

 

//数组的 [] 里面的长度,是一个常量,数组不能修改长度,len和cap是固定的这里是5

a := [5]int{} //数组

fmt.Println(a) // [0 0 0 0 0]

fmt.Println(len(a)) // 5

fmt.Println(cap(a)) // 5

 

//切片 [] 里面是空的或者是...( [...]int),切片的长度和容量是不固定的

s := []int{} //切片

fmt.Println(s) // []

fmt.Println(len(s)) // 0

fmt.Println(cap(s)) // 0

 

s = append(s, 11) //给切片末尾追加一个成员

fmt.Println(s) // [11]

fmt.Println(len(s)) // 1

fmt.Println(cap(s)) // 1

 

16. 切片的创建

//自动推导,同时初始化

s := []int{1, 2, 3}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值