目录
1.字符指针
变量取地址后放入指针中
char a=‘0’;
char*b=&a;
把字符串放入指针
char*c=‘’abcdef“;
此时字符串是常量字符串,不可更改任一字母,用const
字符串的首字母地址放入了指针中,用%s打印指针可以打印出字符串到\0停止。
指针和字符数组。
结果1验证上述结论。
结果2,结果3推测尽管g是整个数组地址但是被当成首元素地址操作。
注意结果3,4相同。
说明要打印整个数组加一不能在函数内部处理,必须在赋值处处理。
2.指针数组:存放指针的数组
存放多个数组的指针
int arr1[]={1,2,3};
int arr2[]={4,5,6};
int arr3[]={7,8,9};
int*arr={arr1,arr2,arr3};
printf("%d",*(arr[i]+j));
arr[0]即取到arr2的首元素地址,arr[0]+2;
即取到arr2首元素地址后加2即第三个元素地址;
因为加号的优先级低于*所以加括号。
效果:同时控制多个数组,打印其中内容。
3.数组指针
存放数组地址
int arr[5]={1,2,3,4,5};
int(*p)[5]=&arr;
[]的优先级大于*所以要加括号。表明他是指针。
剩余的表示存放的数组类型,int型 5个空间。
如char*(*p)[5]表明指针存放char* 5个空间。
技巧:(*p)替代arr
(*p)[0]等价于arr[0]
用于二维数组传参
int arr[3][5]={(1,2,3,4,5),(6,7,8,9,10),(11,12,13,14,15)};
此时arr为第一行元素的数组地址(把一行看成一个元素)
int (*p)[5]=&arr或(int (*p)[5]=arr)
分析:*(*(p+1)+1)
p加1表示第几行的地址,解引用表示第几行的数组名,此时数组名表示该行首元素的地址,加1表示该行首元素的下一个元素的地址,再解引用表示该元素。
1.指针加减就是步长,2.解引用得到数组名,数组名有表示首元素地址(可能是首行元素的地址)
指针加减解引用的变形与分析
*(*(p+1)+1)等价于*(p[1]+1)等价于p[1][1]
结论:1.地址[]可以打印出对应数字,比如arr[1]
2.地址加减后解引用再打印也可以表示对应数字。
3.总结有加减(运算)就要解引用再打印,即使有[]。
全为[]可以不用解应用。
无加减号也无[]的指针要解引用。
4.数组传参:
用数组接收:
int arr(数量可省略,也可用[]或者[数字])
二维数组:
行可省略,列不能省略。
用地址接收:
传的是类型对应的下一级指针
int* arr()(如果传的是int* 型数组,一级指针对应二级指针接收)
二维数组:传的是第一行数组的地址,因此是数组指针(第一行元素地址),注意int (*arr)[列]
5.指针传参:
1.本身int* 的指针(返回值),用二级指针接收也可以用一级指针来接收。
同理函数参数是一级指针:可以接受的参数可以为变量地址或者一级地址或者一级指针数组的地址
或者数组的地址
6.函数指针:指向函数的地址
函数取地址和函数名的地址是一样的。两者等价。
返回类型 int (*指针名)(参数类型,参数类型)=函数名
int (*p)(int,int)=&ADD
使用:(**指针名)等价于(*指针名)等价于指针名等价于函数名
注意此处与上文的字符数组与此处指针有相同的地方
eg:
(*(void)(*)())0)();
void (*signal(int,void(*)(int)))(int)
7.函数指针数组:存放函数指针的数组
int arr[]
int(*)(int,int)函数指针类型
int(* arr[])(int,int)//函数指针数组
变量名必须和指针的*号靠在一起,所以int(*)(int,int) arr[]是错的
arr[i]指向不同数组。
函数指针作用:转移表
函数指针数组可以代替switch语句,不同的数字,对应不同的函数。
8.区分指针和数组
已知[]的结合顺序大于*
eg1:int *arr[10] 先和怕[]结合,剩下的表示数组存放类型。
int(*arr)[10]先和是*结合表明是指针,剩下的表明是数组指针。
int(*arr[10])[2] 先和[]结合表明是数组,剩下的表明存放的类型,把arr[10]替换成a ,a就是个数组指针,数组存放的是数组指针
eg2:
char*(*p)(char* ,const char* )=&my_strcpy//*p等价于函数名
char*(*arr[])(char* ,const char*)先写arr[]确认是数组,再写数据类型,因为是指针*和数组名连在一起。
区分数组和指针
1.和谁先结合(*的结合性小于[])
2.把结合的一部分(名加*或名加[])先去掉,用一个变量名代替,如此重复,直至看出来
9.回调函数:
通过指针调用的函数,先把函数的指针,传到函数中,函数中遇到特定条件再触发,并没有主动调用。利用传不同函数的指针到新的函数,实现函数的嵌套即函数内部调用函数。
void*指针:
可以存放int float型的地址,但不可解引用也不可加减操作。
qsort函数排序
qsort(数字元素地址,数组个数,每个元素大小字节,比较函数)
sz=sizeof(arr)/sizeof(arr[0]);
sizeof(arr[0])
int compare (const void*e1,const void*e2)
return *(int*)e1-*(int*)e2
e1大于e2返回值大于0;小于则小于0,等于则等于0
浮点型:return(int)( *(float*)e1-*(float*)e2)
结构体:整型:return ((struct stu*)e1)->age-((struct stu*)e2)->age
比较字符串,比如姓名等,就是根据首字母排序。用strcmp函数
字符串:return strcmp(((struct stu*)e1)->name,((struct stu*)e2+>name))