做外贸的经常浏览的三个网站,大连建设网缴费查询,crm客户管理系统api,化妆品网站推广策划书内容提要
指针 函数指针与指针函数二级指针
指针
函数指针与指针函数
函数指针
定义
函数指针本质上是指针#xff0c;是一个指向函数的指针。函数都有一个入口地址#xff0c;所谓指向函数的指针#xff0c;就是指向函数的入口地址。#xff08;这里的函数名就代表…内容提要
指针 函数指针与指针函数二级指针
指针
函数指针与指针函数
函数指针
定义
函数指针本质上是指针是一个指向函数的指针。函数都有一个入口地址所谓指向函数的指针就是指向函数的入口地址。这里的函数名就代表入口地址
函数指针存在的意义
让函数多了一种调用方式函数指针可以作为形式可以形式调用回调函数
语法
返回值类型(*指针变量名)(形参列表);举例
int (*p)(int a, int b);函数指针的初始化
①定义的同时赋值
// 函数指针需要依赖于函数先有函数后有指针// 定义一个普通函数
// 普通函数
int add(int a, int b){return a b};// 定义一个函数指针并初始化
// 观察函数指针的返回类型和指向函数的返回类型一致函数的形参列表个数、类型、顺序跟指向函数的形参列表一致
int (*p)(int a, int b) add; // 函数指针p指向函数add这里的add不能带()add就是该函数的入口地址②先定义后赋值
// 函数指针需要依赖于函数先有函数后有指针// 定义一个普通函数
// 普通函数
int add(int a, int b){return a b};// 定义一个函数指针并初始化
// 观察函数指针的返回类型和指向函数的返回类型一致函数的形参列表个数、类型、顺序跟指向函数的形参列表一致
int (*p)(int, int) add; //形参列表的参数名可以省略p add; //此时是将add的入口地址赋值给指针注意: 1.函数指针指向的函数要和函数指针定义的返回值类型形参列表对应否则编译报错 2.函数指针是指针但不能指针运算如p等没有实际意义 3.函数指针作为形参可以形成回调 4.函数指针作为形参函数调用时的实参只能是与之对应的函数名不能带小括号() 5.函数指针的形参列表中的变量名可以省略 注意函数不能作为函数的形参但是指向函数的函数指针是可以作为函数的形参的。
案例
需求求a,b两个数的最大值代码
/**
* 定义一个函数求两个数的最大值
**/
int ger_max(int a, int b)
{return a b ? a : b;
}int main()
{// 定义测试数据int a 3, b 4, max;// 直接调用函数max get_max(a,b);printf(%d,%d中的最大值是%d\n,a,b,max);// 定义一个函数指针int (*p)(int,int) get_max;// 间接调用函数方式1max p(a,b); //直接将指针名作为函数名printf(%d,%d中的最大值是%d\n,a,b,max);// 间接调用函数方式2max (*p)(a,b); //直接将指针名作为函数名printf(%d,%d中的最大值是%d\n,a,b,max);return 0;
}回调函数
定义
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针作为参数传递给另一个函数当这个指针备用来调用其所指向的函数时。我们就说这是回调函数。回调函数不是由该函数的实现方直接调用而是在特定的事件或条件发生时由另外的一方调用的用于对该事件或条件进行响应。
为什么要用回调函数
因为可以把调用者与被调用者分开所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。
简而言之回调函数就是允许用户把需要调用的方法的指针作为参数传递给一个函数以便该函数在处理相似事件的时候可以灵活的使用不同的方法。
/**
*回调函数1
*/
int callback_1(int a)
{printf(hello, this is callback 1:a%d\n, a),return a;
}/**
*回调函数2
*/
int callback_2(int b)
{printf(hello, this is callback_2:b%d\n, b);return b;
}/**
*实现回调函数函数的参数是函数指针
*/
int handle(int x, int(*callback)(int))
{printf(日志开始执行任务\n);int res callback(x);printf(日志执行结果%d\n, res);printf(日志结束执行任务\n);
}int main(int argc,char *argv[])
{handle(100,callback_1);handle(200,callback_2); return 0;
}指针函数
定义
本质上是函数这个函数的返回值类型是指针整个函数称之为指针函数。
int *p普通指针。int (*p)[3]数组指针。int *p[]指针数组。int (*p)()函数指针。int *p()指针函数。
语法
// 写法1
数据类型* 函数名(形参列表)
{函数体return 指针变量;
}
// 写法2
数据类型 *函数名(形参列表)
{函数体;return 指针变量;
}举例
int *get(int a)
{int *p a;return 0;
}
int main()
{int *a get(5);printf(%d\n*a);
}注意:
在函数中不要直接返回一个局部变量的地址因为函数调用完毕后局部变量会被回收使得返回的地址就不明确此时返回的指针就是野指针。
解决方案
如果非要访问可以给这个局部变量添加定义的时候添加static 可以延长它的生命周期从而避免野指针尽量少用因为存在内存泄漏
演示案例
int *add(int a, int b)
{static int sum; // 使用static修饰局部变量会提升生命周期但是作用域不会发生改变不建议sum a b;return sum; // 执行完return 作为函数作用域的布局变量sum的空间被释放
}int main()
{int *res add(5,3); // 接收到了地址但是地址对应的空间已经被释放printf(%d\n, *res);return 0;
}案例
需求有若干个学生每个学生有4门成绩要求在用户输入学号int id后能输出该学生的全部成绩float scores[4]用指针函数实现。
/**
* 定义一个函数要求输入学生序号返回该学生所有成绩
* param all所有人的成绩
* param id要检索学生的序号
* return id对应血行的成绩数组指针
*/
float* search(float (*all)[4], int id)
{// 定义一个指针变量用来接受查询到的某个学生的所有成绩float *pt;pt *(all id); //行偏移return pt; // 赋值运算中 float pt[4] float *pt;
}int main()
{// 准备一个二维数组存储3个学生的成绩float scores[][4] {{60,70,80,90},{66,77,88,99},{61,71,81,91}};// 定义一个变量用来接收学生序号int mprintf(请输入学生序号0~2\n);scanf(%d, m);printf(第%d个学生的成绩\n, m);// 创建一个指针用来接收成绩float *p search(scores, m);// 遍历成绩for(; p scores[m] 4; p){printf(%5.2f\t, *p);}printf(\n);return 0;
}二级指针
定义
二级指针多重指针用于存储一级指针的地址需要两次解引用才能访问原始数据其他多级指针的用法类似实际开发中最常见的多级指针是二级指针
int a 10; // a是普通变量
int *p a; // 一级指针p指向a,p存储的是a的地址
int **w p; // 二级指针w指向pw存储的是p的地址
int ***x w // 三级指针x指向wx存储的是w的地址语法
数据类型 **指针变量名 指针数组的数组名 | 一级指针的地址特点
①与指针数组的等效性二级指针与指针数组等效性但与二维数组不等效。二维数组名是数组指针类型如int (*)[3]而非二级指针。
// 指针数组
int arr[] {11,22,33};
int* arr_[] {arr[0], arr[1], arr[2]}; // 正确的指针数组的定义// 二级指针接受指针数组
char* str[3] {abc,aaa034,12a12}; // str存储的是三个字符串的首地址
char **p str;②与二维数组的差异二维数组名是数组指针类型直接赋值给二级指针会导致类型不匹配
int arr[2][3] {{1,3,5}{11,33,55}};
int (*p)[3] arr; //arr这个数组名就是数组指针类型int **k arr; // 编译报错arr类型 int*[3] 不兼容 k类型 int**解引用
①字符型二级指针可直接遍历字符串数组类似一维数组
void fun1()
{// 定义一个字符类型的指针数组char *arr[] {orange,apple,banana,kiwi};int len sizeof(arr) / sizeof(arr[0]);for (int i 0; i len; i){printf(%s\n,arr[i]);}printf(\n);
}void fun2()
{char *arr[] {orange,apple,banana,kiwi};int len sizeof(arr) / sizeof(arr[0]);// 二级指针等效于指针数组char **p arr;for(int i 0; i len; i){printf(%s\n,p[i]); //下标法printf(%s\n,*(pi)); //指针法}printf(\n);
}void fun3()
{char *arr[] {orange,apple,banana,kiwi};int len sizeof(arr) / sizeof(arr[0]);// 二级指针等效于指针数组char **p;// 定义循环变量int i 0// 遍历指针数组do{p arr i; // p arr ---- p arr 0printf(%s\n, *p);i;}while(i len);
}int main()
{fun1();fun2();fun3();return 0;
}②其他类型的二级指针需要两次解引用访问数据常用于操作指针数组
int main()
{// 普通的一维数组int arr1[] {11,22,33,44,55,66};// 创建一个指针数组int *arr[] {arr1[0],arr1[1],arr1[2],arr2[3],arr1[4],arr1[5]};// 用一个二级指针接收指针数组int **p arr;// 遍历数组for(int i 0; i sizeof(arr) / sizeof(arr[0]); i){printf(%-6d, *p[i]); //下标法printf(%-6d, **(p i)); // 指针法 等价于*(*(pi))}pritnf(\n);return 0;
}总结
①二级制指针与指针数组等效可简化指针数组的遍历操作
②二维数组名是数组指针类型(如: int(*)[3])与二级指针( int**)类型不兼容。
③操作非字符型二级指针时须通过两次解引用访问实际数据。