1.字符指针
char s1[]="hello world";
char s2[]="hello world";
const char* s3="hello world";
const char* s4="hello world";
对于常量字符串来说,会开辟一块独立的空间来存放该常量,字符指针指向的是该空间,故s3和s4指向的空间相同,而s1,s2变量指向的空间不同。
2.数组指针
数组指针是指向数组的指针。
int arr[5]={0};
int (*p)[5]=&arr; //数组的元素类型 (*a表示是指针变量)[数组的元素个数]
这里的p是用来存放数组的地址,p就是数组指针。
char* arr2[5];
char* (*pc)[5]=&arr2;
数组指针看起来很繁琐,那么它的应用场景一般是什么呢?
可以用来代替形式参数二维数组的数组名,传参时二维数组的数组名代表首元素地址,而其首元素地址就是第一行数组的地址。
void print(int arr[2] [4],int h,int l)<-->void print(int (*arr) [4] ,int h,int l)
3.指针数组
指针数组就是存放指针的数组,数组中的元素都是指针类型的。一般来说,指针数组可以模拟实现二维数组。
char* arr[5]; //存放字符指针的数组
int* arr[5]; //存放整形指针的数组,该数组有5个元素,每个元素表示int*类型。
4.指针传参和数组传参
数组传参的本质是传递数组首元素的地址,其形式可以是数组名,也可以是指针。
一维数组传参,传递的是第一个元素的地址;二维数组传参,传递的是第一行的地址。
test(int a[5]){}
test(int a[]){} //形参是数组
test(int *a){} //形参是指针
int arr[5]={0};
test(arr);
test(int[2][4]){}
test(int[ ] [4]){} //形参写成数组,行数可以省略,列数不可以省略。
test(int (*a)[4]){} //形参写成指针
int arr[2][4]={0};
test(arr);
5.函数指针
函数指针是指向函数的指针,存放的是函数的地址。
与数组不同的是,函数不存在首元素的地址,&函数名和函数名都是函数的地址。
int Function(int x,int y){}
int(*p)(int,int)=Function;
int(*p)(int,int)=&Function; //p就是一个函数指针变量
int ret=(*p)(int,int);
int ret1=p(int,int);
int ret2=Function(int,int); //调用函数指针时 * 可以省略,这三种写法都可以调用Function
6.函数指针数组
函数指针数组就是存放函数指针的数组,其本质是数组。
int Add (int a,int b){
return a+b;}
int Sub(int a.int b){
return a-b;}
int (*p)(int,int)=&Add;
int(*p2)(int,int)=⋐
int (*ptrArr[5])(int,int)={&Add,&Sub}; //这就是一个函数指针数组
7.回调函数
回调函数举例:qsort,是一个库函数。
void qsort (void* base, //指向待排序数组第一个对象的指针 size_t num, //base指向的数组中的元素个数。 size_t size, // 数组中每个元素的大小(字节)。 int (*compar)(const void*,const void*));//比较两个元素的函数指针,函数指针compar指向了一个函数,这个函数用来比较这两个元素。void*类型的指针是用来存放任意类型数据的地址,不能进行解引用和+-操作等。int compareMyType (const void * a, const void * b) { if ( *(MyType*)a < *(MyType*)b ) return -1; if ( *(MyType*)a == *(MyType*)b ) return 0; if ( *(MyType*)a > *(MyType*)b ) return 1; }