GO-指针与函数

一、指针类型

1、普通类型,变量存的就是值,也叫值类型。指针类型存的是地址

2、获取变量的地址,用&,比如:var a int, 获取a的地址 &a

3、指针类型,变量存的是一个地址,这个地址存的才是值

4、获取指针类型所指向的值,使用:* ,比如:var p *int,使用*p获取p指向的变量的值

var a int = 5

var p *int = &a   0xefefefe 指向变量a的值是 5

5、指针类型的变量初始话有两种:

5.1、直接给指针赋值其他变量的地址

func test3(){

var p *int  //默认初始化nil

var a int

p = &a

*p = 200

fmt.Println(a)

}

5.2、使用new分配

func test4(){

var p *int

p = new(int)

*p = 2000

fmt.Println(*p)

}

6、练习题

6.1、练习1:写一个程序,获取一个变量的地址,并打印到终端

package main

import (

"fmt"

)

func test1(){

var a int = 5

var p *int = &a

fmt.Printf("a的地址是:%p\n",p)

fmt.Printf("a的值是:%d",*p)

}

func main(){

test1()

}

运行打印的结果如下:

6.2、练习2:写一个函数,传入一个int类型的指针,并在函数中修改所指向的值

func modify(x *int){         //传入的变量x类型是指针 *int代表指针是整形的指针

*x = 200                      //给x指针指向的值重新赋值为200

}

func test2(){

var a int = 5             //定义一个整形的变量a,初始值是5

var p *int = &a           //定义一个指针p,指向的是a

fmt.Println("变量a的初始值是",a)   //打印a的初始值

modify(p)                  //修改p指针指向的a的值

fmt.Println("p指针指向的a变量的改变值是",a)   //打印a的值改变的结果

}

func main(){

test2()

}

执行打印的结果如下:

二、内置函数

1、close:主要用来关闭channel

2、len:用来求长度,比如string、array、slice、map、channel

3、new:用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针。示例可以看上面一的5.2,

4、make:用来分配内存,主要用来分配引用类型,比如channel、map、slice

5、append:用来追加元素到数组、slice中

6、panic和recover:用来做错误处理

7、new和make的区别

7.1、内建函数 new 用来分配内存,它的第一个参数是一个类型,不是一个值,它的返回值是一个指向新分配类型零值的指针

7.2、内建函数 make 用来为 slice,map 或 chan 类型分配内存和初始化一个对象(注意:只能用在这三种类型上),跟 new 类似,第一个参数也是一个类型而不是一个值,跟 new 不同的是,make 返回类型的引用而不是指针,而返回值也依赖于具体传入的类型,具体说明如下:

  Slice: 第二个参数 size 指定了它的长度,它的容量和长度相同。
你可以传入第三个参数来指定不同的容量值,但必须不能比长度值小。
比如 make([]int, 0, 10)

  Map: 根据 size 大小来初始化分配内存,不过分配后的 map 长度为 0,如果 size 被忽略了,那么会在初始化分配内存时分配一个小尺寸的内存

  Channel: 管道缓冲区依据缓冲区容量被初始化。如果容量为 0 或者忽略容量,管道是没有缓冲区的

7.3、总结:

  new 的作用是初始化一个指向类型的指针(*T),make 的作用是为 slice,map 或 chan 初始化并返回引用(T)。

三、函数

1、声明语法:func 函数名(参数列表)[(返回值列表)]{}

  func add(){

  }

  func add(a int,b int){

  }

  func add(a int, b int) int {

  }

  func add(a int, b int) (int , int){

  }

  func add(a , b int) (int , int){

  }

2、golang函数的特点:

  a、不支持重载,一个包不能有两个名字一样的函数;

  b、函数是一等公民,函数也是一种类型,函数也可以赋值给变量

  c、匿名函数

  d、多返回值

  示例: 

  type add_func func(int, int)int

  func oprator(op add_func,a int,b int)int {

   //使用传进来的函数op,进行操作

  return op(a,b)

  }

  func add(a,b int) int {

   return a + b

  }  

  func main(){

  c:=add

   fmt.Println(c)

  sum := oprator(c,100,200)

   fmt.Println(sum)

 

  }
3、函数参数传递方式:

  3.1、值传递

  3.2、引用传递

  注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本。值传递是值的拷贝,一般来说地址拷贝更高效。值拷贝取决于拷贝的对象的大小,对象越大,性能越低。

  注意2:map、slice、channel、指针、interface默认以引用的方式传递

4、命名返回值的名字

//重命名一个返回值

func reduce(a , b int)(c int){

c = a - b

return

}

//重命名多个返回值

func calc(a,b int)(sum int,avg int){

sum = a + b

avg = sum/2

return

}

