宠辱不惊,闲看庭前花开花落;
去留无意,慢随天外云卷云舒。
目录
数组指针
数组指针的定义:数组指针是指针
整型指针:int*pint;能够指向整形数据的指针,存放整型的地址;
那数组指针应该是:能够指向数组的指针,可以存放数组的地址。
arr——首元素地址
&arr[0]——首元素地址
&arr——数组的地址
int* p[10]={0}; 数组
int(*p)[10]=&arr; 存放数组的地址,p就是数组指针
下面代码哪一个是数组指针?
int *p1[10]; int(*p2)[10];
解释:int(*p2)[10];
p先和*结合,说明p是一个指针变量,然后指针指向的是一个大小为10个整型的数组,所以p是一个指针,指向一个数组,叫数组指针。
注意:[ ]的优先级要高于*号的,所以必须加上()来保证p先和*结合
数组传参
#include<stdio.h。
void test(int arr[]) //[ ]里的值可以不填
{}
void test(int arr[10])
{}
void test(int *arr)
{}
void test2(int*arr[20])
{}
void test(int **arr) //erro,一级指针的地址放到二级指针,二维数组的首元素是第一行
{}
int mian()
{
int arr[10];
int* arr[20]={0};
test(arr);
test2(arr);
}
//二维数组传参,可以省略行,不可以省略列
void test3(int *arr)
{}
void test4(int **arr) //error,整型指针存放整形地址,二级指针不能存放一维数组地址
{}
void test5(int(*arr)[5]
{}
int main()
{
int arr[3][5]={0};
test3 (arr);
test4(arr);
test5(arr);
return 0;
}
#include<stdio.h> void pint(int*p,int sz) { int i=0; for(i=0;i<sz;i++) { printf("%d\n",*(p+i)); } } int main() { int arr[10]={1,2,3,4,5,6,7,8,9}; int*p=arr; int sz=sizeof(arr)/sizeof(arr[0]); print(p,sz); 一级指针p,传给函数 retrun 0; }
思考:当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
一级指针传参
void test1(int*p)
{}
int main()
{
int a=10;
int *P1=&a;
test1(&a);
test1(p1);
return 0;
}
二级指针传参
#include<stdio.h>
void test(int**ptr) //传参是传一级指针地址,或二级指针变量
{
printf("num=%d\n",**ptr);
}
int main()
{
int n=10;
int *p=&n;
int **pp=&p;
test(pp);
test(&p);
int *arr[10];
test(arr);
return 0;
}
函数指针
定义:指向函数的指针
int Add(int x,int y)
{
int z=0;
z=x+y;
return z;
}
int main()
{
int a=10;
int a=20;
printf("%p\n",Add(a,b));
printf("%p\n",&Add); //&函数名=函数名,都是函数地址
return 0;
}
//以上主函数还可这样写
int main()
{
int a=10;
int b=20;
int(*pa)(int,int)=Add;
printf("%d\n",(*pa)(2,3));//也可以写成(pa)(2,3) *有没有无关紧要
return 0;
}
void Print (char*str)
{
printf("%s\n",str);
}
int main()
{
void(*p)(char*)=Print;
(*p)("hello bit"); //*p相当于Print
return 0;
}
void *pfun2(); //非指针
void(*p)fun1(); //是指针
下面讲两个坑
①(*(void(*)()0)();
把0强制类型转换成:void(*)()函数指针类型,0是一个函数的地址,调用0地址处的该函数
②void(*signal(int,void(*)(int)))(int);
void(* )(int);
signal返回类型是函数指针
typedef void(*pfun_t)(int);
pfun_t signal(int,pfun_t);
typedef void(*)(int) pfun_t
signal是个函数声明,参数有2个,第一个是int。第二个是函数指针,该函数指针指向的函数的参数是int,返回类型是void。signal函数的返回类型也是一个函数指针,该函数指针指向的函数的参数是int,返回类型是void。
函数指针数组
int Sub(int x,int y)
{
return x-y;
}
int Mul(int x,int y)
{
return x*y;
int Div(int x,int y)
{
return x/y;
}
int main()
{
int *arr[5];
int (*pa[3])(int,int)={Sub,Mul,Div};//需要一个数组,这个数组可以存放3个函数的地址
int i=0;
for(i=o;i<3;i++)
{
printf("%d\n",pa[i](2,3));
}
return 0;
}
int (*parr[10])()
parr先和[ ]结合,说明parr是数组,数组的内容是int(*)()类型的函数指针
函数指针数组的用途:转移表
下面写一个简单的计算器
void menu()
{
printf("**************************");
printf("** 1.add 2.sub**");
printf("** 3.mul 4.div**");
printf("** 0.exit **");
}
int Add(int x,int y)
{
return x+y;
}
int Sub(int x,int y)
{
return x-y;
}
int MUl(int x,int y)
{
return x*y;
}
int Div(int x.int y)
{
return x/y;
}
int main()
{
int input=0;
int x=0;
int y=0;
int(*pfArr[ ])(int,int)={0,Add,Sub,Mul,Div}; //函数指针数组pfArr-----转移表
do //用switch语句过长
{
menu()
printf("请选择:>");
scanf("%d",&input);
if(input>=1&&input<=4)
{
printf("请输入两个操作数:>");
scanf("%d%d",&x,&y);
int ret=pfArr[input](x,y);
printf("%d\n",ret);
}
else if(input==0)
{
printf("退出\n");
}
else
{
printf("选择错误\n");
}
}while(input);
}
回调函数
回调函数就是一个通过函数指针调用的函数,如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外一方调用的,用于该事件或条件进行响应。
下面举例说明
例子1
int Add(int x,int y)
{
return x+y;
}
...
void Calc(int(*pf)(int ,int))
{
int x=0;
int y=0;
printf("请输入两个操作数:");
scanf("%d%d",&x,&y);
printf("%d\n",pf(x,y));
}
int mian()
{
int input=0;
do
{
menu()
printf("请选择:>");
scanf("%d",&input);
switch(input)
{
case 1:
Calc(Add);
break;
case 2:
Calc(Sub);
break;
case 3:
Calc(Mul);
break;
case 4:
Calc(Div);
break;
}
}while(input);
}
例子2
void print(char *str)
{
printf("hehe:%s",str);
}
void test(void(*p)(char*))
{
printf("test\n");
p("bit");
}
int main()
{
test(print);
return o;
}
指向函数指针数组的指针
int Add(int x,int y)
{
return x+y;
}
int main()
{
int arr[ ]={0};
int (*p)[10]=&arr; //取出数组的地址
int(*pfArr[4])(int,int);//pfArr是一个数组——函数指针数组
int(*(*ppfArr)[4])(int,int)=&pfArr;
//ppfArr是个数组指针,指针指向的数组有4个元素;
//指向的数组的每个元素的类型是一个函数指针int(*)(int,int)
//ppfArr是一个指向函数指针数组的指针
return 0;
}
qsort 函数的使用——冒泡排序函数
使用回调函数,模拟实现qsort
注意:这里讲解到void*指针的作用
qsort(s,sz,sizeof(s[0]),cmp_stu_by_name);
第一个参数:待排序数组的首元素地址
地二个参数:待排序数组的元素个数
第三个参数:待排序数组的每个元素的大小---单位是字节
第四个参数:函数指针,比较两个元素所用函数的地址(这个函数是使用者自己实现),函数指针的两个参数是待比较两个元素的地址
#include<stdio.h>
int int_cmp(const void *p1,const void *p2)
{
return (*(int*)p1-*(int*)p2);
}
void Swap(char* buf1,char* buf2,int width)
{
int i=0;
for(i=0;i<width;i++)
{
char tmp=*buf1;
*buf1=*buf2;
*buf2=tmp;
buf1++;
buf2++;
}
}
void bubble_sort(void*base,int sz,int width,(*cmp)(void*e1,void*e2))
{
int i=0;
//趟数
for(i=0;i<sz-1;i++)
{
int j=0;
//每一趟的比较的对数
for(j=0;j<sz-1-i;j++)
{
//两个元素的比较
if(cmp((char*)base+j*width,(char*)base+(j+1)*width)>0)
{
//交换
Swap((char*)base+j*width,(char*)base+(j+1)*width,width);
}
void test4()
{
int arr[10]={9,8,7,6,5,4,3,2,1,0};
int sz=sizeof(arr)/sizeof(arr[0]);
bubble_sort(arr,sz,sizeof(arr[0]),cmp_int);
//使用bubble_sort的程序员一定知道自己排序的是什么数据
//就应该知道如何比较排序数组中的元素
}
struct
{
char name[20];
int age;
};
int cmp_stu_by age(const void*e1,const void*e2)
{
return ((struct Stu*)e1)->age-((struct Stu*)e2->age;
}
int cmp_stu_stu_by name(const void*e1,const void*e2)
{
return strcmp(((struct Stu*)e1)->name,((struct Stu*)e2)->name);
比较名字就是比较字符串,不能直接用<>=来比较,应该用strcmp函数
}
void test5()
{
struct Stu s[3]={{"zhangsan",20},{"lisi",30},{"wangwu",10}};
int sz=sizeof(s)/sizeof(s[0]);
bubble_sort(s,sz,sizeof(s[0]),com_stu_by age);
bubble_sort(s,sz,sizeof(s[0]),cmp_stu_by name);
int mian()
{
int arr[]={0};
int i=0;
qsort(arr,sizeof(arr[0]),sizeof(int),int_cmp);
for (i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
printf("%d",arr[i]);
}
printf("\n");
return 0;
}
制作不易,恳请三连 !!!
在苦难中,浴火重生;在磨砺中,凤凰涅槃。
加油,宝子们!