指针数组
说白了,就是存放指针的数组
数组指针
存放数组变量的地址的指针
数组指针的使用
我们看一下这个代码,我们会发现这个代码很别扭
这个代码奇怪的地方就在print传过去的&arr和print接受的指针类型,以及打印的写法。
首先说明不建议这么写。
这里传过的&arr是一个地址,而地址就是指针,这个指针指向数组,所以是数组指针
p是&arr,而p不就是&arr,和&不就相互抵消了嘛,所以p=arr
二维数组传参(写成指针)
arr1为二维数组,而arr1这个数组名表示二维数组的首地址,而二维数组的首地址是第一行的地址。
所以二维数组的数组名是指向二维数组的第一行的,这个第一行相当于一个一维数组
相当二维数组的首地址是一个指针,然后它指向一个一维数组,所以写成数组指针。
而这个我解释一下,p1+i相当于访问第i行的地址,*(p1+i)解引用相当于第i行,然后再加j然后解引用,相当于找第i行第j列的那一个。
数组指针和指针数组的区分
数组名与&数组名的区别
我们来看一个例子
这里我们发现arr和&arr是一样,而arr是首元素地址,&arr是整个数组的地址,但整个数组的地址也得从首元素一样啊。
我们看下面两个,这两个的后两位一个是2C一个是50,2C是2x16+12x1=44. 50是5x16=80,这两个的差值是36加上第一个的地址的4刚好是40,跳过一整个数组的大小。
数组传参和指针传参
数组传参时,形参可以是数组也可以是指针。
一维数组传参
这里比较有困惑的应该是第五个,我们的arr2是一个存放整形指针(地址)的数组,而我们的int**arr是二级指针
二级指针就是存放着一级指针的指针,这两个不就是相同的嘛,所以可以传过去。
二维数组传参
一维指针传参
一级指针传参只能用一级指针来接收
二维指针传参
二级指针传参只能用二级指针来接收
当形参确定为一级指针时,可以将什么变量传过去呢?
一级指针(*p),一级数组(arrp[10]),&a
当形参确定为二级指针时,可以将什么变量传过去呢?
二级指针(**p),对一级指针取地址(&p2)(p2为一级指针),指针数组(int*p[10])
函数指针
我们先来看一个例子:
我们通过这个例子我们可以知道,原来函数名也等于函数的地址啊
函数指针的定义方法:int(*p)(int x,int y)=Add;
调用函数指针的时候,函数指针的传过去的值可以写名字也可以不写名字
下面这个例子要理解一下
函数指针数组
说白了就是存放了函数指针的数组
int(*p[5])(int x, int y) = { 0, add, sub, mul, div };
回调函数
回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个
函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数
的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进
行响应。
简单来说就是:一个函数指针(或者地址)作为一个函数参数被另外一个函数调用,这个函数就叫做回调函数
我们先来看一个库函数qsort(只是一个排列函数)(头文件#include)
代码完整实现
void*类型的指针很宽容,什么类型的指针都可以放进去,但应用的时候不好运用
void型时你p+1访问的几个字节的长度不清楚
如果我们利用冒泡排序的方法写一个与qsort类似的函数呢
不同类型的数据,比较方法也不一样,用冒泡排序来举例子就是
如果我们利用冒泡排序的方法的话
我们就需要找到要比较的两个值的地址,但void*不可以进行+/-等操作。所以要下面这样
完整代码如下