// _ 忽略返回值

func main(){

sum,_ := calc(100,200)

}

5、可变参数:

多个参数

func test11(arg...int) int{

}

一个或多个参数

func test11(a int ,arg...int) int{

}

二个或多个参数

func test11(a int,b int ,arg...int) int{

}

注意:其中arg是一个slice,我们可以通过arg[index]来获取多个参数

通过len(arg)来判断传递参数的个数

6、练习题示例

package main

import (

"fmt"

)

//练习题一:写一个函数add,支持1个或多个int相加,并返回结果

func add(a int,arg...int)int{

var sum int

//当只有一个参数时

if len(arg)==0{

sum = a

}

//当参数大于一个时

if len(arg)>0{

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

//注意这里但arg里面只有一个参数时,i是等于0即arg[0]

if i == 0 {

sum = a + arg[0]

}

//当arg参数大于一个时

if i >0 {

sum+=arg[i]

}

}

}

return sum

}

//练习题二:写一个函数concat,支持1个或多个string相拼接,并返回结果

func concat(a string,arg...string)string{

var str string

if len(arg)==0{

str = a

}

if len(arg)>0{

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

if i == 0 {

str = a + arg[0]

}

if i >0 {

str+=arg[i]

}

}

}

return str

}

func main(){

fmt.Println(add(-22,23,555))

fmt.Println(concat("aaa","bbbbb","ccccccc"))

}

7、defer的特点和用途

7.1、当函数返回时,执行defer语句。因此可以用来做资源清理

7.2、多个defer语句,按先进后出的方式执行

示例:

func a(){

fmt.Println("defer from a")

i:=0

defer fmt.Println(i)   //defer语句中的变量,在defer声明时就决定

i++

}

func f(){

fmt.Println("defer from f")

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

defer fmt.Println(i)

}

}

func main(){

//练习三

a()

f()

}

打印的结果:

7.3、defer语句中的变量,在defer声明时就决定了

7.4、defer用途:关闭文件句柄,锁资源释放,数据库连接释放

四、递归函数

1、一个函数调用自己,就叫递归函数

2、斐波那契数

//斐波那契数列示例:

func fb( n int)int{

if n <=1{

return 1

}

return fb(n-1)+fb(n-2)

}

func main(){

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

n := fb(i)

fmt.Println(n)

}

}

3、递归的设计原则

3.1、一个大问题能够分解成相似的小问题

3.2、定义好出口条件(即结束递归循环的条件)

五、闭包

一个函数和与其相关的引用环境的组合成的实体

//示例一:

func Adder() func(int)int{

var x int

return func(delta int)int{

x +=delta

return x

}

}

//示例2:

func makeSuffixFunc(suffix string) func(string)string{

return func(name string)string{

if !strings.HasSuffix(name ,suffix){

return name + suffix

}

return name

}

}

func main(){

//练习五:闭包

//示例1:

// var f = Adder()

// fmt.Println(f(1))

// fmt.Println(f(10))

// fmt.Println(f(100))

//示例2:

func1 := makeSuffixFunc(".jpg")

func2 := makeSuffixFunc(".txt")

fmt.Println(func1(func1("test")))

fmt.Println(func2("test"))

}

六、数组和切片

1.1、排序和查找操作

  排序操作主要都在sort包中,导入就可以使用

  sort.Ints对整数进行排序, sort.Strings对字符串串进?行行排序, sort.Float64s对 浮点数进?行行排序.

  sort.SearchInts(a []int, b int) 从数组a中查找b,前提是a 必须有序

  sort.SearchFloats(a []float64, b float64) 从数组a中查找b,前提是a 必须有序

  sort.SearchStrings(a []string, b string) 从数组a中查找b,前提是a 必须有序

时间: 2024-08-09 13:10:14

GO-指针与函数的相关文章

C#委托与C语言函数指针及函数指针数组

C#委托与C语言函数指针及函数指针数组 在使用C#时总会为委托而感到疑惑,但现在总新温习了一遍C语言后,才真正理解的委托. 其实委托就类似于C/C++里的函数指针,在函数传参时传递的是函数指针,在调用的时候通过指针访问这个函数. 在C语言中函数指针的申明如下: //可以理解为申明一个指着变量 Func ,它的类型是 返回Type(可以为 void )类型的参数,接收 (Type one,Type two,...)类型的//参数(可以不接受参数). Type *Func(Type one,Type

了解指针(5)-- 指针和函数

