一、数组名和&数组名

二、字符指针

1、指向字符数组首元素的字符指针 char* p=arr

2、指向常量字符串的字符指针 const char* p=”abc”

三、指针数组 int* p[3]={arr1,arr2,arr3}

四、数组指针 int(*p)[10]=&arr

五、数组传参

1、一维数组传参

2、二维数组传参

六、指针传参

1、一级指针传参

2、二级指针传参

七、函数指针

1、两个代码的理解

2、函数指针重命名

3、函数指针的使用——回调函数

八、函数指针数组——用途:转移表

九、函数指针数组指针


一、数组名和&数组名

区别:数组名表示首元素的地址,地址加1表示跳过一个数据类型的大小。

&数组名表示取出的是整个数组的地址,地址加1表示跳过一个数组的长度。

举例:arr[]需要使用整型(等)指针来指向,而&arr[]需要使用数组指针来指向。

数组名通常表示首元素的地址,但有两个例外:

1、sizeof(数组名),这里的数组名表示数组首元素的地址。

2、&数组名,表示取出的是这个数组。

二、字符指针

1、指向字符数组首元素的字符指针 char* p=arr

#include int main(){char arr[5] = "abc";char* p = arr;printf("%s", p);//打印abcreturn 0;}

数组名是首元素的地址,这里指针p指向的是arr数组的首元素’a’的地址,可以通过指针p,以%s的形式打印字符串。

2、指向常量字符串的字符指针 const char* p=”abc”

#include int main(){const char* p = "abc";//字符串abc为常量字符串printf("%s", p);return 0;}

因为”abc”是常量字符串,不能被修改,所以指针p需要使用const修饰。若没有const,.c文件运行时程序会直接挂掉,.cpp文件更加严格,会直接报错。

三、指针数组 int* p[3]={arr1,arr2,arr3}

指针数组本质上是数组,是存放指针的数组。

#include int main(){int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,7,5,8,99 };int* p[3] = { arr1,arr2,arr3 };for (int i = 0;i < 3;i++){for (int j = 0;j < 5;j++){//printf("%d ", p[i][j]);//printf("%d ", *(*(p+i) + j));//p[i]可以写成*(p+i)printf("%d ",*(p[i]+j));//解释如下图}printf("\n");}return 0;}

三种指针数组的打印方式都是可以的,这里的代码类似二维数组,该数组首元素是第一行。详细解析如下:

四、数组指针 int(*p)[10]=&arr

数组指针是指向数组的指针。

int(*p)[10]=&arr,数组指针p的类型是int(*)[10](去掉p,即为类型)。这里指针+1跳过一个数组大小。

#include print(int(*p)[5], int r, int c)//接收的是指向一维数组的数组指针{for (int i = 0; i < r;i++){for (int j = 0; j < c; j++){//printf("%d ", p[i][j]);//printf("%d ", *(p[i]+j));printf("%d ", *(*(p+i)+j));}printf("\n");}}int main(){int arr[3][5] = { 1,5,4,6,7,9,8,4,2,5,4,5,4,5,6 };print(arr, 3, 5);//传过去的是二维数组return 0;}

打印方式的理解与上一个例子相同,注意二维数组的首元素是第一行。

再来看一个例子:int(*p[10])[5],这是一个存放数组指针的数组,数组元素的类型是int(*)[5]。

五、数组传参

1、一维数组传参

void test(int arr[])//一维数组传参,数组接收{}void test(int arr[10])//一维数组传参,数组接收,10可有可无{}void test(int* arr)//一维数组传参,指针接收{}int main(){int arr[10] = { 0 };test(arr);}
void test2(int* arr[20])//指针数组传参,指针数组接收,20可有可无{}void test2(int** arr)//传过来的是一级指针的指针,当然可以用二级指针接收{}int main(){int* arr2[20] = { 0 };test2(arr2);}

2、二维数组传参

void test(int arr[3][5])//二维数组传参,二维数组接收{}void test(int arr[][])//错误,行不能省略{}void test(int arr[][5])//二维数组传参,二维数组接收{}void test(int *arr)//错误,传过来的是第一行的地址,相当于一维数组的地址,不能用一级指针接收{}void test(int* arr[5])//错误,不能用指针数组接收{}void test(int (*arr)[5])//可以用数组指针接收{}void test(int **arr)//错误,传过来的是一维数组的指针,不能用二级指针接收,二级指针是指向一级指针的指针{}int main(){ int arr[3][5] = {0}; test(arr);//传过来的相当于第一行的地址}

六、指针传参

1、一级指针传参

void text(int* p){}int main(){int a = 0;int* pa = &a;int arr[10] = { 0 };text(&a);//可以传整型变量的地址text(pa);//可以传一级指针的地址text(arr);//可以传整型数组的地址return 0;}

只要传过来的本质是一级指针,就可以用一级指针接收。

2、二级指针传参

void text(int** p){}int main(){int* p1 = NULL;int** p2 = NULL;int* arr[10];text(&p1);//可以传一级指针的地址text(p2);//可以传二级指针text(arr);//可以传指针数组return 0;}

七、函数指针

对于函数名与&函数名,它们的地址是一样的,且本质上没有任何区别。

使用函数值指针进行函数的调用,可以把p当成函数名调用,解引用无意义。

1、两个代码的理解

( *( void (*)() )0 )();

以上代码是一次函数调用,先将0强制类型转换为函数指针类型,该函数指针无参,返回值为void。由于函数指针解引用无意义,所以这里的这颗*可有可无。整个代码的意思是对0地址处的函数进行一次函数调用。

void ( *signal( int , void(*)(int) ) )(int);

以上代码是一次函数声明。

signal是函数名,它的参数是int和函数指针void(*)(int),返回类型是函数指针void(*)(int)。

2、函数指针重命名

typedef void(*pf_t)(int);pf_t signal(int,pf_t);

把void(*)(int)类型重命名为pf_t。

上方函数可以用pf_t来代替void(*)(int)。

3、函数指针的使用——回调函数

int Add(int a, int b){}int Sub(int a,int b){}int Mul(int a, int b){}int Div(int a, int b){}int calc(int(*p)(int,int)){return p(1, 2);}int main(){calc(Add);return 0;}

当有多个参数和返回类型均相同的函数时,可以使用函数指针对这些函数进行按需调用,减少代码冗余。

八、函数指针数组——用途:转移表

函数指针数组是存放函数指针的数组。

int Add(int a, int b){}int Sub(int a,int b){}int Mul(int a, int b){}int Div(int a, int b){}int main(){int input,x,y;scanf("%d%d%d",&input,&x,&y);//int(*p)(int, int) = Add;int(*arr[4])(int,int) = {Add,Sub,Mul,Div};//数组arr的类型直接将函数指针的p替换即可int ret=arr[input](x,y);//使用函数指针数组对函数进行调用——转移表for (int i = 0; i < 4; i++)//函数指针数组的遍历调用{int ret = arr[i](8, 4);}return 0;}

可以使用函数指针数组对相同形参、返回类型的函数进行调用,在实际使用中实现函数的跳转功能,所以被称为转移表,有较大的使用价值。

九、函数指针数组指针

int main(){int(*p)(int, int) = Add;//p是函数指针int(*arr[4])(int,int) = {Add,Sub,Mul,Div};//arr是函数指针数组int(*(*parr))(int,int)=&arr//parr是函数指针数组指针return 0;}

写法可以按照上一级指针/数组类型模仿写。