一.指针
1.指针作为形参
指针作为形参和数组作为形参完全等价
指针变量和数组名的异同
指针变量和数组名在很多地方是类似的,都代表的是一个地址,作为形参完全等价
差别:
指针变量可以赋值但是数组名不行
对指针变量进行sizeof运算得到的是指针变量的大小(4字节),对数组名进行sizeof运算得到的是整个数组的大小
对指针变量进行取地址运算(&)得到的是指针变量在内存中的地址,对数组名取地址的结果还是数组名本身的地址值(类型变成二维数组)
如果希望被调用函数中对数据的修改能够让调用函数得到,那么就传递该数据的地址
2.指针作为返回值
指针作为返回值也可以让调用函数和被调用函数共享存储位置
使用指针变量作为返回值也只能实现值的单向传递,被调用函数返回之后函数已经结束了
注:千万不要使用局部变量的地址作为返回值(生命周期决定的)
指针作为返回值可以让被调用函数传递大量数据给调用函数
3.地址和整数的运算
只有以下地址运算才有意义
地址+整数 地址-整数 地址-地址
前两个的运算可以认为整数是有单位的,单位是地址指向存储位置的大小(存储位置的类型有地址类型决定)
最后一个运算的结果也是有单位的,单位也是地址指向存储位置的大小
3.const指针
声明指针可以使用const关键字
使用const声明指针有多种语法:
const int *p_num;//常量指针
int const *p_num;//常量指针
int *const p_num;//指针常量
前两种声明语法中,可以修改指针记录的地址,不修改指针指向的值
后一种声明语法中,可以修改指针指向的值,不能修改指针记录的地址
const int *const p_num;
以上语法中地址和指向的值都不能修改
4.二级指针(补充)
二级指针可以和二维数组名对应
声明语法:
int **pp_num;
其中int **是二级指针变量类型,指向的数据类型为int *
二级指针的使用
当我们在函数调用时,希望被调用函数中对指针记录地址的修改让调用函数得到,就可以使用二级指针作为形参
5.指针数组和数组指针
(1)指针数组是一个数组,它的数组元素是指针
声明语法:
指针类型 指针数组名[元素个数];
使用指针数组保存地址时,最后一个元素保存为NULL指针
由于指针数组以NULL结束,指针数组作为函数形参是不需要传递数组长度
(2)数组指针是一个指针,这个指针指向的数据是一个数组
指向一维数组的指针就是一个普通的指针,指针的类型和数组元素地址类型相同
指向二维数组的指针本质上应该是一个二级指针(特殊)
声明语法:
数据类型 (*指针变量名)[组内元素个数];
中括号中的数字表示该指针指向的二维数组中一组的元素个数,也就是意味着指针变量名加1跨越一组元素的长度
((二维数组指针+i)+j) 得到的是第i组第j个元素的值
6.指针函数和函数指针
(1)指针函数是一个函数,函数的返回值是一个指针
略
(2)函数指针是一个指针,这个指针指向的数据是一个函数
本质上来说函数指针就是用来记录函数地址(函数地址就是函数中第一条语句地址)
在代码中可以用函数名来代表函数地址
函数指针一旦记录了某个函数的地址就可以利用这个函数指针来调用该函数
函数指针是有类型的,不同函数对应的函数指针类型不同
函数指针的类型和函数返回值,参数有关系
函数指针声明语法:
返回值类型 (*函数指针变量名)(参数列表);
该函数指针的类型为 返回值类型 (*)(参数列表)
使用函数指针记录函数地址时,要求函数指针的类型和指向函数类型一致
练习:
编写程序,计算用户输入的二元四则运算表达式(编写加减乘除的函数,使用一个函数指针来调用函数)
1+1 2*2 5/3 10-2
函数指针作为函数形参可以让先写好的函数去调用后写好的函数,也就是相当于函数一部分功能由调用者定义,大大提高编程的灵活性
这种场景下后写好的函数叫做回调函数(callback)或者钩子函数
一.指针
1.指针作为形参
指针作为形参和数组作为形参完全等价
指针变量和数组名的异同
指针变量和数组名在很多地方是类似的,都代表的是一个地址,作为形参完全等价
差别:
指针变量可以赋值但是数组名不行
对指针变量进行sizeof运算得到的是指针变量的大小(4字节),对数组名进行sizeof运算得到的是整个数组的大小
对指针变量进行取地址运算(&)得到的是指针变量在内存中的地址,对数组名取地址的结果还是数组名本身的地址值(类型变成二维数组)
如果希望被调用函数中对数据的修改能够让调用函数得到,那么就传递该数据的地址
2.指针作为返回值
指针作为返回值也可以让调用函数和被调用函数共享存储位置
使用指针变量作为返回值也只能实现值的单向传递,被调用函数返回之后函数已经结束了
注:千万不要使用局部变量的地址作为返回值(生命周期决定的)
指针作为返回值可以让被调用函数传递大量数据给调用函数
3.地址和整数的运算
只有以下地址运算才有意义
地址+整数 地址-整数 地址-地址
前两个的运算可以认为整数是有单位的,单位是地址指向存储位置的大小(存储位置的类型有地址类型决定)
最后一个运算的结果也是有单位的,单位也是地址指向存储位置的大小
3.const指针
声明指针可以使用const关键字
使用const声明指针有多种语法:
const int *p_num;//常量指针
int const *p_num;//常量指针
int *const p_num;//指针常量
前两种声明语法中,可以修改指针记录的地址,不修改指针指向的值
后一种声明语法中,可以修改指针指向的值,不能修改指针记录的地址
const int *const p_num;
以上语法中地址和指向的值都不能修改
4.二级指针(补充)
二级指针可以和二维数组名对应
声明语法:
int **pp_num;
其中int **是二级指针变量类型,指向的数据类型为int *
二级指针的使用
当我们在函数调用时,希望被调用函数中对指针记录地址的修改让调用函数得到,就可以使用二级指针作为形参
5.指针数组和数组指针
(1)指针数组是一个数组,它的数组元素是指针
声明语法:
指针类型 指针数组名[元素个数];
使用指针数组保存地址时,最后一个元素保存为NULL指针
由于指针数组以NULL结束,指针数组作为函数形参是不需要传递数组长度
(2)数组指针是一个指针,这个指针指向的数据是一个数组
指向一维数组的指针就是一个普通的指针,指针的类型和数组元素地址类型相同
指向二维数组的指针本质上应该是一个二级指针(特殊)
声明语法:
数据类型 (*指针变量名)[组内元素个数];
中括号中的数字表示该指针指向的二维数组中一组的元素个数,也就是意味着指针变量名加1跨越一组元素的长度
((二维数组指针+i)+j) 得到的是第i组第j个元素的值
6.指针函数和函数指针
(1)指针函数是一个函数,函数的返回值是一个指针
略
(2)函数指针是一个指针,这个指针指向的数据是一个函数
本质上来说函数指针就是用来记录函数地址(函数地址就是函数中第一条语句地址)
在代码中可以用函数名来代表函数地址
函数指针一旦记录了某个函数的地址就可以利用这个函数指针来调用该函数
函数指针是有类型的,不同函数对应的函数指针类型不同
函数指针的类型和函数返回值,参数有关系
函数指针声明语法:
返回值类型 (*函数指针变量名)(参数列表);
该函数指针的类型为 返回值类型 (*)(参数列表)
使用函数指针记录函数地址时,要求函数指针的类型和指向函数类型一致
练习:
编写程序,计算用户输入的二元四则运算表达式(编写加减乘除的函数,使用一个函数指针来调用函数)
1+1 2*2 5/3 10-2
函数指针作为函数形参可以让先写好的函数去调用后写好的函数,也就是相当于函数一部分功能由调用者定义,大大提高编程的灵活性
这种场景下后写好的函数叫做回调函数(callback)或者钩子函数