就像数组名是指向数组的第一个元素的常指针一样,函数名也是指向函数的常指针.可以声明一个指向函数的指针变量,并且用这个指针调用其他函数(只要这个函数和你的函数指针在签名.返回.参数值方面一致即可). 例1: long  (* fun) (int) 上面就是一个函数指针,该指针返回值类型是long,所带的参数类型是int. 例2: int fun(char *,int); int (*pfun)(char *,int); pfun=fun; int a=(*pfun)("abcdefg",

C语言指针与函数的关系

一: 函数和指针关系: 1)指向函数的指针 2)指针作为函数的参数 int max(int *p1,int *p2){ } 1)实参可以是一个指针 2)也可以是一个和形参类型相同的数组的数组名 3)返回值是指针的函数: 指针函数 char* 函数名(){ return 地址 } //返回值是一个字符串指针 char * test(){ return "xxxx"; } char * test2(){ char ch='a'; return &ch; } 二: 函数的指针: 1)

数组和指针(2)----指针调用函数

#include <stdio.h>#include<stdlib.h>int add(int a, int b){ return a + b;}int Max(int a, int b){ int i; i=a > b ? a : b; return i;}int main(){ //指针指向函数 //普通写法 int i = add(5,6); printf("%d\n",i); //指针写法 int i1; int(*p)(int, int);//定

嵌入式Linux C语言(三)——指针与函数

嵌入式Linux C语言(三)--指针与函数 指针对函数的功能有巨大的贡献,指针能够将数据传递给函数,并且允许函数对数据进行修改.指针对于函数的作用主要有两方面:将指针传递给函数和声明函数指针. 一.程序的栈和堆 程序的栈和堆是C语言程序运行的运行时元素. 1.程序栈 程序栈是支持函数执行的内存区域,通常和堆共享一块内存区域,通常程序栈占据内存区域的下部,堆用内存区域的上部.程序栈存放栈帧,栈帧存放函数参数和局部变量.调用函数时,函数的栈帧被推倒栈上,栈向上长出一个栈帧,当函数终止时,函数的栈帧

【转载】C/C++杂记:深入理解数据成员指针、函数成员指针

原文:C/C++杂记:深入理解数据成员指针.函数成员指针 1. 数据成员指针 对于普通指针变量来说,其值是它所指向的地址,0表示空指针.而对于数据成员指针变量来说,其值是数据成员所在地址相对于对象起始地址的偏移值,空指针用-1表示.例: 代码示例:   2. 函数成员指针 函数成员指针与普通函数指针相比,其size为普通函数指针的两倍(x64下为16字节),分为:ptr和adj两部分. (1) 非虚函数成员指针 ptr部分内容为函数指针(指向一个全局函数,该函数的第一个参数为this指针),ad

函数指针与函数指针数组的使用方法

转自:http://blog.csdn.net/feitianxuxue/article/details/7300291 函数指针与函数指针数组的使用方法 函数指针: 函数指针包含函数在内存中的地址.数组名实际上就是数组的第一个元素在内存中的地址,类似地,函数名实际上也是执行这个函数任务的代码在内存中的起始地址. 函数指针可以传递给函数.从函数返回.保存在数组中.赋予另一个函数指针或者调用底层函数. 下面我们用数值算法accumulate讨论下函数指针的用法.accumulate是一种常用的ST

【学习笔记】【C语言】返回指针的函数

函数如果带*的返回的就是指针 char *test(){ } 1 #include <stdio.h> 2 char *test(); 3 4 /* 5 返回指针的函数 6 */ 7 8 int main() 9 { 10 char *name = test(); 11 12 printf("name=%s\n", name); 13 14 return 0; 15 } 16 17 char *test() 18 { 19 return "rose";

指针 指针与数组 指针与字符串 指针与函数 结构体与指针 宏

指针 指针与数组 指针与字符串 指针与函数?? 指针与数组 1.数组名:数组元素首地址 eg: int array[3]={1,3,6}; 这里array 恒等于&array[0] 2.int *p = a; int *p = 0; int a[]={0}; 3.int *p = a; 均指向数组的首地址 *p是? *(p+1)是?(*p)+1是? *(p+1)决定向下移动几个字节是类型 4.指针可以当数组名使用 p[1] = 3; 恒等于a[1] ;恒等于*(p+1);恒等于*(a+1) 5.

入职培训笔记记录--day9(1、指针函数与函数指针、函数指针数组 2、malloc memset 3、递归函数 4、结构体 5、共用体---》大小端 6、枚举)

1.指针函数与函数指针.函数指针数组 指针函数:返回值为指针的函数 char *fun() { char str[] = "hello world"; return str; } int main() { char *p = fun(); puts(p); return 0; } 编译时,会出现警告,返回了一个已经被释放掉的内存空间的首地址解决方法:1.static 2.char *str = "hello world"; 3.malloc 注意:使用完后要free