指针的相关介绍

           宠辱不惊,闲看庭前花开花落;

去留无意,慢随天外云卷云舒。 


 

目录

数组指针

数组传参

函数指针

函数指针数组

回调函数

 指向函数指针数组的指针

 qsort 函数的使用——冒泡排序函数


数组指针

数组指针的定义:数组指针是指针

整型指针: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;
}

制作不易,恳请三连 !!!

在苦难中,浴火重生;在磨砺中,凤凰涅槃。 

加油,宝子们!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值